Reputation: 2049
I'm having an issue with a Django 1.6 project.
I have a view that reports a bunch of web logs. When the view is loaded, it gets all logs from the DB. However, the user has access to two datepickers to limit the from_date and to_date on the query. To accomplish this, I added a check in the get_queryset() to verify if any of those datepickers had been used. This feels really stupid and clunky, and I'm sure there's a better way to do it, but I'm not sure what it is. Here's my view code, let me know if theres anything I'm missing here.
class SiteUsersView(generic.ListView):
"""
EX: localhost/reports/site/facebook
"""
model = Cleanedlog
template_name = "trafficreport/site_chunk_log.html"
def get_context_data(self, **kwargs):
context = super(SiteUsersView, self).get_context_data(**kwargs)
context["url_chunk"] = self.kwargs["url_chunk"]
return context
def get_queryset(self):
from_date = self.request.GET.get("fromDate")
to_date = self.request.GET.get("toDate")
if from_date is not None and to_date is not None:
return self.from_to_date()
elif from_date is not None and to_date is None:
return self.from_date()
elif to_date is not None and to_date is None:
return self.to_date()
else:
return self.all_dates()
def from_date(self, from_date):
return Cleanedlog.objects.filter(dest_url__contains=self.kwargs["url_chunk"],
time_received__gte=from_date).values('user__name').annotate(
count=Sum('size')).order_by('-count')
def to_date(self, to_date):
return Cleanedlog.objects.filter(dest_url__contains=self.kwargs["url_chunk"],
time_received__lte=to_date).values('user__name').annotate(
count=Sum('size')).order_by('-count')
def from_to_date(self, to_date, from_date):
return Cleanedlog.objects.filter(dest_url__contains=self.kwargs["url_chunk"],
time_received__gte=from_date,
time_received__lte=to_date).values('user__name').annotate(
count=Sum('size')).order_by('-count')
def all_dates(self):
return Cleanedlog.objects.filter(dest_url__contains=self.kwargs["url_chunk"]).values('user__name').annotate(
count=Sum('size')).order_by('-count')
What's more is that I have other reports (Users/IPs) that follow the exact same format, just with a different model and marginally different queries. The datepickers and all the data presentation is in a higher level template, and that works well, but it feels really stupid to just duplicate all this code. Am I missing something obvious?
Thanks!
Upvotes: 0
Views: 110
Reputation: 37364
I've solved problems like this in the past by inverting the logic and using exclude
, eg:
return Cleanedlog.objects.filter(dest_url__contains=self.kwargs["url_chunk"]) \
.exclude(time_received__lt=from_date).exclude(time_received__gt=to_date)
And then take values and annotate and count as desired.
Comparisons against None
always fail, so nothing gets excluded unless the date is provided.
That's probably the simplest way to write it, but you can also take advantage of the ability to chain querysets without evaluating them:
base_qs = Cleanedlog.objects.filter(dest_url__contains=self.kwargs["url_chunk"])
if from_date is not None:
base_qs = base_qs.filter(time_received_gte=from_date)
if to_date is not None:
base_qs = base_qs.filter(time_received_lte=to_date)
return base_qs.values(# as above
That avoids putting the unnecessary None
comparisons into the query at all.
Upvotes: 1