我有一个包含三个字段的模型,以确定文本是否应该在模板中可见。
如果选中了布尔字段,它将覆盖两个日期字段。
如果未选中布尔字段,则只应在startdate过去时返回True,如果设置了enddate,则只有在将来设置日期时才返回true。
我该怎么做?
这是我尝试过的,但不能像我想的那样工作:
class Entry(models.Model):
name = models.CharField(max_length=200)
visible = models.BooleanField(default=False, help_text="If checked, the text will be visible, even if the datefield is set")
visible_start = models.DateTimeField(help_text="Visible from", blank=True, null=True)
visible_end = models.DateTimeField(help_text="Visible to", blank=True, null=True)
def is_visible(self):
now = timezone.now()
if not self.visible:
if self.visible_start and now < self.visible_start:
return False
if self.visible_end and now > self.visible_end:
return False
return True
答案 0 :(得分:3)
您可以实施经理,例如(另):
class VisibleEntryManager(models.Manager):
def get_query_set(self):
now = datetime.now()
return super(VisibleEntryManager, self).get_query_set()\
.filter(visible=True)\
.filter(visible_start__gte=now, visible_end__lte=now) # Or use Q objects
class Entry(models.Model):
# other stuff
visible_objects = VisibleEntryManager()
编辑:管理员使用默认管理器(通过调用_default_manager
类上的Model
)。如果你想推迟管理对象,你可以这样做:
class EntryAdmin(admin.ModelAdmin):
# other stuff
def queryset(self, request):
if request.user.is_superuser or request.user.is_staff: # example rule
qs = self.model.objects.all() # could be admin_objects if you want to set
# .objects as the default filtered option on
# the Entry model.
ordering = self.get_ordering(request)
if ordering:
qs = qs.order_by(*ordering)
return qs
return super(ProductAdmin, self).queryset(request)
答案 1 :(得分:1)
开始和停止有null = True。因此,您可以检查:Null < now
和Null > Now
(始终为假)。如果start和stop在现在的标准范围内,则下面的代码将返回True。
def is_visible(self):
now = datetime.now()
if self.is_visible:
# is_visible field is checked.
return True
#elif self.visible_start < now and self.visible_stop == Null:
# return True
elif self.visible_start < now and self.visible_stop > now:
# Start is before now and stop is after now.
return True
else:
# All other options
return False
我添加了这个,以显示何时使用过滤器,方法和管理员。
看起来你想做这样的事情:
# views.py
objects = Entry.objects.all()
# template.html
{% for obj in objects %}
{% if obj.is_visible %}
{{ obj.title }}
{% endif %}
{% endfor %}
不要这样做!这将循环所有条目(可以是很多)。这是一场表演噩梦!首先过滤条目。像这样:
# views.py
now = datetime.now()
objs0 = Entry.objects.filter(visible=True)
objs1 = Entry.objects.filter(visible_start__lte=now, visible_stop__gt=now)
objects = objs0 | objs1
# template.html
{% for obj in objects %}
{{ obj.title }}
{% endfor %}
这只会循环抛出相关对象。如果在项目中多次出现此列表,并且您注意到多次在上面查看,那么请考虑模型管理器。像@HeddeVanDerHeide建议的那样。编写完经理后,您可以获得所有可见对象:
objects = Entry.visible_objects.all()
为什么不直接过滤模型方法?
objects = Entry.objects.filter(is_visible=True)
因为Django没有那样工作。对数据库执行查询,数据库不知道方法。但模型方法有什么用呢?如果要显示条目之间的差异,请使用模型方法:
# models.py
def is_important(self):
now = datetime.now()
if self.start < now and self.stop > now:
return True
else:
return False
# views.py
objects = Entries.objects.all()
# template.html
{% for obj in objects %}
<p{% if obj.is_important %} class="highlight"{% endif %}>{{ obj.title }}</p>
{% endfor %}
当你想在管理列表显示中显示一个布尔值时,模型方法可以实现这一点:
class EntryAdmin(admin.ModelAdmin):
list_display = ('title', 'is_visible')
来自文档:
在模型上定义自定义方法以添加自定义“行级” 对象的功能。而管理方法的目的是 做“全桌”的事情。