2

Good afternoon! I'm using the verbose_name_plural dynamic field to show some up-to-date information in the admin panel. Django version: 4.1 The model looks like this:

from django.utils.functional import lazy
from django.utils.translation import gettext_lazy as _

class Post(models.Model):
    # ...

    class Meta:
        verbose_name = 'Post'
        verbose_name_plural = lazy(lambda: _('Posts ({})').format(Post.....count()), str)()

I don't remember where I found this option to display some information, but it works great, except that every time the value changes and the command to create migrations is run, I get something like this:

from django.db import migrations


class Migration(migrations.Migration):
    operations = [
        migrations.AlterModelOptions(
            name='post',
            options={'verbose_name': 'Post', 'verbose_name_plural': 'Posts (123)'},
        ),
    ]

I found this option: https://stackoverflow.com/a/39801321/2166371 But I don’t know how relevant it is and why a class that is not used is imported there

maksam07
  • 31
  • 1
  • 8
  • 1
    Editing the admin page would be better that changing how migrations are run imo - see the answer here: https://stackoverflow.com/questions/6241906/display-number-of-instances-for-each-model-in-djangos-admin-index – 0sVoid Sep 27 '22 at 09:26

1 Answers1

0

Based on the variant that 0sVoid suggested, I implemented a slightly different one that seems to work without problems.

Initially, it was proposed to change one method in the main class of the admin panel (_build_app_dict): https://stackoverflow.com/a/71740645/2166371

But there is too much code in this method that I didn't want to rewrite

I rewrote another method get_app_list

Parent method:

    def get_app_list(self, request, app_label=None):
        """
        Return a sorted list of all the installed apps that have been
        registered in this site.
        """
        app_dict = self._build_app_dict(request, app_label)

        # Sort the apps alphabetically.
        app_list = sorted(app_dict.values(), key=lambda x: x["name"].lower())

        # Sort the models alphabetically within each app.
        for app in app_list:
            app["models"].sort(key=lambda x: x["name"])

        return app_list

My version:

    def get_app_list(self, request, app_label=None):
        """
        Return a sorted list of all the installed apps that have been
        registered in this site.
        """
        app_dict = self._build_app_dict(request, app_label)

        # Sort the apps alphabetically.
        app_list = sorted(app_dict.values(), key=lambda x: x["name"].lower())

        # Sort the models alphabetically within each app.
        for app in app_list:
            app["models"].sort(key=lambda x: x["name"])

            for model in app['models']:
                if hasattr(model['model'], 'get_name_admin_panel'):
                    model['name'] = model['model'].get_name_admin_panel()

        return app_list

I have added 3 new lines, before return (these lines can also be added before sorting if sequence is important to you)

There is a check that if the get_name_admin_panel method is described for the model, then we change its name to the one that the method returns

In the model itself, I added the following lines:

    @classmethod
    def get_name_admin_panel(cls):
        return _('Posts ({})').format(Post.objects.filter(...).count())

Thanks to this, I can now set a static value for the verbose_name_plural field and the migration will not be repeated many times

If you do not specify a @classmethod, then unfortunately the admin panel page will load with an error, but I didn't see any problem with that.

maksam07
  • 31
  • 1
  • 8