How do I extend the Django Group model?

前端 未结 4 1048
Happy的楠姐
Happy的楠姐 2020-12-01 02:12

Is there a way to extend the built-in Django Group object to add additional attributes similar to the way you can extend a user object? With a user object, you can do the fo

相关标签:
4条回答
  • 2020-12-01 02:28

    You can create a model that subclasses Group, add your own fields, and use a Model Manager to return any custom querysets you need. Here's a truncated example showing how I extended Group to represent Families associated with a school:

    from django.contrib.auth.models import Group, User
    
    class FamilyManager(models.Manager):
        """
        Lets us do querysets limited to families that have 
        currently enrolled students, e.g.:
            Family.has_students.all() 
        """
        def get_query_set(self):
            return super(FamilyManager, self).get_query_set().filter(student__enrolled=True).distinct()
    
    
    class Family(Group):
        notes = models.TextField(blank=True)
    
        # Two managers for this model - the first is default 
        # (so all families appear in the admin).
        # The second is only invoked when we call 
        # Family.has_students.all()  
        objects = models.Manager()
        has_students = FamilyManager()
    
        class Meta:
            verbose_name_plural = "Families"
            ordering = ['name']
    
        def __unicode__(self):
            return self.name
    
    0 讨论(0)
  • 2020-12-01 02:33

    If you simply subclass the Group object then by default it will create a new database table and the admin site won't pick up any new fields.

    You need to inject new fields into the existing Group:

    if not hasattr(Group, 'parent'):
        field = models.ForeignKey(Group, blank=True, null=True, related_name='children')
        field.contribute_to_class(Group, 'parent')
    

    To add methods to the Group, subclass but tag the model as proxy:

    class MyGroup(Group):
    
        class Meta:
            proxy = True
    
        def myFunction(self):
            return True
    
    0 讨论(0)
  • 2020-12-01 02:39

    For me worked solution based on:

    https://docs.djangoproject.com/pl/1.11/topics/auth/customizing/#extending-user

    Let me explain what I did with Groups extending default model with email alias:

    First of all I created my own django application let name it

    python manage.py startapp auth_custom

    Code section:

    In auth_custom/models.py I created object CustomGroup

    from django.contrib.auth.models import Group
    from django.db import models
    
    class CustomGroup(models.Model):
            """
            Overwrites original Django Group.
            """
            def __str__(self):
                return "{}".format(self.group.name)
    
            group = models.OneToOneField('auth.Group', unique=True)
            email_alias = models.EmailField(max_length=70, blank=True, default="")
    

    In auth_custom/admin.py:

    from django.contrib.auth.admin import GroupAdmin as BaseGroupAdmin
    from django.contrib.auth.models import Group
    
    
    class GroupInline(admin.StackedInline):
        model = CustomGroup
        can_delete = False
        verbose_name_plural = 'custom groups'
    
    
    class GroupAdmin(BaseGroupAdmin):
        inlines = (GroupInline, )
    
    
    # Re-register GroupAdmin
    admin.site.unregister(Group)
    admin.site.register(Group, GroupAdmin)
    

    After making migrations I have such result in Django Admin view.

    Custom Group in Django Admin

    In order to access this custom field you must type:

    from django.contrib.auth.models import Group
    
    
        group = Group.objects.get(name="Admins")  # example name
    
        email_alias = group.customgroup.email_alias
    

    If any mistakes please notify me, I'll correct this answere.

    0 讨论(0)
  • 2020-12-01 02:39

    I managed to use migrations with @Semprini aswer.

    So i needed to create a company related field in my groups related field, so in my models i did this:

    if not hasattr(Group, 'company'):
        field = models.ForeignKey(Company, on_delete=models.DO_NOTHING, null=True)
        field.contribute_to_class(Group, 'company')
    
    
    class Group(Group):
    
        class Meta:
            proxy = True
    

    Then i run manage.py makemigrations. This created 2 files. One with dependencies on the other, but the first one belonging to the auth app was created inside my virtual enviroment. The files look like this:

    # Generated by Django 2.2.5 on 2019-10-08 16:00
    
    from django.db import migrations, models
    import django.db.models.deletion
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('myapp', '0013_guestuser_permissions_20190919_1715'),
            ('auth', '0011_update_proxy_permissions'),
        ]
    
        operations = [
            migrations.AddField(
                model_name='group',
                name='company',
                field=models.ForeignKey(
                    null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='myapp.Company'),
            ),
        ]
    

    The second one created in myapp migrations folder look like this:

    # Generated by Django 2.2.5 on 2019-10-08 16:00
    
    import django.contrib.auth.models
    from django.db import migrations
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('auth', '0012_group_company_20191008'),
            ('myapp', '0013_guestuser_permissions_20190919_1715'),
        ]
    
        operations = [
            migrations.CreateModel(
                name='Group',
                fields=[
                ],
                options={
                    'proxy': True,
                    'indexes': [],
                    'constraints': [],
                },
                bases=('auth.group',),
                managers=[
                    ('objects', django.contrib.auth.models.GroupManager()),
                ],
            ),
        ]
    

    So the solution was to move the file created in my virtualenv to myapp migrations folder, before the other one generated with makemigrations, but since the migration is applied to the auth app instead of myapp i have to implement a workaround in the file. So the final file now is:

    # Generated by Django 2.2.5 on 2019-10-08 16:00
    
    from django.db import migrations, models
    import django.db.models.deletion
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('myapp', '0013_guestuser_permissions_20190919_1715'),
            ('auth', '0011_update_proxy_permissions'),
        ]
    
        operations = [
            migrations.AddField(
                model_name='group',
                name='company',
                field=models.ForeignKey(
                    null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='myapp.Company'),
            ),
        ]
    
        def mutate_state(self, project_state, preserve=True):
            """
            This is a workaround that allows to store ``auth``
            migration outside the directory it should be stored.
            """
            app_label = self.app_label
            self.app_label = 'auth'
            state = super(Migration, self).mutate_state(project_state, preserve)
            self.app_label = app_label
            return state
    
        def apply(self, project_state, schema_editor, collect_sql=False):
            """
            Same workaround as described in ``mutate_state`` method.
            """
            app_label = self.app_label
            self.app_label = 'auth'
            state = super(Migration, self).apply(project_state, schema_editor, collect_sql)
            self.app_label = app_label
            return state
    
    

    The mutate an apply methods allow you to migrate to the auth app from myapp migrations.

    In the second file i just change the dependencie to depend on the newly file created:

    # Generated by Django 2.2.5 on 2019-10-08 16:00
    
    import django.contrib.auth.models
    from django.db import migrations
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('myapp', '0014_group_company_20191008'),
            ('myapp', '0013_guestuser_permissions_20190919_1715'),
        ]
    
        operations = [
            migrations.CreateModel(
                name='Group',
                fields=[
                ],
                options={
                    'proxy': True,
                    'indexes': [],
                    'constraints': [],
                },
                bases=('auth.group',),
                managers=[
                    ('objects', django.contrib.auth.models.GroupManager()),
                ],
            ),
        ]
    
    
    0 讨论(0)
提交回复
热议问题