Artificial Intelligence

What I Learned Today: Django model_to_dict and Missing Fields

This was actually a couple weeks ago, but it is still fresh enough in my memory that I find it interesting and therefore worth sharing.


Filed under:

This was actually a couple weeks ago, but it is still fresh enough in my memory that I find it interesting and therefore worth sharing.

Background

I had a Django Model that looked something like this:

class MyModel(models.Model):
date_added = models.DateTimeField('date added', auto_now_add=True, db_index=True, editable=False)
title = models.CharField(max_length=32, db_index=True)
title_overridden = models.BooleanField('title overridden', db_index=True, editable=False)
# some other unimportant fields

I had set editable=False to those fields because I did not want users to be able to edit the values of those fields directly if/when I enabled the admin for this model. The initial data for this model was coming from an API source, but an administrator should be able to override the title. When they do, I was setting the title_overridden flag. The main reason is that the title should be kept up-to-date from the API source, unless the administrator has overridden the title then it should keep the administrator's changes.

Problem

I was also creating a view that would return these items as JSON. The quickest way to do that seemed to be django.forms.models.model_to_dict to convert my models to a dictionary, to which I was also adding additional data from the API source, and then using simplejson.dumps to output it as JSON. But for some reason several fields were missing from the dictionary.

The reason is that editable=False fields are automatically ignored in model_to_dict. And as an added gotcha, auto_now_add and auto_now automatically set editable=False.

Solution

Remove editable=False and auto_now_add=True, and create my own ModelManager.

class MyModelManager(models.Manager):

def create(self, **kwargs):
kwargs['date_added'] = datetime.now()

item = super(ScrapbookItemManager, self).create(**kwargs)
return item

class MyModel(models.Model):
date_added = models.DateTimeField('date added', db_index=True)
title = models.CharField(max_length=32, db_index=True)
title_overridden = models.BooleanField('title overridden', db_index=True)
# some other unimportant fields

objects = MyModelManager()

Then when I enable the admin pages for this model, I can create a custom ModelForm using the exclude attribute.

Similar posts

Get notified on new marketing insights

Be the first to know about new B2B SaaS Marketing insights to build or refine your marketing function with the tools and knowledge of today’s industry.