如何扩展Django Group模型?

Ste*_*atz 39 python django django-models

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

class UserProfile(models.Model):
    user = models.OneToOneField(User)
Run Code Online (Sandbox Code Playgroud)

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

AUTH_PROFILE_MODULE = 'app.UserProfile'
Run Code Online (Sandbox Code Playgroud)

哪个让你:

profile = User.objects.get(id=1).get_profile()
Run Code Online (Sandbox Code Playgroud)

是否有任何相当于扩展组的方法?如果没有,我可以采取另一种方法吗?

Sem*_*ini 47

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

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

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

要向Group添加方法,请将模型标记为代理:

class MyGroup(Group):

    class Meta:
        proxy = True

    def myFunction(self):
        return True
Run Code Online (Sandbox Code Playgroud)

  • 'if not hasattr(Group ...'行去哪儿了? (8认同)
  • 请小心这个答案,因为它将迁移文件添加到:django.contrib.auth.migrations。我还没有找到避免这种情况的方法 (5认同)
  • 这种方法是否仍适用于Django迁移?1.8将为注入的字段创建一个很好的迁移,但是将它放入Django pip文件夹中,在重新构建时找不到它. (4认同)

sha*_*ker 24

您可以创建一个模型,该模型将子类分组,添加您自己的字段,并使用模型管理器返回您需要的任何自定义查询集.这是一个截断的示例,显示我如何扩展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
Run Code Online (Sandbox Code Playgroud)

  • 对于python3,将`__unicode__`替换为`__str__` (3认同)
  • @RomanKonoval 答案并非不完整,因为它回答了所提出的问题。迁移数据是一个完全不同的主题。 (3认同)

Car*_*tor 11

我设法通过@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
Run Code Online (Sandbox Code Playgroud)

然后我运行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'),
        ),
    ]
Run Code Online (Sandbox Code Playgroud)

在 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()),
            ],
        ),
    ]
Run Code Online (Sandbox Code Playgroud)

因此,解决方案是将 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

Run Code Online (Sandbox Code Playgroud)

mutate 和 apply 方法允许您auth从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 = [
        ('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()),
            ],
        ),
    ]

Run Code Online (Sandbox Code Playgroud)

  • `班级组(Group):`哦!男人 (3认同)

roz*_*cek 6

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

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="")
Run Code Online (Sandbox Code Playgroud)

在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)
Run Code Online (Sandbox Code Playgroud)

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

Django Admin中的自定义组

为了访问此自定义字段,您必须输入:

from django.contrib.auth.models import Group


    group = Group.objects.get(name="Admins")  # example name

    email_alias = group.customgroup.email_alias
Run Code Online (Sandbox Code Playgroud)

如果有任何错误,请通知我,我会纠正此答复。