如何为Wagtail博客生成不同假日期?解决Faker重复日期问题
问题:使用Faker生成博客文章日期时所有文章日期相同
我正在测试博客文章是否按倒序排列,需要给每个创建的文章设置随机日期。用Faker库生成日期,但所有文章的假日期完全相同。这是Django auto_now的问题,还是我对Faker的用法有误?
Factory代码
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
Models代码
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})
解答
问题出在你对Faker和Factory Boy的用法上,和Django的auto_now无关——你的模型里date字段也没设置auto_now或auto_now_add。
原因分析
你在类定义外提前执行了fake.date_time(),把结果赋值给mocked,这个值是固定的时间对象。之后每次创建BlogPageFactory实例时,date字段都会用这个预先生成好的固定值,所以所有文章日期都一样。另外,你用patch的方式也不对,patch需要包裹的是会调用now()的代码,而不是直接赋值一个静态值。
解决方法
用Factory Boy的factory.LazyAttribute或者直接使用集成的factory.Faker,确保每次创建实例时都会生成新的随机日期:
修改后的Factory代码:
from factory import LazyAttribute fake = Faker() class BlogPageFactory(wagtail_factories.PageFactory): class Meta: model = models.BlogPage # 方式1:用LazyAttribute动态生成 date = LazyAttribute(lambda _: fake.date_time().date()) # 方式2:直接使用Factory Boy集成的Faker,更简洁 # date = factory.Faker('date') 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
说明
LazyAttribute会在每次创建实例时执行传入的lambda函数,确保每次都生成新的随机时间并转成date类型匹配模型字段。factory.Faker('date')是Factory Boy和Faker的集成用法,内部会自动处理每次生成新值的逻辑,代码更简洁。- 移除之前的
patch代码,因为你不需要mocktimezone.now,直接给date字段赋值随机日期即可。
内容的提问来源于stack exchange,提问作者user3605767
相关产品推荐
相关产品推荐

