Pergunta

I have an admin page in django 1.4.3 [final]. We use CF cards in a lot of hardware, each card connects to a VPN. I have a function which determines whether the card is online or not depending on its last feedback written in database.

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 ]

and everytime I try to set the online filter, the file /tmp/list gets full with the right set of cards and then filled with the default list - as if the filter gets called twice. And the URL in my browser says ?e=1 instead of ?online=yes. If the filter is not set, it is called only once - giving only one set of cards in the file.

BTW: the OnlineFilter.filter method is out of the queryset method just so that I know what goes out of my code, in final release I would have put it in only one method ...

is this a bug? or a feature? Am I doing something wrong? If so, what?

Foi útil?

Solução

I wouldn't be surprised if django calls the queryset function twice - I seem to remember noticing that once before. Not sure why though. Regarding why the filter is not working, django expects a QuerySet to be returned, not a list. You might be able to construct a query to determine online status, but given the complexity I suspect it will prove to be beyond the powers to the django ORM and you'd need to revert to raw SQL. The alternative would be to create a list of primary keys, the simply filter the queryset by those, so:

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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top