【问题标题】:How do I extend the Django Group model?如何扩展 Django Group 模型?
【发布时间】:2011-01-11 23:15:07
【问题描述】:

有没有办法扩展内置的 Django Group 对象以添加类似于扩展用户对象的方式的附加属性?使用用户对象,您可以执行以下操作:

class UserProfile(models.Model):
    user = models.OneToOneField(User)

并将以下内容添加到 settings.py 文件中

AUTH_PROFILE_MODULE = 'app.UserProfile'

这让你:

profile = User.objects.get(id=1).get_profile()

是否有任何等效于扩展组的方法?如果没有,我可以采取其他方法吗?

【问题讨论】:

    标签: python django django-models


    【解决方案1】:

    如果您只是对 Group 对象进行子类化,那么默认情况下它将创建一个新的数据库表,并且管理站点不会获取任何新字段。

    您需要将新字段注入现有组:

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

    要将方法添加到组,子类但将模型标记为代理:

    class MyGroup(Group):
    
        class Meta:
            proxy = True
    
        def myFunction(self):
            return True
    

    【讨论】:

    • 'if not hasattr(Group...' 行在哪里?
    • 可以放在MyGroup上面的models.py中
    • 这种方法仍然适用于 Django 迁移吗? 1.8 将为注入的字段创建一个迁移,但将其放入重新构建时找不到的 Django pip 文件夹中。
    • @beluga.me 您可以使用MIGRATION_MODULES 移动迁移,这样行吗?
    • 小心这个答案,因为它将迁移文件添加到:django.contrib.auth.migrations。我还没有找到避免这种情况的方法
    【解决方案2】:

    您可以创建一个将 Group 子类化的模型,添加您自己的字段,并使用模型管理器返回您需要的任何自定义查询集。这是一个截断的示例,展示了我如何扩展 Group 以代表与学校相关的家庭:

    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
    

    【讨论】:

    • 虽然如果组模型是从项目开始时创建的,这可能会起作用,但此答案不完整,因为它没有解决现有组数据迁移的重要问题。
    • @RomanKonoval 答案并不完整,因为它回答了所提出的问题。迁移数据是一个完全不同的主题。
    • 如何通过这样的设置访问用户所属的家庭实例?做类似的事情,但 user.groups 只获取 Group 实例。我希望能够做类似 user.families 的事情。 Django 是否默认设置了相关名称以从用户访问家庭?
    【解决方案3】:

    对我来说,解决方案基于:

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

    让我解释一下我对使用电子邮件别名扩展默认模型的群组做了什么:

    首先我创建了我自己的 django 应用程序并命名它

    python manage.py startapp auth_custom

    代码部分:

    auth_custom/models.py 我创建了对象 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="")
    

    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)
    

    进行迁移后,我在 Django Admin 视图中得到了这样的结果。

    Custom Group in Django Admin

    要访问此自定义字段,您必须键入:

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

    如果有任何错误请通知我,我会更正这个答案。

    【讨论】:

    • 对我不起作用,从 django 管理界面添加组时出错。 TypeError at /admin/staff/customgroup/add/ __str__ returned non-string (type Group)
    • 我建议您将所有内容复制到单独的auth_custom/ 目录中,如我所示,然后验证是否仍然出现错误。我想您的文件层次结构不同,并且可能会遗漏更多内容。抱歉回复晚了,我不是经常来这里。
    • 已经一个月了,谢谢回复。我猜我已经通过其他方法修复了它。现在不记得了...!
    • 我如何在视图中创建实例?
    【解决方案4】:

    我设法通过@Semprini aswer 使用迁移。

    所以我需要在我的组相关字段中创建一个公司相关字段,所以在我的模型中我这样做了:

    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
    

    然后我运行 manage.py makemigrations。这创建了 2 个文件。一个依赖于另一个,但属于auth 应用程序的第一个是在我的虚拟环境中创建的。文件如下所示:

    # 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'),
            ),
        ]
    

    在 myapp 迁移文件夹中创建的第二个如下所示:

    # 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()),
                ],
            ),
        ]
    

    因此解决方案是将在我的 virtualenv 中创建的文件移动到 myapp 迁移文件夹,然后再使用 makemigrations 生成另一个文件,但由于迁移应用于 auth 应用程序而不是 myapp 我必须实现一个文件中的解决方法。所以现在的最终文件是:

    # 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
    
    

    mutate 和 apply 方法允许您从 myapp 迁移迁移到 auth 应用程序。

    在第二个文件中,我只是将依赖项更改为依赖于新创建的文件:

    # 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()),
                ],
            ),
        ]
    
    

    【讨论】:

    • class Group(Group):哦!男人
    猜你喜欢
    • 1970-01-01
    • 2014-12-19
    • 1970-01-01
    • 2020-11-29
    • 2020-05-20
    • 1970-01-01
    • 2013-12-23
    • 2016-10-12
    • 2011-02-28
    相关资源
    最近更新 更多