Enhance group auth model with field and a custom string representation

I would like to add a extra field to django.contrib.auth.models.Group and to change the display behavior of this field in the django user/groups administration view.

A simple example:

from django.contrib.auth.models import Group
from django.db import models

def _alternative_group_representation(self) -> str:
    return self.foo_description or self.name

Group.add_to_class('foo_description',
                   models.CharField(max_length=150, null=True, blank=True, verbose_name="Human readable name"))
Group.add_to_class('__str__', _alternative_group_representation)

That works if i execute “makemigrations” and “migration” but seems to have real drawbacks:

  • the migration are created to venv/lib/python3.8/site-packages/django/contrib/auth/migrations/ and i found no solution to change that
  • the migration depends on the version of the django framework
  • monkeypatching this class appears to be a unsafe, ugly and dangerous

Is there a better possibility to achieve this?
Proxy models not seem to the right choice to replace the original model.

2 Likes

You are correct. It has been my experience that the standard Django Group model is what it is, and that any change to it implies the creation of a new model.

Rather than trying to modify the Group model itself, you might find it easier to use the “profile model” to associate additional data with the group.
Yes, this does mean that your views and templates need to be aware of that relationship - but then, if you’re creating a new Group-ish model, the views and templates need to be aware of that, too.

1 Like

My main question is: Is there a chance to create a proxied group model and to replace the standard group model by my enhanced version. How can i do this?

To the best of my knowledge, not without replacing the User model as well. If you use a custom user model, you can replace the group field with one having a relationship to your group model.

2 Likes

I am still a newbie regarding the django model internals :slight_smile:
If i follow your recommendation and the tutorial at Customizing authentication in Django | Django documentation | Django i am trying something like that:

settings.py

AUTH_USER_MODEL = 'main.FooUser'

# Application definition
INSTALLED_APPS = [
    'foo.app.main',
    ...

main.models.py:

from django.contrib.auth.models import Group
from django.contrib.auth.models import AbstractUser

from django.db import models


class FooGroup(Group):
    description = models.CharField(max_length=150, null=True, blank=True, verbose_name="Human readable name")

    def __str__(self):
        return self.description or self.name


class FooUser(AbstractUser):
   # Fetched from the iriginal implementation
    groups = models.ManyToManyField(
        FooGroup,
        verbose_name=('groups'),
        blank=True,
        help_text=(
            'The groups this user belongs to. A user will get all permissions '
            'granted to each of their groups.'
        ),
        related_name="user_set",
        related_query_name="user",
    )

main/admin.py:

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import FooUser, FooGroup

admin.site.register(FooUser, UserAdmin)

If i now execute a “./manage.py makemigrations” to migrations are created.
What did i missed to use my adapted model?

2 Likes

Is this a new app for which no previous migrations have been created? If so, try manage.py makemigrations main

Migrations relies upon a directory (migrations) existing within the application. It will not automatically create migrations for an app if that directory doesn’t exist, so the first time you do a makemigrations, you want to specify the name of the app to allow Django to create that directory.

1 Like