Last active
October 19, 2022 05:52
-
-
Save gregplaysguitar/b97aa5b96d4f322009ccb63a4a8621ce to your computer and use it in GitHub Desktop.
Show object description and a link next to django's raw_id_fields, for ForeignKey and ManyToMany fields
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Show customisable str representation of the linked objects next to each raw id | |
field in a django admin change form. Works for ForeignKey, OneToOneField, and | |
ManyToManyField fields. | |
Example: | |
from django.contrib import admin | |
from admin_raw_id import ImprovedRawIdFieldsAdmin | |
from .models import MyModel | |
@admin.register(MyModel) | |
class MyModelAdmin(ImprovedRawIdFieldsAdmin): | |
... | |
Inspired by https://djangosnippets.org/snippets/2217/ | |
""" | |
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.html import escape | |
class VerboseForeignKeyRawIdWidget(ForeignKeyRawIdWidget): | |
"""Shows customisable str representation of the linked object next to the | |
raw id field for a ForeignKey or OneToOneField in a django admin change | |
form. To customise pass get_str as a keyword argument when initialising | |
the widget. | |
""" | |
def __init__(self, *args, **kwargs): | |
self.get_str = kwargs.pop('get_str', str) | |
super(VerboseForeignKeyRawIdWidget, self).__init__(*args, **kwargs) | |
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}) | |
except (ValueError, self.rel.to.DoesNotExist): | |
return '???' | |
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(self.get_str(obj))) | |
class VerboseManyToManyRawIdWidget(ManyToManyRawIdWidget): | |
"""Shows customisable str representation of the linked object next to the | |
raw id field for a ManyToManyField in a django admin change form. To | |
customise pass get_str as a keyword argument when initialising the | |
widget. | |
""" | |
def __init__(self, *args, **kwargs): | |
self.get_str = kwargs.pop('get_str', str) | |
super(VerboseManyToManyRawIdWidget, self).__init__(*args, **kwargs) | |
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}) | |
except self.rel.to.DoesNotExist: | |
str_values += ['???'] | |
else: | |
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(self.get_str(obj)))] | |
return ', '.join(str_values) | |
class ImprovedRawIdFieldsAdmin(admin.ModelAdmin): | |
def formfield_for_dbfield(self, db_field, **kwargs): | |
if db_field.name in self.raw_id_fields: | |
kwargs.pop("request", None) | |
rel_type = db_field.rel.__class__.__name__ | |
if rel_type == "ManyToManyRel": | |
kwargs['widget'] = VerboseManyToManyRawIdWidget( | |
db_field.rel, site) | |
else: | |
# assume it's a ManyToOneRel or OneToOneRel | |
kwargs['widget'] = VerboseForeignKeyRawIdWidget( | |
db_field.rel, site) | |
return db_field.formfield(**kwargs) | |
return super(ImprovedRawIdFieldsAdmin, self).formfield_for_dbfield( | |
db_field, **kwargs) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment