4

I have a model like this

class BaseRequest(models.Model):
    created = models.DateTimeField(auto_now_add=True, editable=False)
    modified = models.DateTimeField(auto_now=True, editable=False)   
    price_quoted =  models.DecimalField(max_digits=10, decimal_places=2,null=True, blank=True)

 class RequestLeg(models.Model):
    created = models.DateTimeField(auto_now_add=True, editable=False)
    modified = models.DateTimeField(auto_now=True, editable=False)
    depart_date = models.DateField()
    num_seats = models.IntegerField()

class Request(BaseRequest):
    owner = models.ForeignKey(User, null=True, blank=True)
    name = models.CharField(max_length=30, null=True, blank=True)
    email = models.EmailField()
    phone = models.CharField(max_length=30, null=True, blank=True)
    legs = models.ManyToManyField(RequestLeg)

and admin for above Request model is

class RequestAdmin(NoDeletionsAdmin):
    list_display=['id', 'created', 'name', 'depart_date']

    def depart_date(self, obj):
        try:
            return min([leg.depart_date for leg in obj.legs.all()])
        except ValueError, e:
            return None

I want Daterangelist filter for depart_date in RequestAdmin ? enter image description here

3
  • 1
    No, above given question is related to providing date range filter to one model but my question is providing the date range filter to inherited model field with many to many relationship. Please let me know if you didn't understand my question.
    – Vijay
    Commented Jul 21, 2015 at 13:29
  • I don't see what's being inherited that is relevant to the lookup. BaseRequest seems not to play any part in the filter you want.
    – frnhr
    Commented Jul 21, 2015 at 13:52
  • I need date range filter for depart_date like above image in Request Admin.
    – Vijay
    Commented Jul 22, 2015 at 7:11

2 Answers 2

3

I have created custom date range filter for depart_date following way

class DateFieldListFilter(FieldListFilter):
        def __init__(self, field, request, params, model, model_admin, field_path):
            self.field_generic = '%s__' % field_path
            self.date_params = dict([(k, v) for k, v in params.items()
                                     if k.startswith(self.field_generic)])

            now = timezone.now()
            # When time zone support is enabled, convert "now" to the user's time
            # zone so Django's definition of "Today" matches what the user expects.
            if timezone.is_aware(now):
                now = timezone.localtime(now)

            if isinstance(field, models.DateTimeField):
                today = now.replace(hour=0, minute=0, second=0, microsecond=0)
            else:       # field is a models.DateField
                today = now.date()
            tomorrow = today + datetime.timedelta(days=1)

            self.lookup_kwarg_since = '%s__gte' % field_path
            self.lookup_kwarg_until = '%s__lt' % field_path
            self.links = (
                (_('Any date'), {}),
                (_('Today'), {
                    self.lookup_kwarg_since: str(today),
                    self.lookup_kwarg_until: str(tomorrow),
                }),
                (_('Past 7 days'), {
                    self.lookup_kwarg_since: str(today - datetime.timedelta(days=7)),
                    self.lookup_kwarg_until: str(tomorrow),
                }),
                (_('This month'), {
                    self.lookup_kwarg_since: str(today.replace(day=1)),
                    self.lookup_kwarg_until: str(tomorrow),
                }),
                (_('This year'), {
                    self.lookup_kwarg_since: str(today.replace(month=1, day=1)),
                    self.lookup_kwarg_until: str(tomorrow),
                }),
            )
            super(DateFieldListFilter, self).__init__(
                field, request, params, model, model_admin, field_path)

        def expected_parameters(self):
            return [self.lookup_kwarg_since, self.lookup_kwarg_until]

        def choices(self, cl):
            for title, param_dict in self.links:
                yield {
                    'selected': self.date_params == param_dict,
                    'query_string': cl.get_query_string(
                                        param_dict, [self.field_generic]),
                    'display': title,
                }

    FieldListFilter.register(
        lambda f: isinstance(f, models.DateField), DateFieldListFilter)

In Request Admin

list_filter = [('legs__depart_date', DateRangeListFilter),]

def lookup_allowed(self, key, value):
    if key in ('legs__depart_date__gte', 'legs__depart_date__lt'):
        return True
    return super(RequestAdmin, self).lookup_allowed(key, value)
1
  • 1
    What is 'Request Admin'? Where is function 'lookup_allowed' located? What is 'DateRangeListFilter' ?
    – user9608133
    Commented Sep 6, 2019 at 16:06
2

Filter it using field lookups, just like any other relationship:

Request.objects.filter(legs__created__range=["2015-01-01", "2016-01-31"])

If filtering over a field from parent model is required, I suggest reading Multi-table inheritance.

A TL;DR would be that Django implicitly creates a OneToOneField on the child model and we can filter over it just like any other field, e.g:

BaseRequest.objects.filter(request__depart_date__range=[...])

or

Request.objects.filter(baserequest_ptr__created__range=[...])

However, the second query is usually better written like so, letting Django to handle the internals:

Request.objects.filter(created__range=[...])
1
  • This does not explain how to add a date filter for ForeignKey field in Django admin.
    – user9608133
    Commented Sep 6, 2019 at 14:22

Not the answer you're looking for? Browse other questions tagged or ask your own question.