Yawd website

aug16

Allow for lazy dynamic choices in django's model fields

Here's a quick how-to for those that need to dynamically generate model field choices with django. Normally we would define a CharField as follows, where choices should be a tuple containing static choices.

class TestModel(models.Model):
    ...
    choices_f = models.CharField(max_length=8, blank=True,choices=('Choice 1','Choice 2',
        'Choice 3','Choice 4'))

In order to dynamically get the choices (say, from a function get_menu_choices that returns a list containing the choices) we must define the model as follows:

def get_menu_choices():
    choices_tuple = []
    #do your stuff
    return choices_tuple

class TestModel(models.Model):
     ...
    choices_f = models.CharField(max_length=8, blank=True)

    def __init__(self,  *args, **kwargs):
        super(MenuItem, self).__init__(*args, **kwargs)
        self._meta.get_field_by_name('choices_f')[0]._choices = get_menu_choices()

This will work as expected, however get_menu_choices will be called each and every time a TestModel object will be instantiated. If get_menu_choices function queries the database a couple of times this does not seem to be the best solution. Ideally we would like get_menu_choices to be called only when we actually need to access the choices; that is, to be called lazily. In such a situation django's lazy utility function comes in handy. This function is not well documented since it was originally used only in django's source code.

from django.utils.functional import lazy


def get_menu_choices():
    choices_tuple = []
    #do your stuff
    return choices_tuple

class TestModel(models.Model):
     ...
    choices_f = models.CharField(max_length=8, blank=True)

    def __init__(self,  *args, **kwargs):
        super(MenuItem, self).__init__(*args, **kwargs)
        self._meta.get_field_by_name('choices_f')[0]._choices = lazy(getMenuChoices, list)()

Hope this yawd tip helps someone and saves him the time I spent looking for this solution! :)

Meta

Published: Aug. 16, 2011
Comments:  
Word Count: 301
Comments powered by Disqus