8

django Guardian https://github.com/lukaszb/django-guardianは、オブジェクト レベルのパーミッション アプリとして非常によくできています。私は実際に、さまざまなdjangoプロジェクトで他のかなりの数のdjangoオブジェクトレベルのアクセス許可アプリを読んで使用しました。

私が取り組んでいる最近のプロジェクトでは、django ガーディアンを使用することにしましたが、2 つの可能なアプローチの長所と短所、および SQL クエリのパフォーマンスに対するそれぞれの影響に関するモデル設計の質問があります。

  1. それを使用django.contrib.auth.models.Groupして、カスタム組織アプリのモデルに拡張します。また

  2. 代わりに使用django.contrib.auth.models.Userし、組織アプリの組織タイプごとに m2m フィールドを作成します。

アプローチ #1

# Organisation app's models.py

from django.contrib.auth.models import Group

class StudentClass(models.Model):
    name = models.CharField('Class Name', max_length=255)
    groups = models.ManyToManyField(Group, blank=True)
    size = models.IntegerField('Class Size', blank=True)

class SpecialInterestGroup(models.Model):
    name = models.CharField('Interest Group Name', max_length=255)
    groups = models.ManyToManyField(Group, blank=True)
    description = models.TextField('What our group does!', blank=True)

class TeachingTeam(models.Model):
    name = models.CharField('Teacher Team Name', max_length=255)
    groups = models.ManyToManyField(Group, blank=True)
    specialization = models.TextField('Specialty subject matter', blank=True)

このアプローチでは、ユーザーが初めてグループ (django グループ) に追加されると、グループ オブジェクトが作成され、これら 3 つのクラスのいずれかに割り当てられます。そのグループ オブジェクトがまだ追加されたクラスに属していない場合は、の中へ。

これは、各 StudentClass オブジェクトなどsc_Asc_B多くのグループが含まれる可能性があることを意味します。

つまり、特定のユーザー (たとえばmyuser) が特定の組織に属しているかどうかを確認するには、そのユーザーが属するgroups_myuser_belongto = myuser.groupsすべてのグループを照会し、関連付けられているすべてのグループを照会する必要があります。私が興味を持っている組織は、groups_studentclass = sc_A.groups.all()比較する必要がある 2 つのリストを持っているので、 を実行できますset(groups_myuser_belongto) && set(groups_studentclass)。これにより、交差する 1 つ以上のグループを含む可能性のある新しいセットが返されます。1 つ以上のグループがある場合、myuserは確かに のメンバーですsc_A

したがって、このモデル設計は、ユーザーが組織に属しているかどうかを確認するためだけに、多くの問題 (および追加のクエリ) を実行する必要があることを意味します。

また、m2m をグループに使用している理由は、django ガーディアンが提供するグループ レベルのアクセス許可機能を利用するためです。

そのようなモデル設計は実用的ですか?

それとも、そのような別のモデル設計を使用したほうがよいのでしょうか...

アプローチ #2

# Organisation app's models.py

from django.contrib.auth.models import User

class StudentClass(models.Model):
    name = models.CharField('Class Name', max_length=255)
    users = models.ManyToManyField(User, blank=True)
    size = models.IntegerField('Class Size', blank=True)

class SpecialInterestGroup(models.Model):
    name = models.CharField('Interest Group Name', max_length=255)
    users = models.ManyToManyField(User, blank=True)
    description = models.TextField('What our group does!', blank=True)

class TeachingTeam(models.Model):
    name = models.CharField('Teacher Team Name', max_length=255)
    users = models.ManyToManyField(User, blank=True)
    specialization = models.TextField('Specialty subject matter', blank=True)

明らかに、このモデル設計により、ユーザー オブジェクトが特定の組織に属しているかどうかを簡単に確認できます。ユーザーjohnが TeachingTeam のメンバーであるかどうかを確認するために必要なことは、次のことを確認することだけmaths_teachersです。

user = User.objects.get(username='john')
maths_teachers = TeachingTeam.objects.get(name='Maths teachers')
if user in maths_teachers.users.all():
    print "Yes, this user is in the Maths teachers organization!"

しかし、このモデル設計が意味することは、ユーザー オブジェクトをグループに追加するとき(django ガーディアンのグループ アクセス許可機能を使用したいことを思い出してください)、save()呼び出しによってユーザー オブジェクトが「Maths Teachers」グループに追加されることを確認する必要があるということです。 django.contrib.auth.models.Group ANDをカスタムTeachingTeamクラスの "Maths Teachers" オブジェクトに挿入します。そして、それはあまり DRY ではありません。言うまでもなく、両方のモデルへの保存呼び出しが単一のtransaction.

このユースケース/要件を考慮してモデルを設計するより良い方法はありますか?djangoグループを使用し、djangoのネイティブグループ機能を「拡張」する方法を提供します(「ユーザープロファイルアプリ」でdjangoのユーザーモデルを拡張する方法とほぼ同じです) ?

4

2 に答える 2

8

これに対する私の見解 (django アプリを長い間開発してきた) は、自然なアプローチに固執する必要があるということです (したがって、StudentClass にはグループではなくユーザーが含まれます)。ここで「自然」とは、関連するオブジェクトの実際のセマンティクスに対応することを意味します。

特定の StudentClass に属することが (ユーザーに付与されたものに加えて) 自動グループを意味する必要がある場合は、groupsm2m を StudentClass モデルに追加し、カスタムget_all_permissions(self, user_obj, obj=None)メソッドを提供する新しい認証バックエンドを作成します (デフォルトのものを拡張します)。https://github.com/django/django/blob/master/django/contrib/auth/models.py#L201によってフックされます

このメソッドでは、ユーザーが属する組織に関連付けられたグループを照会します。また、1+N クエリを実行する必要はありません。ORM を正しく使用すると、2 つの *-to-many を一度にナビゲートできます。

https://github.com/django/django/blob/master/django/contrib/auth/backends.py#L37クエリの現在の ModelBackend メソッドはget_group_permissions(user_obj)、ユーザーが割り当てたパーマにそれらを追加します。get_student_class_permission(キャッシュされた)および他の対応するメソッドを追加することにより、同様の動作を追加できます。

(より明確なプロローグのために編集)

于 2012-06-22T14:10:25.683 に答える
0

Obs:一般的なリレーションシップを使用する別のアプローチがあります。このアプローチでは、ユーザー モデル インスタンスが contenttypes フレームワークを介してそのリソースを指すようにします。このアプローチを説明する SE に関する素敵な質問があります。

パフォーマンスについて: JOIN を使用した単一の選択は、多くの単純な選択 ( 123 )よりも安価であるといういくつかの手がかりがあります。この場合、オプション 2 の方が適しています。

ユーザビリティについて: 最初のアプローチは説明が難しく、理解しにくいです。私見はいいえ。2. または、一般的な関係を試してください。

于 2012-06-26T02:01:21.803 に答える