Collection of admin fields, decorators and mixin to help to create computed or custom fields more friendly and easy way
Requirements: Django > 3 and Python > 3
pip install django-admin-easy==0.8.0
For Django < 1.8 or Python 2.x
pip install django-admin-easy==0.4.1
For Django < 2
pip install django-admin-easy==0.7.0
When you want to display a field on Django Admin, and this field doesn't exist in your Model or you need to compute some information, like a Image or Link, you will need to create a method on your ModelAdminClass like this:
from django.contrib import admin
class YourAdmin(admin.ModelAdmin):
fields = ('sum_method', 'some_img', 'is_true')
def sum_method(self, obj):
sum_result = obj.field1 + obj.field2 + obj.field3
return '<b>%s</b>' % sum_result
sum_method.short_description = 'Sum'
sum_method.admin_order_field = 'field1'
sum_method.allow_tags = True
def some_img(self, obj):
return '<img scr="%s">' % obj.image
some_img.short_description = 'image'
some_img.admin_order_field = 'id'
some_img.allow_tags = True
def is_true(self, obj):
return obj.value > 0
is_true.short_description = 'Positive'
is_true.admin_order_field = 'value'
is_true.boolean = True
It takes too much lines! =D
With django-admin-easy you can easily create this field with less lines:
from django.contrib import admin
import easy
class YourAdmin(admin.ModelAdmin):
fields = ('sum_method', 'some_img', 'is_true')
sum_method = easy.SimpleAdminField(lambda obj: '<b>%s</b>' % (obj.field1 + obj.field2 + obj.field3), 'Sum', 'field1', True)
some_img = easy.ImageAdminField('image', 'id')
is_true = easy.BooleanAdminField('Positive', 'value')
If you still prefer using a custom method, you can use our decorators, like this:
from django.contrib import admin
import easy
class YourAdmin(admin.ModelAdmin):
fields = ('sum_method', 'some_img', 'is_true')
@easy.smart(short_description='Sum', admin_order_field='field1', allow_tags=True )
def sum_method(self, obj):
sum_result = obj.field1 + obj.field2 + obj.field3
return '<b>%s</b>' % sum_result
@easy.short(desc='image', order='id', tags=True)
def some_img(self, obj):
return '<img scr="%s">' % obj.image
@easy.short(desc='Positive', order='value', bool=True)
def is_true(self, obj):
return obj.value > 0
In all of this extra decorators, you can use short or smart arguments to complement field information.
- Allow HTML tags
@easy.with_tags()
def some_field_with_html(self, obj):
return '<b>{}</b>'.format(obj.value)
# output some as: mark_safe("<b>something</b>")
if value is 5, will display:
5 and not <b>5</b> on admin page.
- Cached field
If you, for some reason, need to cache a custom field on admin
@easy.cache(10)# in secondd, default is 60
def some_field_with_html(self, obj):
return obj.related.some_hard_word()
If you change something on your model, or some related object, you can clean this cache using this easy way:
import easy
# wherever you want
easy.cache_clear(my_model_instance)
# or
class MyModel(models.Model):
# ... fields
def save(*args, **kwargs):
easy.cache_clear(self)
super(MyModel, self).save(*args, **kwargs)
- Django template filter
Can be used with all template filters on your project.
# builtin template filter like {{ value|title }}
@easy.filter('title')
def some_field_with_html(self, obj):
return 'ezequiel bertti'
# output: "Ezequiel Bertti"
# like {% load i10n %} and {{ value|localize }}
@easy.filter('localize', 'l10n')
def some_field_with_html(self, obj):
return 10000
# output: "10.000"
# like {{ value|date:'y-m-d' }}
@easy.filter('date', 'default', 'y-m-d')
def some_field_with_html(self, obj):
return datetime(2016, 06, 28)
# output: "16-06-28"
- Django utils functions
Tested with:
@easy.utils('html.escape')
@easy.utils('html.conditional_escape')
@easy.utils('html.strip_tags')
@easy.utils('safestring.mark_safe')
@easy.utils('safestring.mark_for_escaping')
@easy.utils('text.slugify')
@easy.utils('translation.gettext')
@easy.utils('translation.ugettext')
@easy.utils('translation.gettext_lazy')
@easy.utils('translation.ugettext_lazy')
@easy.utils('translation.gettext_noop')
@easy.utils('translation.ugettext_noop')
def your_method(self, obj):
return obj.value
from django.contrib import admin
import easy
class YourAdmin(admin.ModelAdmin):
list_fields = ('id', 'custom1', 'custom2', 'custom3' ... 'customN')
actions = ('simples_action',)
@easy.action('My Little Simple Magic Action')
def simple_action(self, request, queryset):
return queryset.update(magic=True)
# actoin only for user that has change permission on this model
@easy.action('Another Simple Magic Action', 'change')
def simple_action(self, request, queryset):
return queryset.update(magic=True)
# render a value of field, method, property or your model or related model
simple1 = easy.SimpleAdminField('model_field')
simple2 = easy.SimpleAdminField('method_of_model')
simple3 = easy.SimpleAdminField('related.attribute_or_method')
simple4 = easy.SimpleAdminField('related_set.count', 'count')
simple5 = easy.SimpleAdminField(lambda x: x.method(), 'show', 'order_by')
# render boolean fields
bool1 = easy.BooleanAdminField(lambda x: x.value > 10, 'high')
# render with string format fields
format1 = easy.FormatAdminField('{o.model_field} - {o.date_field:Y%-%m}', 'column name')
# render foreignkey with link to change_form in admin
fk1 = easy.ForeignKeyAdminField('related')
# render foreignkey with link to change_form in admin and related_id content as text
fk2 = easy.ForeignKeyAdminField('related', 'related_id')
# render foreignkey_id, like raw_id_fields, with link to change_form in admin and related_id content as text
# without extra queries or select_related to prevent extra n-1 queries
raw1 = easy.RawIdAdminField('related')
# render template
template1 = easy.TemplateAdminField('test.html', 'shorty description', 'order_field')
# render to change_list of another model with a filter on query
link1 = easy.LinkChangeListAdminField('app_label', 'model_name', 'attribute_to_text',
{'field_name':'dynamic_value_model'})
link2 = easy.LinkChangeListAdminField('app_label', 'model_name', 'attribute_to_text',
{'field_name':'dynamic_value_model'},
{'another_field': 'static_value'})
# render link to generic content type fields
# don't forget to use select_related with content-type to avoid N+1 queries like example below
generic = easy.GenericForeignKeyAdminField('generic')
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.select_related('content_type')
# or enable cache
generic = easy.GenericForeignKeyAdminField('generic', cache_content_type=True)
# display image of some model
image1 = easy.ImageAdminField('image', {'image_attrs':'attr_value'})
# use django template filter on a field
filter1 = easy.FilterAdminField('model_field', 'upper')
filter2 = easy.FilterAdminField('date_field', 'date', 'django', 'y-m-d')
filter3 = easy.FilterAdminField('float_field', 'localize', 'l18n')
@easy.smart(short_description='Field Description 12', admin_order_field='model_field')
def custom12(self, obj):
return obj.something_cool()
@easy.short(desc='Field Description 1', order='model_field', tags=True)
def decorator1(self, obj):
return '<b>' + obj.model_field + '</b>'
@easy.short(desc='Field Description 2', order='model_field', bool=True)
def decorator2(self, obj):
return obj.model_field > 10
If you want to use on admin form to show some information,
don't forget to add your custom field on readonly_fields
attribute of your admin class
from django.contrib import admin
import easy
class YourAdmin(admin.ModelAdmin):
fields = ('custom1', 'custom2', 'custom3' ... 'customN')
readonly_fields = ('custom1', 'custom2', 'custom3' ... 'customN')
custom1 = easy.ForeignKeyAdminField('related')
# ...
Another way to use is directly on list_fields
declaration:
from django.contrib import admin
import easy
class YourAdmin(admin.ModelAdmin):
list_fields = (
easy.TemplateAdminField('test.html', 'shorty description', 'order_field'),
easy.ImageAdminField('image', {'image_attrs':'attr_value'}),
# ...
)
# ...
To help you to create a custom view on django admin, we create the MixinEasyViews for your Admin Classes
from django.contrib import admin
import easy
class MyModelAdmin(easy.MixinEasyViews, admin.ModelAdmin):
# ...
def easy_view_jump(self, request, pk=None):
# do something here
return HttpResponse('something')
To call this view, you can use this reverse:
from django.core.urlresolvers import reverse
# to do something with one object of a model
reverse('admin:myapp_mymodel_easy', args=(obj.pk, 'jump'))
# or to do something with a model
reverse('admin:myapp_mymodel_easy', args=('jump',))
Or one HTML template
#<!-- to do something with one object of a model -->
{% url 'admin:myapp_mymodel_easy' obj.pk 'jump' %}
#<!-- or to do something with a model -->
{% url 'admin:myapp_mymodel_easy' 'jump' %}
Response for admin actions
Return for the change list and show some message for the user keeping or not the filters.
from django.contrib import admin
from django.contrib import messages
import easy
class YourAdmin(admin.ModelAdmin):
# ...
actions = ('simples_action',)
def simples_action(self, request, queryset):
success = queryset.do_something()
if success:
return easy.action_response(request, 'Some success message for user', keep_querystring=False)
else:
return easy.action_response(request, 'Some error for user', messages.ERROR)
# or just redirect to changelist with filters
return easy.action_response()
So easy, no?
Using example of poll of django tutorial
This project is still under development. Feedback and suggestions are very welcome and I encourage you to use the Issues list on Github to provide that feedback.
The django-admin-easy was originally created by Ezequiel Bertti @ebertti October 2014.
0.8.0
Add new field GenericForeignKeyAdminField Add Support for Django 5.0 and 5.1 Add Support for Python 3.12 Drop support for Django < 2.0 Add typing and docstring (thanks codeium)
0.7.0
Add support for Django 4.0, 4.1 and 4.2 Add support for Python 3.10 and 3.11 Add Github Actions for testing Add job to realease on pypi Thanks @Lex98
0.6.1
Add support for Django 3.2 and Python 3.9
0.6
Add RawIdAdminField
0.5.1
Add permission on action decorator
0.4.1
Django 2.0
0.4
Django 1.11 Create module utils with action_response
0.3.2
Add params_static to LinkChangeListAdminField
0.3.1
Add FormatAdminField
0.3
Add import from __future__ on all files Django 1.10 More decorators More admin fields
0.2.2
Add MixinEasyViews
0.2.1
Fix for Django 1.7 from @kevgathuku