Mezzanine/django 模板渲染不调用模型方法
Mezzanine/django template rendering not calling model methods
TLDR: 自定义 view/template 仅有时调用自定义模型方法。有时结果错误(方法没有打印消息),有时结果正确(方法有打印消息)。
我是 Mezzanine 的新手(更习惯于 Pyramid)并且我遇到了一些模板渲染的奇怪的非确定性问题。我创建了一个带有内部 Django 应用程序的 Mezzanine 项目,用于添加 3 种新类型:Experiment(Page,RichText),Instrument(Page,RichText),DailyStatus(Displayable,Ownable,RichText)。我在 DailyStatus 上定义了一个 ForeignKey 以 link 它到单个实验。
由于 DailyStatus 不是 Page 的子类,因此我创建了自己的视图和模板(扩展 base.html)。由于 DailyStatus 具有类似的用途,因此该模板从博客详细信息模板中获取了大量信息。在模板中,我调用了两种方法来获取使用 DailyStatus status_date
DateField.
的实验(get_previous_by_status_date
和 get_next_by_status_date
)中的上一个和下一个 DailyStatus
有时,当我访问每日状态页面时,prev/next 按钮会按预期工作(显示实验中的下一个状态或在实验中不显示任何 if first/last)。但其他时候,当服务器 restarts/reloads 时,它似乎正在通过 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 方法中,有时它们甚至似乎没有被调用(无输出)但它们 return 是一个不正确的值。
有谁知道发生了什么事吗?或者任何其他有用的调试技巧?我的 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>>
花了一段时间,但我想通了。这一切都与信号的魔力(我假设基于问题的竞争条件性质)和 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)
TLDR: 自定义 view/template 仅有时调用自定义模型方法。有时结果错误(方法没有打印消息),有时结果正确(方法有打印消息)。
我是 Mezzanine 的新手(更习惯于 Pyramid)并且我遇到了一些模板渲染的奇怪的非确定性问题。我创建了一个带有内部 Django 应用程序的 Mezzanine 项目,用于添加 3 种新类型:Experiment(Page,RichText),Instrument(Page,RichText),DailyStatus(Displayable,Ownable,RichText)。我在 DailyStatus 上定义了一个 ForeignKey 以 link 它到单个实验。
由于 DailyStatus 不是 Page 的子类,因此我创建了自己的视图和模板(扩展 base.html)。由于 DailyStatus 具有类似的用途,因此该模板从博客详细信息模板中获取了大量信息。在模板中,我调用了两种方法来获取使用 DailyStatus status_date
DateField.
get_previous_by_status_date
和 get_next_by_status_date
)中的上一个和下一个 DailyStatus
有时,当我访问每日状态页面时,prev/next 按钮会按预期工作(显示实验中的下一个状态或在实验中不显示任何 if first/last)。但其他时候,当服务器 restarts/reloads 时,它似乎正在通过 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 方法中,有时它们甚至似乎没有被调用(无输出)但它们 return 是一个不正确的值。
有谁知道发生了什么事吗?或者任何其他有用的调试技巧?我的 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>>
花了一段时间,但我想通了。这一切都与信号的魔力(我假设基于问题的竞争条件性质)和 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)