web-dev-qa-db-ja.com

Djangoグループモデルを拡張するにはどうすればよいですか?

組み込みのDjangoグループオブジェクトを拡張して、ユーザーオブジェクトを拡張できる方法と同様の属性を追加する方法はありますか?ユーザーオブジェクトを使用すると、次のことができます。

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

以下をsettings.pyファイルに追加します

AUTH_PROFILE_MODULE = 'app.UserProfile'

あなたを得る:

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

グループを拡張するためのこのアプローチに相当するものはありますか?そうでない場合、私が取ることができる代替アプローチはありますか?

41
Steve Platz

Groupをサブクラス化するモデルを作成し、独自のフィールドを追加し、Model Managerを使用して必要なカスタムクエリセットを返すことができます。以下は、グループを拡張して、学校に関連付けられた家族を表す方法を示す省略された例です。

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
25
shacker

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
52
Semprini

私のために基づいて解決策を働いた:

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

メールエイリアスでデフォルトモデルを拡張するグループで行ったことを説明しましょう。

まず、自分でDjangoアプリケーションを作成し、名前を付けます

python manage.py startappauth_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管理者]のカスタムグループ

このカスタムフィールドにアクセスするには、次のように入力する必要があります。

from Django.contrib.auth.models import Group


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

    email_alias = group.customgroup.email_alias

間違いがあればお知らせください。この回答を訂正します。

7
rozacek

@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つのファイルが作成されました。 1つは他に依存関係がありますが、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 migrationsフォルダーに作成された2番目のものは次のようになります。

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

したがって、解決策は、仮想環境で作成されたファイルを、他のファイルがmakemigrationsで生成される前にmyapp migrationsフォルダーに移動することですが、移行は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アプリに移行できます。

2番目のファイルでは、新しく作成したファイルに依存するように依存関係を変更します。

# 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
CardCaptor