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?
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