public

Howto use ListFields in Django's admin

  • Download Gist
0-howto-listfield-django-admin.rst
reStructuredText

Howto use ListFields in Django's admin

Problem

Consider this blog post model:

models.py

from django.db import models
from djangotoolbox.fields import ListField

class Post(models.Model):
    title = models.CharField(max_length=100)
    categories = ListField()

admin.py

from django.contrib.admin import site
from models import Post

site.register(Post)

Trying to edit some posts in the admin crashes with:

No form field implemented for <class 'djangotoolbox.fields.ListField'>

Solution

What we need to do is to teach the admin how to display a ListField in the edit view. Our form field will be a simple <input type=text> input box with comma-separated category names. For more about custom form fields, refer to the Django documentation and your favourite search engine using the terms "Django custom form field".

First, we need to subclass ListField to override the formfield method:

from .forms import StringListField

class CategoryField(ListField):
    def formfield(self, **kwargs):
        return models.Field.formfield(self, StringListField, **kwargs)

class Post(models.Model):
    title = models.CharField(max_length=100)
    categories = CategoryField()

Then, in forms.py, we define StringListField:

from django import forms

class StringListField(forms.CharField):
    def prepare_value(self, value):
        return ', '.join(value)

    def to_python(self, value):
        if not value:
            return []
        return [item.strip() for item in value.split(',')]

This will covert the comma-separated input box contents into a Python list, and the list value that is fetched from the database int a comma-separated string which is then displayed in the input box.

Let's add a post and check out the resulting model object in the database:

http://img30.imageshack.us/img30/2391/editform.png
>>> Post.objects.get(title='foo').categories
[u'spam', u'eggs', u'bar']

It worked! Simple, isn't it?

1-models.py
Python
1 2 3 4 5 6 7 8 9 10 11
from django.db import models
from djangotoolbox.fields import ListField
from .forms import StringListField
 
class CategoryField(ListField):
def formfield(self, **kwargs):
return models.Field.formfield(self, StringListField, **kwargs)
 
class Post(models.Model):
title = models.CharField(max_length=100)
categories = CategoryField()
2-forms.py
Python
1 2 3 4 5 6 7 8 9 10
from django import forms
 
class StringListField(forms.CharField):
def prepare_value(self, value):
return ', '.join(value)
 
def to_python(self, value):
if not value:
return []
return [item.strip() for item in value.split(',')]
3-admin.py
Python
1 2 3 4 5 6 7 8 9 10
from django.contrib.admin import site, ModelAdmin
from models import Post
 
def categories(instance):
return ', '.join(instance.categories)
 
class PostAdmin(ModelAdmin):
list_display = ['title', categories]
 
site.register(Post, PostAdmin)

Thanks a lot for this!

Is there something similar to handle loaddata/dumpdata? At the moment, my 'tags' SetField gets converted to a comma-delimited list of single characters.

@georgedorn could you please open a bug for that: https://github.com/django-nonrel/django-nonrel. With your model definition and the output. Thanks!

Very helpful. Thank You!

Great work! Here's how to use EmbeddedModelField in Django's admin https://gist.github.com/3011156

Thanks. How would you model finding a post by one of the tags?

This is very useful. Thanks a lot!

Thanks so much. This gist got me on the right page!

Thanks! very helpful!

Thanks! Saved my day!

I'll buy u a beer.

谢谢,非常好

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.