Package: django-admin-easy
Collection of admin fields, decorators and mixin to help to create computed or custom fields more friendly and easy wayInstallationRequirements:Django > 1.8andPython > 3.5pip installdjango-admin-easy==0.7.0ForDjango < 1.8orPython 2.xpip installdjango-admin-easy==0.4.1How it WorksWhen 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:fromdjango.contribimportadminclassYourAdmin(admin.ModelAdmin):fields=('sum_method','some_img','is_true')defsum_method(self,obj):sum_result=obj.field1+obj.field2+obj.field3return'<b>%s</b>'%sum_resultsum_method.short_description='Sum'sum_method.admin_order_field='field1'sum_method.allow_tags=Truedefsome_img(self,obj):return'<img scr="%s">'%obj.imagesome_img.short_description='image'some_img.admin_order_field='id'some_img.allow_tags=Truedefis_true(self,obj):returnobj.value>0is_true.short_description='Positive'is_true.admin_order_field='value'is_true.boolean=TrueIt takes too much lines! =DWithdjango-admin-easyyou can easily create this field with less lines:fromdjango.contribimportadminimporteasyclassYourAdmin(admin.ModelAdmin):fields=('sum_method','some_img','is_true')sum_method=easy.SimpleAdminField(lambdaobj:'<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:fromdjango.contribimportadminimporteasyclassYourAdmin(admin.ModelAdmin):fields=('sum_method','some_img','is_true')@easy.smart(short_description='Sum',admin_order_field='field1',allow_tags=True)defsum_method(self,obj):sum_result=obj.field1+obj.field2+obj.field3return'<b>%s</b>'%sum_result@easy.short(desc='image',order='id',tags=True)defsome_img(self,obj):return'<img scr="%s">'%obj.image@easy.short(desc='Positive',order='value',bool=True)defis_true(self,obj):returnobj.value>0Another DecoratorsIn all of this extra decorators, you can useshortorsmartarguments to complement field information.Allow HTML tags@easy.with_tags()defsome_field_with_html(self,obj):return'<b>{}</b>'.format(obj.value)# output some as: mark_safe("<b>something</b>")if value is5, will display:5and not<b>5</b>on admin page.Cached fieldIf you, for some reason, need to cache a custom field on admin@easy.cache(10)# in secondd, default is 60defsome_field_with_html(self,obj):returnobj.related.some_hard_word()If you change something on your model, or some related object, you can clean this cache using this easy way:importeasy# wherever you wanteasy.cache_clear(my_model_instance)# orclassMyModel(models.Model):# ... fieldsdefsave(*args,**kwargs):easy.cache_clear(self)super(MyModel,self).save(*args,**kwargs)Django template filterCan be used with all template filters on your project.# builtin template filter like {{ value|title }}@easy.filter('title')defsome_field_with_html(self,obj):return'ezequiel bertti'# output: "Ezequiel Bertti"# like {% load i10n %} and {{ value|localize }}@easy.filter('localize','l10n')defsome_field_with_html(self,obj):return10000# output: "10.000"# like {{ value|date:'y-m-d' }}@easy.filter('date','default','y-m-d')defsome_field_with_html(self,obj):returndatetime(2016,06,28)# output: "16-06-28"Django utils functionsTested 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')defyour_method(self,obj):returnobj.valueMore Examplesfromdjango.contribimportadminimporteasyclassYourAdmin(admin.ModelAdmin):list_fields=('id','custom1','custom2','custom3'...'customN')actions=('simples_action',)@easy.action('My Little Simple Magic Action')defsimple_action(self,request,queryset):returnqueryset.update(magic=True)# actoin only for user that has change permission on this model@easy.action('Another Simple Magic Action','change')defsimple_action(self,request,queryset):returnqueryset.update(magic=True)# render a value of field, method, property or your model or related modelsimple1=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(lambdax:x.method(),'show','order_by')# render boolean fieldsbool1=easy.BooleanAdminField(lambdax:x.value>10,'high')# render with string format fieldsformat1=easy.FormatAdminField('{o.model_field}- {o.date_field:Y%-%m}','column name')# render foreignkey with link to change_form in adminfk1=easy.ForeignKeyAdminField('related')# render foreignkey with link to change_form in admin and related_id content as textfk2=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 queriesraw1=easy.RawIdAdminField('related')# render templatetemplate1=easy.TemplateAdminField('test.html','shorty description','order_field')# render to change_list of another model with a filter on querylink1=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'})# display image of some modelimage1=easy.ImageAdminField('image',{'image_attrs':'attr_value'})# use django template filter on a fieldfilter1=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')defcustom12(self,obj):returnobj.something_cool()@easy.short(desc='Field Description 1',order='model_field',tags=True)defdecorator1(self,obj):return'<b>'+obj.model_field+'</b>'@easy.short(desc='Field Description 2',order='model_field',bool=True)defdecorator2(self,obj):returnobj.model_field>10If you want to use on admin form to show some information,
don’t forget to add your custom field onreadonly_fieldsattribute of your admin classfromdjango.contribimportadminimporteasyclassYourAdmin(admin.ModelAdmin):fields=('custom1','custom2','custom3'...'customN')readonly_fields=('custom1','custom2','custom3'...'customN')custom1=easy.ForeignKeyAdminField('related')# ...Another way to use is directly onlist_fieldsdeclaration:fromdjango.contribimportadminimporteasyclassYourAdmin(admin.ModelAdmin):list_fields=(easy.TemplateAdminField('test.html','shorty description','order_field'),easy.ImageAdminField('image',{'image_attrs':'attr_value'}),# ...)# ...MixinTo help you to create a custom view on django admin, we create the MixinEasyViews for your Admin Classesfromdjango.contribimportadminimporteasyclassMyModelAdmin(easy.MixinEasyViews,admin.ModelAdmin):# ...defeasy_view_jump(self,request,pk=None):# do something herereturnHttpResponse('something')To call this view, you can use this reverse:fromdjango.core.urlresolversimportreverse# to do something with one object of a modelreverse('admin:myapp_mymodel_easy',args=(obj.pk,'jump'))# or to do something with a modelreverse('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' %}UtilitiesResponse for admin actionsReturn for the change list and show some message for the user keeping or not the filters.fromdjango.contribimportadminfromdjango.contribimportmessagesimporteasyclassYourAdmin(admin.ModelAdmin):# ...actions=('simples_action',)defsimples_action(self,request,queryset):success=queryset.do_something()ifsuccess:returneasy.action_response(request,'Some success message for user',keep_querystring=False)else:returneasy.action_response(request,'Some error for user',messages.ERROR)# or just redirect to changelist with filtersreturneasy.action_response()So easy, no?ScreenshotUsing example of poll of django tutorialPlease help usThis project is still under development. Feedback and suggestions are very welcome and I encourage you to use theIssues liston Github to provide that feedback.AuthorsThe django-admin-easy was originally created by Ezequiel Bertti@eberttiOctober 2014.Changelog0.7.0Add 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 @Lex980.6.1Add support for Django 3.2 and Python 3.90.6Add RawIdAdminField0.5.1Add permission on action decorator0.4.1Django 2.00.4Django 1.11
Create module utils with action_response0.3.2Add params_static to LinkChangeListAdminField0.3.1Add FormatAdminField0.3Add import from__future__on all files
Django 1.10
More decorators
More admin fields0.2.2Add MixinEasyViews0.2.1Fix for Django 1.7 from@kevgathuku