【问题标题】:Mezzanine/django template rendering not calling model methodsMezzanine/django 模板渲染不调用模型方法
【发布时间】:2015-05-23 01:54:24
【问题描述】:

TLDR:自定义视图/模板仅有时会调用自定义模型方法。有时是错误的结果(没有来自方法的打印消息),有时是正确的结果(有来自方法的打印消息)。

我是 Mezzanine 的新手(更习惯于 Pyramid),并且在某些模板渲染方面遇到了一个奇怪的非确定性问题。我创建了一个带有内部 Django 应用程序的夹层项目,用于添加 3 种新类型:实验(Page、RichText)、Instrument(Page、RichText)、DailyStatus(Displayable、Ownable、RichText)。我在 DailyStatus 上定义了一个 ForeignKey 以将其链接到单个实验。

由于 DailyStatus 不是 Page 的子类,因此我创建了自己的视图和模板(扩展 base.html)。该模板从博客详细信息模板中汲取了很多内容,因为 DailyStatus 具有类似的目的。在模板中,我调用了两种方法来获取使用 DailyStatus status_date DateField 的 Experiment(get_previous_by_status_date 和 get_next_by_status_date)中的上一个和下一个 DailyStatus。

有时,当我访问每日状态页面时,上一个/下一个按钮会按预期工作(显示实验中的下一个状态,或者在实验中显示第一个/最后一个状态)。但其他时候,当服务器重新启动/重新加载时,它似乎是通过 publish_date 选择 prev/next 或者只是不工作。它永远不会在服务器的单个实例期间切换这些状态。我已经使用 pdb 和 ipdb 尝试对此进行调试,并且已经到了调用daily_status_inst.get_previous_by_status_date() 产生错误结果而daily_status_inst._get_next_or_previous_by_status_date(False) 产生正确结果的地步。正确状态和错误状态之间的上下文似乎没有任何不同(我将字典转储到文件中)。我已将 print 添加到各个 prev/next 方法中,有时它们甚至似乎都没有被调用(没有输出),但它们返回的值不正确。

有人知道发生了什么吗?或任何其他有用的调试技巧?我的 DailyStatus 模型如下:

class DailyStatus(Displayable, Ownable, RichText):
    experiment = models.ForeignKey(Experiment, related_name="daily_statuses")
    status_date = models.DateField(_("Status Date"))

    class Meta:
        verbose_name = _("Daily Status")
        verbose_name_plural = _("Daily Statuses")
        ordering = ("-status_date",)
        order_with_respect_to = "experiment"

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        from django.core.urlresolvers import reverse
        return reverse('daily_status_detail',
                       kwargs={
                           "experiment": self.experiment.slug,
                           "slug": self.slug,
                       })

    def _get_next_or_previous_by_status_date(self, is_next, **kwargs):
        arg = "status_date__gt" if is_next else "status_date__lt"
        order = "status_date" if is_next else "-status_date"
        lookup = {arg: self.status_date, "experiment": self.experiment}
        try:
            queryset = DailyStatus.objects.published
        except AttributeError:
            queryset = DailyStatus.objects.all
        try:
            dstatus = queryset(**kwargs).filter(**lookup).order_by(order)[0]
            return dstatus
        except IndexError:
            return False

    def get_next_by_status_date(self, **kwargs):
        dstatus = self._get_next_or_previous_by_status_date(True, **kwargs)
        return dstatus

    def get_previous_by_status_date(self, **kwargs):
        dstatus = self._get_next_or_previous_by_status_date(False, **kwargs)
        return dstatus

最简单的模板:

<html>
<head>
</head>
<body>
    {{ daily_status.get_previous_by_status_date }}
    <p></p>
    {{ daily_status.get_next_by_status_date }}
</body>
</html>

使用:

* Mezzanine 3.1.10
* Django 1.6.11
* Python 3.4.3
* SQLite 3.8.10.1
* Darwin 14.3.0

感谢您的帮助。

更新 1:

我已经追踪到 prev/next 方法是否为_curried。当他们被咖喱时,它永远不会调用实际的方法(或者至少不打印任何输出)。当它是正常绑定方法时,我得到预期的输出:

# custom view
status_posts = DailyStatus.objects.published().filter(experiment__slug=experiment).all()
print(status_posts.get_next_by_status_date)
# get_object_or_404 and so on with rendering...

# print produces:
<bound method DailyStatus._curried of <DailyStatus: 2013: Update 1>>
# or (after a couple server restarts):
<bound method DailyStatus.get_next_by_status_date of <DailyStatus: 2013: Update 1>>

【问题讨论】:

    标签: python django python-3.x mezzanine


    【解决方案1】:

    花了一段时间,但我想通了。这一切都与信号的魔力(我假设基于问题的竞争条件性质)和contribute_to_class 方法有关。下面是正确的模型,或者至少是我尝试做的一个可行的解决方案。

    当您在模型上创建 DateField 并将其添加到其他对象(我认为)时,会调用 contribute_to_class 方法,该方法会添加带有字段名称的 get_next_by_%s 和 get_previous_by_%s 方法。因此,当我使用 get_previous_by_status_date 名称创建方法时,添加的 contribute_to_class 方法和添加的方法之间存在竞争条件。由于您不能在模板中调用带有参数的方法,因此我必须创建自动添加实验过滤器的新方法。

    如果我有任何错误请纠正我。好在我不害怕阅读源代码。

    class DailyStatus(Displayable, Ownable, RichText):
        experiment = models.ForeignKey(Experiment, related_name="daily_statuses")
        status_date = models.DateField(_("Status Date"))
    
        class Meta:
            verbose_name = _("Daily Status")
            verbose_name_plural = _("Daily Statuses")
            ordering = ("-status_date",)
            order_with_respect_to = "experiment"
    
        def __str__(self):
            return self.title
    
        def get_absolute_url(self):
            from django.core.urlresolvers import reverse
            return reverse('daily_status_detail',
                           kwargs={
                               "experiment": self.experiment.slug,
                               "slug": self.slug,
                           })
    
        def get_next_by_status_date_exp(self, **kwargs):
            """
            Retrieves next object by status date.
            """
            kwargs.setdefault("experiment", self.experiment)
            return self.get_next_by_status_date(**kwargs)
    
        def get_previous_by_status_date_exp(self, **kwargs):
            """
            Retrieves previous object by status date.
            """
            kwargs.setdefault("experiment", self.experiment)
            return self.get_previous_by_status_date(**kwargs)
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-07-22
    • 2021-06-28
    • 2012-10-27
    • 1970-01-01
    • 2016-06-07
    • 2018-05-20
    • 2018-11-05
    • 2017-09-26
    相关资源
    最近更新 更多