DjangoのModelAdminでは、ユーザーの権限に応じてカスタマイズされたフォームを表示する必要があります。 __init__
メソッドでフォームをカスタマイズできるように、現在のユーザーオブジェクトをフォームクラスに入れる方法はありますか?
現在のリクエストをローカルのスレッドに保存することは可能だと思いますが、これは悪いデザインアプローチだと思っている私の最後の手段です。
これが私が最近ブログのためにしたことです:
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
の追加に注意してください)
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ドキュメント を参照してください。
私はうまくいく解決策を見つけたと思います: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
この使用例は 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)
この問題を解決するもう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)
同じことを偶然見つけ、これは私のページで最初の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