【问题标题】:SimpleListFilter called twice and finally ?e=1SimpleListFilter 调用了两次,最后 ?e=1
【发布时间】:2013-12-11 16:22:19
【问题描述】:

我在 django 1.4.3 [final] 中有一个管理页面。我们在很多硬件中使用 CF 卡,每张卡都连接到一个 VPN。我有一个函数可以根据它在数据库中写入的最后反馈来确定卡是否在线。

models.py:

class Card(models.Model):
    ...
    last_feedback = models.DateTimeField(_('Last feedback'), null=True, blank=True)

    ...
    def online_status(self):
            nowtime = calendar.timegm(timezone.now().utctimetuple())
            seen = calendar.timegm(self.last_feedback.utctimetuple())

            diff = nowtime-seen

            if (self.state == 1) and (diff < 300):
                    return '<div style="width:100%%; height:100%%; background-color:green; color:white;">online & production</div>'
            elif (diff < 300):
                    return '<div style="width:100%%; height:100%%; background-color:orange;">online</div>'
            else:
                    return "offline"
    online_status.allow_tags = True

admin.py:

class OnlineFilter(admin.SimpleListFilter):
    title = _("Online")
    parameter_name = "online"

    def lookups(self, request, model_admin):
            return (("yes", "Yes"),
                    ("no", "No"),
            )

    def queryset(self, request, queryset):
            out = self.filter(request, queryset)
            f = open("/tmp/list", "w")
            f.write(str(out))
            f.close()
            return out

    def filter(self, request, queryset):
            if not self.value():
                    return queryset
            else:
                    out = []
                    if self.value() == 'yes':
                            for i in queryset:
                                    try:
                                            if i.online_status() != "offline":
                                                    out.append(i)
                                    except:
                                            pass
                    elif self.value() == 'no':
                            for i in queryset:
                                    try:
                                            if i.online_status() == "offline":
                                                    out.append(i)
                                    except:
                                            pass
                    return out
class CardAdmin(admin.ModelAdmin):
    list_filter     = [ ... , OnlineFilter ]

每次我尝试设置在线过滤器时,文件/tmp/list 都会被正确的卡片组填满,然后填充默认列表 - 好像过滤器被调用了两次。我浏览器中的 URL 显示 ?e=1 而不是 ?online=yes。如果未设置过滤器,则仅调用一次 - 仅在文件中提供一组卡片。

顺便说一句:OnlineFilter.filter 方法不在queryset 方法中,只是为了让我知道我的代码出了什么问题,在最终版本中我只会把它放在一个方法中......

这是一个错误吗?还是一个功能?难道我做错了什么?如果有,是什么?

【问题讨论】:

  • 它似乎总是被调用两次,即使过滤器关闭......文件总是包含两次列表。如果设置了过滤器,则有正确的过滤器和完整列表。如果未设置过滤器,则有两个完整列表。任何人?为什么会这样?
  • 旁注:为什么要混合表示和逻辑?每张卡都调用nowtime = calendar.timegm(timezone.now().utctimetuple()),您会获得巨大的开销。你不能只用常规的 django 方法过滤吗,即沿着.filter(last_feedback__gt=...) 的线 smthng?
  • 我最喜欢.filter(last_feedback__gt=...)。老实说,我不知道为什么它一开始就没有击中我。我在更多情况下使用它,但我并没有想到这个。
  • 混合表示和逻辑?那我应该如何显示差异呢? ...我需要显示卡片是多久之前响应的。
  • 如果您将其作为答案发布,我会给出“已接受”标志。

标签: python django filter django-admin django-1.4


【解决方案1】:

如果 django 两次调用 queryset 函数,我不会感到惊讶 - 我似乎记得之前注意到过一次。不知道为什么。关于过滤器为什么不起作用,django 期望返回 QuerySet,而不是列表。您可能能够构建一个查询来确定在线状态,但考虑到复杂性,我怀疑它会被证明超出了 django ORM 的能力,您需要恢复到原始 SQL。另一种方法是创建一个主键列表,只需按这些键过滤查询集,因此:

def filter(self, request, queryset):
    if not self.value():
        return queryset
    else:
        pks = []
        if self.value() == 'yes':
            for i in queryset:
                try:
                    if i.online_status() != "offline":
                        pks.append(i.pk)
                except:
                    pass
        elif self.value() == 'no':
              for i in queryset:
                  try:
                      if i.online_status() == "offline":
                          pks.append(i.pk)
                  except:
                      pass
        out = queryset.filter(pk__in=pks)
        return out

【讨论】:

  • 我不完全理解.pk 是我应该定义的吗?或者它是 Django 已经定义的东西?这是方法还是属性?
  • 它总是在模型上定义,并且是主键字段。见docs.djangoproject.com/en/dev/topics/db/queries/…
  • 哦,我一直使用id属性,因为我很少覆盖django的默认主键。很高兴知道。谢谢。
  • 虽然你的方式不错,但我想我还是会选择.filter(last_feedback__gt=...)的方式。
  • 总的来说这是一个更好的解决方案,但至少你知道它为什么不起作用。
猜你喜欢
  • 2020-07-28
  • 2023-03-27
  • 1970-01-01
  • 2017-06-25
  • 2013-01-21
  • 2012-09-08
  • 2016-04-27
  • 2019-02-27
  • 1970-01-01
相关资源
最近更新 更多