Link raw_id_fields (both ForeignKeys and ManyToManyFields) to their change pages

 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 '&nbsp;<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

  1. Display user-friendly values of a ManyToManyRawIdWidget by luc_j 2 years, 10 months ago
  2. RelatedNullFilterSpec: django-admin custom filter all/null/not null/choices by Codeko 2 years, 7 months ago
  3. Make hyperlinks for labels of raw_id_fields (jQuery) by ramen 3 years, 4 months ago
  4. ForeignKey filterspec by luc_j 2 years, 8 months ago
  5. Admin Hack: Quick lookup of GenericForeignKey id by ContentType by adnan 4 years, 7 months ago

Comments

Cerinin (on February 26, 2012):

Thanks, works perfectly! I can't imagine why this functionality isn't included by default!

#

EmilStenstrom (on April 25, 2012):

Updated to work in Django 1.4.

#

AndyHilton (on December 29, 2012):

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 ?

#

EmilStenstrom (on February 12, 2013):

@AndyHilton: Here's some example usage: https://gist.github.com/EmilStenstrom/4761449

#

(Forgotten your password?)