我正在测试我的博客文章是否按时间倒序排列。为此,我必须为创建的每个帖子设置随机日期。我正在使用
faker
来设置日期。我找回了一个假日期,但每个帖子的日期都是相同的。 auto 现在仍然是这里的问题,还是我没有正确使用 Faker?
工厂:
fake = Faker()
mocked = fake.date_time()
class BlogPageFactory(wagtail_factories.PageFactory):
class Meta:
model = models.BlogPage
with patch('django.utils.timezone.now', mocked):
date = mocked
# date = datetime.date.today()
author = factory.SubFactory(UserFactory)
slug = factory.sequence(lambda n: f"post{n}")
snippet = factory.sequence(lambda n: f"Article {n} snippet...")
body = "Test post..."
featured_image = factory.SubFactory(wagtail_factories.ImageFactory)
featured_article = False
型号:
class BlogPage(Page):
date = models.DateField("Post date")
snippet = models.CharField(
max_length=250, help_text="Excerpt used in article list preview card."
)
body = RichTextField(blank=True)
tags = ClusterTaggableManager(through=BlogPageTag, blank=True)
featured_image = models.ForeignKey("wagtailimages.Image", on_delete=models.CASCADE)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
featured_article = models.BooleanField(default=False)
content_panels = Page.content_panels + [
MultiFieldPanel(
[
FieldPanel("date"),
FieldPanel("tags"),
],
heading="Blog Information",
),
FieldPanel("snippet"),
FieldPanel("featured_image"),
FieldPanel("body"),
FieldPanel("author"),
InlinePanel("page_comments", label="Comments"),
]
search_fields = Page.search_fields + [index.SearchField("body")]
parent_page_types = ["CategoryIndexPage"]
subpage_types = []
def serve(self, request, *args, **kwargs):
"""
Method override to handle POST conditions for blog comments, ``BlogComment``.
"""
from .forms import CommentForm
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.user = request.user
new_comment.page = self
new_comment.save()
messages.success(
request,
"Your message was successfully "
"submitted and is awaiting moderation. "
"Thank you for contributing!",
)
return redirect(self.get_url())
else:
form = CommentForm
return render(request, "blog/blog_page.html", {"page": self, "form": form})
fake = Faker()
class BlogPageFactory(wagtail_factories.PageFactory):
class Meta:
model = models.BlogPage
date = fake.date_time_this_decade()
...
您当前的代码有两个问题,导致您遇到的问题:
mocked
日期;auto_now
覆盖任何
patch(..., mocked)
mocked
约会问题来自您的代码编写方式;你在模块导入时计算
mocked
日期——因此对于所有未来的调用它总是相同的。
为了获得动态值,您需要使用 factory_boy 的专用声明之一——每次要求工厂生成实例时都会对它们进行评估。
我建议看看我的另一个答案以获得更深入的解释。
date
在这里,你的模型字段声明是一个“标准的”Django 字段,没有魔法;无需修补
django.utils.timezone.now()
,因为将date=mocked
传递给BlogPage.objects.create(...)
会起作用。 顺便说一句,这正是 factory_boy 在后台执行的调用。
如果你有一个带有
auto_now_add
的模型,Django 不允许覆盖该值——正如 在他们的文档中看到的。
这会给你留下两个可能的选择:
将
auto_now_add=True
替换为 default=timezone.now
:当 default
是可调用对象时,Django 将为模型的每个新实例执行可调用对象,除非调用者提供了一个值——就像您对工厂所做的那样;
_create()
方法:
class BlogPageFactory(factory.django.DjangoModelFactory):
...
date = factory.Faker("date_time")
@classmethod
def _create(cls, model_class, *args, **kwargs):
# Extract the "date" kwarg, as an explicit value will be ignore
# by auto_now_add
date = kwargs.pop("date")
# Force `timezone.now()` to always return the expected date
# for the duration of the instance creation
with patch("django.utils.timezone.now", lambda: date):
# Let factory_boy actually create the instance
return super()._create(model_class, *args, **kwargs)