Login

Exists Filter OneToOneField in Admin

Author:
davidvaz
Posted:
November 5, 2011
Language:
Python
Version:
1.3
Score:
0 (after 0 ratings)

Adds Boolean like Filter in Admin to OneToOneField reference. Allowing to filter in the Parent for instances without Referenced Field.

To register the filter, import in urls.py for example:

import filterspecs

Example models.py:

from django.db import models

class Place(models.Model):
    name = model.CharField(maxlength=50)
    address = model.CharField(maxlength=80)

class Restaurant(meta.Model):
    place = model.OneToOneField(Place)
    place.exists_filter = True
    serves_hot_dogs = model.BooleanField()
    serves_pizza = model.BooleanField()

Example admin.py:

from django.contrib import admin
from models import *

class PlaceAdmin(admin.ModelAdmin):
    list_filter = ('restaurant',)

admin.site.register(Place, PlaceAdmin)

With this example PlaceAdmin will have a filter:

By Restaurant
All
Yes
No

Where Yes will list Place with Restaurant instances, and No will list Place without Restaurant instances.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File: filterspecs.py
from django.db import models
from django.contrib.admin.util import get_model_from_relation
from django.contrib.admin.filterspecs import FilterSpec
from django.utils.translation import ugettext as _

class OneToOneExistsFilterSpec(FilterSpec):
    def __init__(self, f, request, params, model, model_admin,
                 field_path=None):
        super(OneToOneExistsFilterSpec, self).__init__(f, request, params,
                                                       model, model_admin,
                                                       field_path=field_path)
        other_model = get_model_from_relation(f)
        if isinstance(f, (models.ManyToManyField,
                          models.related.RelatedObject)):
            # no direct field on this model, get name from other model
            self.lookup_title = other_model._meta.verbose_name
        else:
            self.lookup_title = f.verbose_name # use field name
        self.lookup_kwarg = '%s__isnull' % self.field_path
        self.lookup_val = request.GET.get(self.lookup_kwarg, None)
    
    def title(self):
        return self.lookup_title

    def choices(self, cl):
        for k, v in ((_('All'), None), (_('Yes'), 'False'), (_('No'), 'True')):
            yield {'selected': self.lookup_val == v,
                   'query_string': cl.get_query_string(
                                   {self.lookup_kwarg: v},
                                   [self.lookup_kwarg]),
                   'display': k}

# registering the filter
FilterSpec.filter_specs.insert(0, (lambda f: getattr(f.field, 'exists_filter', False),
                                   OneToOneExistsFilterSpec))

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 2 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 2 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 9 months, 2 weeks ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 10 months, 1 week ago
  5. Help text hyperlinks by sa2812 11 months ago

Comments

declanshanaghy (on February 7, 2012):

The register portion does not work correctly for all field types, try this:

django.contrib.admin.filterspecs.FilterSpec.filter_specs.insert( 0, (lambda f: (hasattr(f, 'field') and getattr(f.field, 'exists_filter', False)), OneToOneExistsFilterSpec))

#

Please login first before commenting.