web-dev-qa-db-ja.com

Django:管理フォームで現在のユーザーを取得する方法

DjangoのModelAdminでは、ユーザーの権限に応じてカスタマイズされたフォームを表示する必要があります。 __init__メソッドでフォームをカスタマイズできるように、現在のユーザーオブジェクトをフォームクラスに入れる方法はありますか?
現在のリクエストをローカルのスレッドに保存することは可能だと思いますが、これは悪いデザインアプローチだと思っている私の最後の手段です。

47

これが私が最近ブログのためにしたことです:

class BlogPostAdmin(admin.ModelAdmin):
    form = BlogPostForm

    def get_form(self, request, **kwargs):
         form = super(BlogPostAdmin, self).get_form(request, **kwargs)
         form.current_user = request.user
         return form

forms.ModelFormにアクセスして、self.current_userの現在のユーザーにアクセスできるようになりました

編集:これは古い回答です。最近見てみると、get_formメソッドを次のように修正する必要があることに気付きました。

    def get_form(self, request, *args, **kwargs):
         form = super(BlogPostAdmin, self).get_form(request, *args, **kwargs)
         form.current_user = request.user
         return form

*argsの追加に注意してください)

53
Joshmaker

Joshmakerの回答がDjango 1.7で機能しません。Django 1.7で私がしなければならないことは次のとおりです:

class BlogPostAdmin(admin.ModelAdmin):
    form = BlogPostForm

    def get_form(self, request, obj=None, **kwargs):
        form = super(BlogPostAdmin, self).get_form(request, obj, **kwargs)
        form.current_user = request.user
        return form

このメソッドの詳細については、 これに関連するDjangoドキュメント を参照してください。

21
sid-kap

私はうまくいく解決策を見つけたと思います:ModelForm Djangoを作成するには、管理者のformfield_for_db_field-メソッドをコールバックとして使用します。
私は私の管理でこのメソッドを上書きし、現在のユーザーオブジェクトをすべてのフィールドの属性として渡します(おそらく最も効率的ではありませんが、threadlocalsを使用するよりもきれいに見えます:

    def formfield_for_dbfield(self, db_field, **kwargs):
        field = super(MyAdmin, self).formfield_for_dbfield(db_field, **kwargs)
        field.user = kwargs.get('request', None).user
        return field

これで、__init__の形式で現在のユーザーオブジェクトにアクセスできます。

    current_user=self.fields['fieldname'].user
5

この使用例は ModelAdmin.get_form に文書化されています

[...]スーパーユーザーに追加のフィールドを提供したい場合は、次のように別の基本フォームにスワップできます。

class MyModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        if request.user.is_superuser:
            kwargs['form'] = MySuperuserForm
        return super().get_form(request, obj, **kwargs)

フィールドを保存する必要があるだけの場合は、 ModelAdmin.save_model をオーバーライドできます。

from Django.contrib import admin

class ArticleAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.user = request.user
        super().save_model(request, obj, form, change)
4
ptim

この問題を解決するもう1つの方法は、Django=カリー化を使用することです。これは、リクエストオブジェクトをフォームモデルに添付するよりも少しクリーンです。

from Django.utils.functional import curry

class BlogPostAdmin(admin.ModelAdmin):
    form = BlogPostForm

    def get_form(self, request, **kwargs):
        form = super(BlogPostAdmin, self).get_form(request, **kwargs)
        return curry(form, current_user=request.user)

これには、初期化前にクラスオブジェクトにランダムにアタッチされた属性ではなくkwargとして渡されていることが他の人に理解されるため、フォームのinitメソッドをもう少し明確にするという追加の利点があります。

class BlogPostForm(forms.ModelForm):

   def __init__(self, *args, **kwargs):
       self.current_user = kwargs.pop('current_user')
       super(BlogPostForm, self).__init__(*args, **kwargs)
3
Cody

同じことを偶然見つけ、これは私のページで最初のgoogleの結果でした。

これが私にとってはどのように機能するかです(Django 1.7+):

class SomeAdmin(admin.ModelAdmin):
    # This is important to have because this provides the
    # "request" object to "clean" method
    def get_form(self, request, obj=None, **kwargs):
        form = super(SomeAdmin, self).get_form(request, obj=obj, **kwargs)
        form.request = request
        return form

class SomeAdminForm(forms.ModelForm):
    class Meta(object):
        model = SomeModel
        fields = ["A", "B"]

    def clean(self):
        cleaned_data = super(SomeAdminForm, self).clean()
        logged_in_email = self.request.user.email #voila
        if logged_in_email in ['[email protected]']:
            raise ValidationError("Please behave, you are not authorised.....Thank you!!")
        return cleaned_data
2
NoobEditor