- Author:
- EmilStenstrom
- Posted:
- October 4, 2010
- Language:
- Python
- Version:
- 1.4
- Score:
- 6 (after 6 ratings)
UPDATE: Now works in Django 1.4
Based on luc_j:s snippet (http://djangosnippets.org/snippets/2108/) to show values in ManyToManyFields in the admin. This snippets does that, but also links each value to its corresponding admin change page.
To use, just set the raw_id_fields to the value you want, and let your form inherit from ImproveRawIdFieldsForm.
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 | from django import forms
from django.contrib import admin
from django.contrib.admin.sites import site
from django.contrib.admin.widgets import ManyToManyRawIdWidget, ForeignKeyRawIdWidget
from django.core.urlresolvers import reverse
from django.utils.encoding import smart_unicode
from django.utils.html import escape
class VerboseForeignKeyRawIdWidget(ForeignKeyRawIdWidget):
def label_for_value(self, value):
key = self.rel.get_related_field().name
try:
obj = self.rel.to._default_manager.using(self.db).get(**{key: value})
change_url = reverse(
"admin:%s_%s_change" % (obj._meta.app_label, obj._meta.object_name.lower()),
args=(obj.pk,)
)
return ' <strong><a href="%s">%s</a></strong>' % (change_url, escape(obj))
except (ValueError, self.rel.to.DoesNotExist):
return '???'
class VerboseManyToManyRawIdWidget(ManyToManyRawIdWidget):
def label_for_value(self, value):
values = value.split(',')
str_values = []
key = self.rel.get_related_field().name
for v in values:
try:
obj = self.rel.to._default_manager.using(self.db).get(**{key: v})
x = smart_unicode(obj)
change_url = reverse(
"admin:%s_%s_change" % (obj._meta.app_label, obj._meta.object_name.lower()),
args=(obj.pk,)
)
str_values += ['<strong><a href="%s">%s</a></strong>' % (change_url, escape(x))]
except self.rel.to.DoesNotExist:
str_values += [u'???']
return u', '.join(str_values)
class ImproveRawIdFieldsForm(admin.ModelAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name in self.raw_id_fields:
kwargs.pop("request", None)
type = db_field.rel.__class__.__name__
if type == "ManyToOneRel":
kwargs['widget'] = VerboseForeignKeyRawIdWidget(db_field.rel, site)
elif type == "ManyToManyRel":
kwargs['widget'] = VerboseManyToManyRawIdWidget(db_field.rel, site)
return db_field.formfield(**kwargs)
return super(ImproveRawIdFieldsForm, self).formfield_for_dbfield(db_field, **kwargs)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Thanks, works perfectly! I can't imagine why this functionality isn't included by default!
#
Updated to work in Django 1.4.
#
This sounds like just what I am looking for but struggling to see where to put the pieces (as with so many django snippets it's hard when it is just raw code without a note to say where it should be placed !) - I tried adding the above to my admin.py but cannot then see how to inherit my form from ImproveRawIdFieldsForm (my form is currently in forms.py) - am sure I am close !! Any helpful pointers ?
#
@AndyHilton: Here's some example usage: https://gist.github.com/EmilStenstrom/4761449
#
so... how i use in INLINE form?
#
if you change line 45 to the follow it will also support OneToOneRel's
also a good ideal to add the following else after line 48 to avoid losing special handling in super's formfield_for_dbfield for raw_id_fields we don't otherwise handle (assuming there's more than 3 types)
#
Note that you need your admin to inherit from ImproveRawIdFieldsForm, not your form, as stated above (this should become obvious if you actually read the code though).
#
To answer @kase (from a few years ago but I've just found a need for this) you can subclass TabularInline in the same way that you can ModelAdmin. Add this:
class ImproveRawIdFieldsInline(admin.TabularInline): def formfield_for_dbfield(self, db_field, **kwargs): if db_field.name in self.raw_id_fields: kwargs.pop("request", None) type = db_field.rel.__class__.__name__ if type == "ManyToOneRel": kwargs['widget'] = VerboseForeignKeyRawIdWidget(db_field.rel, site) elif type == "ManyToManyRel": kwargs['widget'] = VerboseManyToManyRawIdWidget(db_field.rel, site) return db_field.formfield(**kwargs) return super(ImproveRawIdFieldsInline, self).formfield_for_dbfield(db_field, **kwargs)
Also of note is that this code snippet still works as of Django 1.9.1
#
Oops, formatted properly we have
#
Please login first before commenting.