Login

Exclusive boolean field

Author:
anentropic
Posted:
December 8, 2009
Language:
Python
Version:
1.1
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. Template tag - list punctuation for a list of items by shapiromatron 2 months ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 2 months, 1 week ago
  3. Serializer factory with Django Rest Framework by julio 9 months, 1 week ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 9 months, 4 weeks ago
  5. Help text hyperlinks by sa2812 10 months, 3 weeks 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.