В Django ModelAdmin мне нужно отображать формы, настроенные в соответствии с разрешениями пользователя. Есть ли способ получить текущий объект пользователя в класс формы, чтобы я мог настроить форму в методе __init__
?
Я думаю, что сохранение текущего запроса в локальном потоке было бы возможным, но это было бы моим последним приложением, я думаю, что это плохой дизайн.
Django: как получить текущего пользователя в админ-формах
Ответ 1
Вот что я недавно сделал для блога:
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
)
Ответ 2
Ответ 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
Ответ 3
Я думаю, что нашел решение, которое работает для меня: для создания ModelForm
Django использует метод admin 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
Ответ 4
наткнулся на одно и то же, и это был первый результат 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
Ответ 5
Другой способ решить эту проблему - использовать Django currying, который немного чище, чем просто привязать объект запроса к модели формы.
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)
Это добавило преимущества, приведя ваш метод init к вашей форме немного более ясно, поскольку другие поймут, что он передается как объект kwarg, а не только случайно привязанный атрибут к объекту класса до его инициализации.
class BlogPostForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.current_user = kwargs.pop('current_user')
super(BlogPostForm, self).__init__(*args, **kwargs)
Ответ 6
Этот пример использования документирован на 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)