Подтвердить что ты не робот

Как расширить модель Django Group?

Есть ли способ расширить встроенный объект 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()

Существует ли какой-либо эквивалент этого подхода для расширения группы? Если нет, есть ли альтернативный подход, который я могу взять?

4b9b3361

Ответ 1

Вы можете создать модель, которая подклассифицирует группу, добавить свои собственные поля и использовать диспетчер моделей для возврата любых настраиваемых запросов. Здесь показан усеченный пример, показывающий, как я расширил группу для представления семейств, связанных со школой:

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

Ответ 2

Если вы просто подклассифицируете объект 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

Ответ 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.

Пользовательская группа в Django Admin

Чтобы получить доступ к этому настраиваемому полю, вы должны ввести:

from django.contrib.auth.models import Group


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

    email_alias = group.customgroup.email_alias

Если есть ошибки, пожалуйста, сообщите мне, я исправлю этот ответ.

Ответ 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

Затем я запускаю make.migrations. Это создало 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 позволяют выполнять миграцию в приложение 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()),
            ],
        ),
    ]