Login

Exclusive boolean field

Author:
anentropic
Posted:
December 8, 2009
Language:
Python
Version:
1.1
Tags:
field
Score:
3 (after 3 ratings)

NOTE: I now have a better implementation of this (nicer api, less signal wrangling) available on PyPI here

Sometimes you want to be able to make one (and only one) row in your model 'featured' or 'the default one'

If you have some kind of parent model you could have a ForeignKey on the parent to hold that info, but that won't always be the case - eg you may have no parent, or multiple parent models.

With the exclusive_boolean_fields() helper you can do it with or without a parent model and it possibly makes the admin interface a bit simpler.

 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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
"""
NOTE: I now have a better implementation of this
(nicer api, less signal wrangling) available on PyPI here:
https://pypi.python.org/pypi/django-exclusivebooleanfield
"""

from django.db.models.signals import post_save

"""
an Exclusive Boolean Field means that only one row in the model table
can have that field True at a time...

if you supply names in 'with_fields' then only one row in the model table
where those additional fields match the instance being saved can have
their exclusive boolean fields True at the same time.
"""
def exclusive_boolean_handler(sender, instance, created, **kwargs):
    eb_fields = getattr(sender, '_exclusive_boolean_fields', [])
    with_fields = getattr(sender, '_exclusive_boolean_with_fields', [])
    uargs = {}
    for field in eb_fields:
        ifield = getattr(instance, field)
        if ifield == True:
            uargs.update({field:False})
    fargs = {}
    for field in with_fields:
        ifield = getattr(instance, field)
        fargs.update({field:ifield})
    sender.objects.filter(**fargs).exclude(pk=instance.pk).update(**uargs)

def exclusive_boolean_fields(model, eb_fields=[], with_fields=[]):
    setattr(model, '_exclusive_boolean_fields', eb_fields)
    setattr(model, '_exclusive_boolean_with_fields', with_fields)
    post_save.connect(exclusive_boolean_handler, sender=model)


"""
Example usage:
"""
class Address(models.Model):
    account = models.ForeignKey(Account, related_name='addresses')
    default = models.BooleanField(default=False)
    
    country = CountryField()
    postcode = models.CharField(max_length=16)
    line1 = models.CharField(max_length=128)
    line2 = models.CharField(max_length=128, blank=True, null=True)
    line3 = models.CharField(max_length=128, blank=True, null=True)
    
exclusive_boolean_fields(Address, ('default',), ('account',))

"""
i.e.
if you set the 'default' field to True on an instance, then it will
be set False on all the other rows with the same 'account' value
"""

More like this

  1. Markup Selection in Admin by jonathan 7 years, 9 months ago
  2. DRY with common model fields (another way) by jmrbcu 7 years, 10 months ago
  3. Self-referencing Foreign Key Infinite Loop by minarets 7 years, 8 months ago
  4. Model inheritance with content type by crucialfelix 6 years, 8 months ago
  5. jstree integration to django admin by pawnhearts 5 years, 4 months ago

Comments

diverman (on December 8, 2009):

Nice. Better for this purpose will be theoretical TrueNoneField (modification of NullBooleanField that stores only True and None values) and unique_together with another field. Or improve data model to go around this...

#

anentropic (on October 25, 2011):

that's a nice idea and wouldn't be impossible...

#

Please login first before commenting.