{"id":13448733,"url":"https://github.com/ebertti/django-admin-easy","last_synced_at":"2025-10-19T18:15:04.086Z","repository":{"id":21433654,"uuid":"24751850","full_name":"ebertti/django-admin-easy","owner":"ebertti","description":"Collection of admin fields and decorators to help to create computed or custom fields more friendly and easy way","archived":false,"fork":false,"pushed_at":"2025-03-06T04:03:05.000Z","size":315,"stargazers_count":499,"open_issues_count":4,"forks_count":30,"subscribers_count":16,"default_branch":"main","last_synced_at":"2025-07-04T22:50:52.901Z","etag":null,"topics":["django","django-admin","easy","easy-to-use","python"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/django-admin-easy/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ebertti.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-10-03T08:38:45.000Z","updated_at":"2025-07-01T18:51:57.000Z","dependencies_parsed_at":"2024-01-06T09:54:02.178Z","dependency_job_id":"0ce40879-a299-44ca-8ea5-cd32c48f8b87","html_url":"https://github.com/ebertti/django-admin-easy","commit_stats":{"total_commits":142,"total_committers":14,"mean_commits":"10.142857142857142","dds":"0.30281690140845074","last_synced_commit":"bc4fc41e7b576fe6ce9590925498bf511e1c85d0"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/ebertti/django-admin-easy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebertti%2Fdjango-admin-easy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebertti%2Fdjango-admin-easy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebertti%2Fdjango-admin-easy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebertti%2Fdjango-admin-easy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ebertti","download_url":"https://codeload.github.com/ebertti/django-admin-easy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebertti%2Fdjango-admin-easy/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263641606,"owners_count":23493419,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","django-admin","easy","easy-to-use","python"],"created_at":"2024-07-31T06:00:19.655Z","updated_at":"2025-10-19T18:14:59.027Z","avatar_url":"https://github.com/ebertti.png","language":"Python","readme":"django-admin-easy\n=================\n\nCollection of admin fields, decorators and mixin to help to create computed or custom fields more friendly and easy way\n\n\n\n.. image:: https://img.shields.io/badge/django-2.x%203.x%204.x%205.0%205.1-brightgreen.svg\n  :target: http://pypi.python.org/pypi/django-admin-easy\n\n.. image:: https://img.shields.io/pypi/v/django-admin-easy.svg?style=flat\n  :target: http://pypi.python.org/pypi/django-admin-easy\n\n.. image:: https://img.shields.io/pypi/pyversions/django-admin-easy.svg?maxAge=2592000\n  :target: http://pypi.python.org/pypi/django-admin-easy\n\n.. image:: https://img.shields.io/pypi/format/django-admin-easy.svg?maxAge=2592000\n  :target: http://pypi.python.org/pypi/django-admin-easy\n\n.. image:: https://img.shields.io/pypi/status/django-admin-easy.svg?maxAge=2592000\n  :target: http://pypi.python.org/pypi/django-admin-easy\n\n.. image:: https://github.com/ebertti/django-admin-easy/actions/workflows/test.yml/badge.svg?maxAge=2592000\n  :target: https://github.com/ebertti/django-admin-easy/actions/workflows/test.yml\n\n.. image:: https://img.shields.io/coveralls/ebertti/django-admin-easy/master.svg?maxAge=2592000\n  :target: https://coveralls.io/r/ebertti/django-admin-easy?branch=master\n\n\nInstallation\n------------\n\n1. Requirements: **Django \u003e 3** and **Python \u003e 3**\n\n    ``pip install django-admin-easy==0.8.0``\n\n\n* For **Django \u003c 1.8** or **Python 2.x**\n\n    ``pip install django-admin-easy==0.4.1``\n\n* For **Django \u003c 2**\n\n    ``pip install django-admin-easy==0.7.0``\n\n\nHow it Works\n------------\n\nWhen you want to display a field on Django Admin, and this field doesn't exist in your Model\nor you need to compute some information, like a Image or Link, you will need to create a method on your ModelAdminClass like this:\n\n.. code-block:: python\n\n    from django.contrib import admin\n\n    class YourAdmin(admin.ModelAdmin):\n        fields = ('sum_method', 'some_img', 'is_true')\n\n        def sum_method(self, obj):\n            sum_result = obj.field1 + obj.field2 + obj.field3\n            return '\u003cb\u003e%s\u003c/b\u003e' % sum_result\n        sum_method.short_description = 'Sum'\n        sum_method.admin_order_field = 'field1'\n        sum_method.allow_tags = True\n\n        def some_img(self, obj):\n            return '\u003cimg scr=\"%s\"\u003e' % obj.image\n        some_img.short_description = 'image'\n        some_img.admin_order_field = 'id'\n        some_img.allow_tags = True\n\n        def is_true(self, obj):\n            return obj.value \u003e 0\n        is_true.short_description = 'Positive'\n        is_true.admin_order_field = 'value'\n        is_true.boolean = True\n\nIt takes too much lines! =D\n\nWith **django-admin-easy** you can easily create this field with less lines:\n\n.. code-block:: python\n\n    from django.contrib import admin\n    import easy\n\n    class YourAdmin(admin.ModelAdmin):\n        fields = ('sum_method', 'some_img', 'is_true')\n\n        sum_method = easy.SimpleAdminField(lambda obj: '\u003cb\u003e%s\u003c/b\u003e' % (obj.field1 + obj.field2 + obj.field3), 'Sum', 'field1', True)\n        some_img = easy.ImageAdminField('image', 'id')\n        is_true = easy.BooleanAdminField('Positive', 'value')\n\nIf you still prefer using a custom method, you can use our decorators, like this:\n\n.. code-block:: python\n\n    from django.contrib import admin\n    import easy\n\n    class YourAdmin(admin.ModelAdmin):\n        fields = ('sum_method', 'some_img', 'is_true')\n\n        @easy.smart(short_description='Sum', admin_order_field='field1', allow_tags=True )\n        def sum_method(self, obj):\n            sum_result = obj.field1 + obj.field2 + obj.field3\n            return '\u003cb\u003e%s\u003c/b\u003e' % sum_result\n\n        @easy.short(desc='image', order='id', tags=True)\n        def some_img(self, obj):\n            return '\u003cimg scr=\"%s\"\u003e' % obj.image\n\n        @easy.short(desc='Positive', order='value', bool=True)\n        def is_true(self, obj):\n            return obj.value \u003e 0\n\nAnother Decorators\n------------------\n\nIn all of this extra decorators, you can use `short` or `smart` arguments to complement field information.\n\n* **Allow HTML tags**\n\n.. code-block:: python\n\n    @easy.with_tags()\n    def some_field_with_html(self, obj):\n        return '\u003cb\u003e{}\u003c/b\u003e'.format(obj.value)\n    # output some as: mark_safe(\"\u003cb\u003esomething\u003c/b\u003e\")\n\n\nif value is `5`, will display:\n\n**5** and not `\u003cb\u003e5\u003c/b\u003e` on admin page.\n\n* **Cached field**\n\nIf you, for some reason, need to cache a custom field on admin\n\n.. code-block:: python\n\n    @easy.cache(10)# in secondd, default is 60\n    def some_field_with_html(self, obj):\n        return obj.related.some_hard_word()\n\nIf you change something on your model, or some related object, you can clean this cache using this easy way:\n\n.. code-block:: python\n\n    import easy\n    # wherever you want\n    easy.cache_clear(my_model_instance)\n\n    # or\n    class MyModel(models.Model):\n        # ... fields\n\n        def save(*args, **kwargs):\n            easy.cache_clear(self)\n            super(MyModel, self).save(*args, **kwargs)\n\n\n* **Django template filter**\n\nCan be used with all template filters on your project.\n\n.. code-block:: python\n\n    # builtin template filter like {{ value|title }}\n    @easy.filter('title')\n    def some_field_with_html(self, obj):\n        return 'ezequiel bertti'\n    # output: \"Ezequiel Bertti\"\n\n    # like {% load i10n %} and {{ value|localize }}\n    @easy.filter('localize', 'l10n')\n    def some_field_with_html(self, obj):\n        return 10000\n    # output: \"10.000\"\n\n    # like {{ value|date:'y-m-d' }}\n    @easy.filter('date', 'default', 'y-m-d')\n    def some_field_with_html(self, obj):\n        return datetime(2016, 06, 28)\n    # output: \"16-06-28\"\n\n* **Django utils functions**\n\nTested with:\n\n.. code-block:: python\n\n    @easy.utils('html.escape')\n    @easy.utils('html.conditional_escape')\n    @easy.utils('html.strip_tags')\n    @easy.utils('safestring.mark_safe')\n    @easy.utils('safestring.mark_for_escaping')\n    @easy.utils('text.slugify')\n    @easy.utils('translation.gettext')\n    @easy.utils('translation.ugettext')\n    @easy.utils('translation.gettext_lazy')\n    @easy.utils('translation.ugettext_lazy')\n    @easy.utils('translation.gettext_noop')\n    @easy.utils('translation.ugettext_noop')\n    def your_method(self, obj):\n        return obj.value\n\nMore Examples\n-------------\n\n.. code-block:: python\n\n    from django.contrib import admin\n    import easy\n\n    class YourAdmin(admin.ModelAdmin):\n        list_fields = ('id', 'custom1', 'custom2', 'custom3' ... 'customN')\n\n        actions = ('simples_action',)\n\n        @easy.action('My Little Simple Magic Action')\n        def simple_action(self, request, queryset):\n            return queryset.update(magic=True)\n\n        # actoin only for user that has change permission on this model\n        @easy.action('Another Simple Magic Action', 'change')\n        def simple_action(self, request, queryset):\n            return queryset.update(magic=True)\n\n\n        # render a value of field, method, property or your model or related model\n        simple1 = easy.SimpleAdminField('model_field')\n        simple2 = easy.SimpleAdminField('method_of_model')\n        simple3 = easy.SimpleAdminField('related.attribute_or_method')\n        simple4 = easy.SimpleAdminField('related_set.count', 'count')\n        simple5 = easy.SimpleAdminField(lambda x: x.method(), 'show', 'order_by')\n\n        # render boolean fields\n        bool1 = easy.BooleanAdminField(lambda x: x.value \u003e 10, 'high')\n\n        # render with string format fields\n        format1 = easy.FormatAdminField('{o.model_field} - {o.date_field:Y%-%m}', 'column name')\n\n        # render foreignkey with link to change_form in admin\n        fk1 = easy.ForeignKeyAdminField('related')\n\n        # render foreignkey with link to change_form in admin and related_id content as text\n        fk2 = easy.ForeignKeyAdminField('related', 'related_id')\n\n        # render foreignkey_id, like raw_id_fields, with link to change_form in admin and related_id content as text\n        # without extra queries or select_related to prevent extra n-1 queries\n        raw1 = easy.RawIdAdminField('related')\n\n        # render template\n        template1 = easy.TemplateAdminField('test.html', 'shorty description', 'order_field')\n\n        # render to change_list of another model with a filter on query\n        link1 = easy.LinkChangeListAdminField('app_label', 'model_name', 'attribute_to_text',\n                                              {'field_name':'dynamic_value_model'})\n\n        link2 = easy.LinkChangeListAdminField('app_label', 'model_name', 'attribute_to_text',\n                                              {'field_name':'dynamic_value_model'},\n                                              {'another_field': 'static_value'})\n\n        # render link to generic content type fields\n        # don't forget to use select_related with content-type to avoid N+1 queries like example below\n        generic = easy.GenericForeignKeyAdminField('generic')\n\n        def get_queryset(self, request):\n            qs = super().get_queryset(request)\n\n            return qs.select_related('content_type')\n\n        # or enable cache\n        generic = easy.GenericForeignKeyAdminField('generic', cache_content_type=True)\n\n        # display image of some model\n        image1 = easy.ImageAdminField('image', {'image_attrs':'attr_value'})\n\n        # use django template filter on a field\n        filter1 = easy.FilterAdminField('model_field', 'upper')\n        filter2 = easy.FilterAdminField('date_field', 'date', 'django', 'y-m-d')\n        filter3 = easy.FilterAdminField('float_field', 'localize', 'l18n')\n\n        @easy.smart(short_description='Field Description 12', admin_order_field='model_field')\n        def custom12(self, obj):\n            return obj.something_cool()\n\n        @easy.short(desc='Field Description 1', order='model_field', tags=True)\n        def decorator1(self, obj):\n            return '\u003cb\u003e' + obj.model_field + '\u003c/b\u003e'\n\n        @easy.short(desc='Field Description 2', order='model_field', bool=True)\n        def decorator2(self, obj):\n            return obj.model_field \u003e 10\n\n\nIf you want to use on admin form to show some information,\ndon't forget to add your custom field on ``readonly_fields`` attribute of your admin class\n\n.. code-block:: python\n\n    from django.contrib import admin\n    import easy\n\n    class YourAdmin(admin.ModelAdmin):\n        fields = ('custom1', 'custom2', 'custom3' ... 'customN')\n        readonly_fields = ('custom1', 'custom2', 'custom3' ... 'customN')\n\n        custom1 = easy.ForeignKeyAdminField('related')\n        # ...\n\nAnother way to use is directly on ``list_fields`` declaration:\n\n.. code-block:: python\n\n    from django.contrib import admin\n    import easy\n\n    class YourAdmin(admin.ModelAdmin):\n        list_fields = (\n            easy.TemplateAdminField('test.html', 'shorty description', 'order_field'),\n            easy.ImageAdminField('image', {'image_attrs':'attr_value'}),\n            # ...\n        )\n\n        # ...\n\nMixin\n-----\n\nTo help you to create a custom view on django admin, we create the MixinEasyViews for your Admin Classes\n\n.. code-block:: python\n\n    from django.contrib import admin\n    import easy\n\n    class MyModelAdmin(easy.MixinEasyViews, admin.ModelAdmin):\n        # ...\n\n        def easy_view_jump(self, request, pk=None):\n            # do something here\n            return HttpResponse('something')\n\nTo call this view, you can use this reverse:\n\n.. code-block:: python\n\n    from django.core.urlresolvers import reverse\n\n    # to do something with one object of a model\n    reverse('admin:myapp_mymodel_easy', args=(obj.pk, 'jump'))\n\n    # or to do something with a model\n    reverse('admin:myapp_mymodel_easy', args=('jump',))\n\nOr one HTML template\n\n.. code-block:: html\n\n    #\u003c!-- to do something with one object of a model --\u003e\n    {% url 'admin:myapp_mymodel_easy' obj.pk 'jump' %}\n\n    #\u003c!-- or to do something with a model --\u003e\n    {% url 'admin:myapp_mymodel_easy' 'jump' %}\n\nUtilities\n---------\n\n* Response for admin actions\n\n  Return for the change list and show some message for the user keeping or not the filters.\n\n.. code-block:: python\n\n    from django.contrib import admin\n    from django.contrib import messages\n    import easy\n\n    class YourAdmin(admin.ModelAdmin):\n        # ...\n        actions = ('simples_action',)\n\n        def simples_action(self, request, queryset):\n\n            success = queryset.do_something()\n            if success:\n                return easy.action_response(request, 'Some success message for user', keep_querystring=False)\n            else:\n                return easy.action_response(request, 'Some error for user', messages.ERROR)\n\n            # or just redirect to changelist with filters\n            return easy.action_response()\n\nSo easy, no?\n\nScreenshot\n----------\n\nUsing example of poll of django tutorial\n\n.. image:: https://raw.githubusercontent.com/ebertti/django-admin-easy/master/screenshot/more.png\n\n.. image:: https://raw.githubusercontent.com/ebertti/django-admin-easy/master/screenshot/related.png\n\nPlease help us\n--------------\nThis project is still under development. Feedback and suggestions are very welcome and I encourage you to use the `Issues list \u003chttp://github.com/ebertti/django-admin-easy/issues\u003e`_ on Github to provide that feedback.\n\n.. image:: https://img.shields.io/github/issues/ebertti/django-admin-easy.svg\n   :target: https://github.com/ebertti/django-admin-easy/issues\n\n.. image:: https://img.shields.io/waffle/label/ebertti/django-admin-easy/in%20progress.svg?maxAge=2592000\n   :target: https://waffle.io/ebertti/django-admin-easy\n\n.. image:: https://img.shields.io/github/forks/ebertti/django-admin-easy.svg\n   :target: https://github.com/ebertti/django-admin-easy/network\n\n.. image:: https://img.shields.io/github/stars/ebertti/django-admin-easy.svg\n   :target: https://github.com/ebertti/django-admin-easy/stargazers\n\nAuthors\n-------\nThe django-admin-easy was originally created by Ezequiel Bertti `@ebertti \u003chttps://github.com/ebertti\u003e`_ October 2014.\n\nChangelog\n---------\n* 0.8.0\n\n   Add new field GenericForeignKeyAdminField\n   Add Support for Django 5.0 and 5.1\n   Add Support for Python 3.12\n   Drop support for Django \u003c 2.0\n   Add typing and docstring (thanks `codeium \u003chttps://codeium.com/\u003e`_)\n\n* 0.7.0\n\n   Add support for Django 4.0, 4.1 and 4.2\n   Add support for Python 3.10 and 3.11\n   Add Github Actions for testing\n   Add job to realease on pypi\n   Thanks @Lex98\n\n* 0.6.1\n\n   Add support for Django 3.2 and Python 3.9\n\n* 0.6\n\n   Add RawIdAdminField\n\n* 0.5.1\n\n   Add permission on action decorator\n\n* 0.4.1\n\n   Django 2.0\n\n* 0.4\n\n   Django 1.11\n   Create module utils with action_response\n\n* 0.3.2\n\n   Add params_static to LinkChangeListAdminField\n\n* 0.3.1\n\n   Add FormatAdminField\n\n* 0.3\n\n   Add import from `__future__` on all files\n   Django 1.10\n   More decorators\n   More admin fields\n\n* 0.2.2\n\n   Add MixinEasyViews\n\n* 0.2.1\n\n   Fix for Django 1.7 from `@kevgathuku \u003chttps://github.com/kevgathuku\u003e`_\n\n\nStar History\n------------\n\n.. image:: https://api.star-history.com/svg?repos=ebertti/django-admin-easy\u0026type=Date\n  :target: https://star-history.com/#ebertti/django-admin-easy\u0026Date\n","funding_links":[],"categories":["Admin interface","Python","管理界面","Best Django Admin Interface Resources","Packages to install at your project"],"sub_categories":["Admin Extensions \u0026 Functional Enhancements","Packages"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Febertti%2Fdjango-admin-easy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Febertti%2Fdjango-admin-easy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Febertti%2Fdjango-admin-easy/lists"}