0

Django のデフォルト認証システム (django.contrib.auth) を使用しています。Django 管理者が操作できるように、ユーザーに「ロール」を追加したいと考えています。

例:

  • ユーザーは、スタッフ教師生徒、および/または親になることができます
  • ユーザーにロールが割り当てられている場合、ユーザーは権限を取得します (たとえば、スタッフメンバーは Django 管理者にサインインできます) 。
  • 一部のロールには追加のフィールドがある場合があります (たとえば、は少なくとも 1 人の生徒と関係があり、各生徒はクラスグループのフィールドを持っています)。
  • すべてのロールに追加のフィールドがあるわけではありません
  • 保護者は教師またはスタッフになることができ、その逆も可能です
  • 学生は別の役割を持つことはできません

モデル内で上記を達成するためのあらゆる種類の (従来の) 方法があります。Django はそれらの多くをサポートしていますが、Django 管理者はサポートしていません。Django admin には多くの優れた機能があるので、それを使用したいと思います (しかし、それが不可能になるのではないかとますます恐れています)。

最初に考えたのは次のモデルです。

class ExtendedUser(contrib.auth.models.User):
    """
       For the ease of use I inherit from User. I might
       want to add methods later
    """
    pass

class StaffMember(models.Model):
    """
       A staffmember is a co-worker of the organisation
       and has permissions to make changes to (parts of)
       the system.

       For now the staffmember only has methods
    """
    user = models.OneToOneField(ExtendedUser, related_name="staff_member")

class Student(models.Model):
    """
      A student can participate in some courses
    """
    user = models.OneToOneField(ExtendedUser, related_name="student")

class Teacher(models.Model):
   user = models.OneToOneField(ExtendedUser, related_name="teacher")
   subjects = models.ManyToManyField(..)

class Parent(models.Model):
    user = models.OneToOneField(ExtendedUser, related_name="parent")
    children = models.ManyToManyField(Student, related_name=parents")

これは Django (および他の多くの MVC ベースのフレームワーク) で機能します。しかし、管理画面で上記を表示する適切な方法が見つかりません。

理想的には、ユーザーを追加してから、ユーザー変更ビュー内にさまざまな役割を追加したいと考えています。最初は、インラインを使用できると思いました:

class StudentInlineAdmin(admin.StackedInline):
    model = Student
    extra = 0
    template = 'accounts/admin/role.html'

次に、インライン テンプレートに若干の変更を加えて、編集ユーザー ボタンに「学生ロールの追加」というキャプションを表示します。ボタンをクリックすると、フォームが表示され、ユーザー ロールが追加されます。理想的ではありませんが、機能します。

残念ながら、Staffmembers にはインライン フォームに追加するフィールドがありません。この方法では、インライン フォームの「has_changed」プロパティをトリガーすることはできません。これにより、新しい役割がデータベースに保存されません。

この最後の問題を解決するために、私は少しハックして空のユーザーロールに「ダミー」フォームフィールドを追加し、JS を使用してこのフィールドを非表示にしました。これにより、has_changed がトリガーされました。

それでも、後でいくつかのテスト中にインラインモデルが保存されない場合、これはうまくいきません。

だから私はそれを間違った方法でやっているだけだと思います。私は多くのグーグルを行い、多くの人が同じ種類の問題に悩まされていることを発見しました. 私の状況に最も適していたのはhttp://www.mail-archive.com/django-users@googlegroups.com/msg52867.htmlでした。しかし、それでもこのソリューションでは、管理者を簡単に実装する方法はありません。

組み込みのグループを使用することも考えましたが、その場合、さまざまなフィールドを追加する方法がわかりません。

私が考えたもう1つのことは、ユーザーを追加して彼に役割を割り当てる代わりに、「学生を追加」しようとすることでした。ユーザーを継承するだけの場合、これは管理者で非常にうまく機能します。

class StudentUser(auth.models.User):
  pass

しかし、ここで 2 つの問題があります。最初はスタッフや教師になることはできません。2 つ目は、Django の残りの部分では、リクエスト オブジェクトが User オブジェクトを返し、そのために Student、Parent、Staffmember オブジェクトをリクエストすることが実際には機能していません。これらのいずれかを取得する唯一の方法は、User オブジェクトに基づいて新しい Student オブジェクトをインスタンス化することです。

Django と Django admin で機能するようにユーザーにロールを追加するには、どのタイプのモデル設計を使用する必要がありますか?

よろしく、 Wout

4

1 に答える 1

2

django.contrib.admin以下では、管理者を変更したり、必要に応じてコピーを作成してハッキングしたりしたくないと想定しています。

ユーザーは、スタッフ、教師、学生、および/または親になることができます

これをユーザー プロファイルに保存できます。from の継承Userも機能しますが、 を使用する代わりに、 fromをUser.get_profile()に手動でマッピングする必要があります。UserExtendedUser

ユーザーにロールが割り当てられている場合、ユーザーは権限を取得します (たとえば、スタッフは Django 管理者にサインインできます)。

その特定のケースでは、ロールベースの自動割り当てを使用できません。ユーザーが管理者にアクセスできるかどうかは、レコードのis_staffフィールドによって決まります。User

私が考えることができる最も自動的な方法は、「権限の更新」管理コマンドis_staffを作成することです。これは、ユーザーのプロファイルに設定された役割に基づいて、権限などの管理フィールドを更新します。ところで、これは完全に「自動」ではありませんが、パフォーマンスを向上させることができる非正規化です。

一部のロールには追加のフィールドがある場合があります (たとえば、親は少なくとも 1 人の生徒と関係があり、各生徒はクラスグループのフィールドを持っています)。

すべてのロールに追加のフィールドがあるわけではありません

保護者は教師またはスタッフになることができ、その逆も可能です

学生は別の役割を持つことはできません

フォームの検証を読んでください。ここで、これらのルールを適用できます。

モデルでは、1 対 1 フィールドの関連する名前を変更することをお勧めします。

class StaffMember(models.Model):
    user = models.OneToOneField(ExtendedUser, related_name="as_staff_member")

class Student(models.Model):
    user = models.OneToOneField(ExtendedUser, related_name="as_student")

class Teacher(models.Model):
    user = models.OneToOneField(ExtendedUser, related_name="as_teacher")

class Parent(models.Model):
    user = models.OneToOneField(ExtendedUser, related_name="as_parent")

sinceは(「ユーザーの先生」と読みます)theUser.as_teacherよりもはるかに明確です。theUser.teacher

これは Django (および他の多くの MVC ベースのフレームワーク) で機能します。しかし、管理画面で上記を表示する適切な方法が見つかりません。

ロールごとに管理者に 1 つのテーブルを作成します。「ロールを変更すると、編集ページの下半分が再描画される」機能はありません。それが必要な場合は、独自の管理者を作成する必要があります。

Django の管理者は素晴らしいですが、すべての人にすべてを提供しようとしているわけではありません。私はあなたのような役割ベースのセットアップを持っています (役割自体がテーブルに保存されていることを除いて)。一般的な考え方は、管理者が十分でない場合は、独自のビューを作成する必要があるということです。

組み込みのグループを使用することも考えましたが、その場合、さまざまなフィールドを追加する方法がわかりません。

組み込みのグループは、探しているものではありません。

私が考えたもう1つのことは、ユーザーを追加して彼に役割を割り当てる代わりに、「学生を追加」しようとすることでした。[...] 最初はスタッフや教師になることはできません。

「サブクラス化」は、より限定的な 1 対 1 です。初期モデルの方が良いと思います。

2 つ目は、Django の残りの部分では、リクエスト オブジェクトが User オブジェクトを返し、そのオブジェクトに対して Student、Parent、Staffmember オブジェクトをリクエストすることが実際には機能していません。これらのいずれかを取得する唯一の方法は、User オブジェクトに基づいて新しい Student オブジェクトをインスタンス化することです。

いいえ、代わりに、オブジェクトからStudent自動生成されたを使用してオブジェクトを見つけます。idUser

try:
   theStudent = Student.objects.get(user_ptr_id=theUser.id)
except Student.DoesNotExist:
   # That user isn't a student; deal with it here.

管理者を使用する場合は、ExtendedUserを追加してから、Studentまたはそれらのエントリを追加するという 2 段階のプロセスを実行する必要があると思います。

つまり、組み込みの admin を使用するか、独自のユーザー管理ビューを作成するという、少し余分な作業が必要になります。どのルートが最適かは、このインターフェイスがどれだけ使用されるかによって異なります。多くの人が日常的に使用する場合は、独自のビューを作成して処理する必要があります。

于 2010-11-27T13:26:37.327 に答える