Я пытаюсь request.user получить чистый метод формы, но как мне получить доступ к объекту запроса? Могу ли я изменить чистый метод, чтобы разрешить ввод переменных?
Ответы:
Ответ Бера - хранить его в threadlocals - очень плохая идея. Нет абсолютно никаких причин для этого.
Гораздо лучший способ, чтобы переопределить форму по __init__
методу взять дополнительный аргумент ключевого слова, request
. Это сохраняет запрос в той форме , в которой он требуется, и откуда вы можете получить к нему доступ в своем чистом методе.
class MyForm(forms.Form):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyForm, self).__init__(*args, **kwargs)
def clean(self):
... access the request object via self.request ...
и на ваш взгляд:
myform = MyForm(request.POST, request=request)
ОБНОВЛЕНО 25.10.2011 : теперь я использую это с динамически созданным классом вместо метода, поскольку в противном случае Django 1.3 отображает некоторую странность.
class MyModelAdmin(admin.ModelAdmin):
form = MyCustomForm
def get_form(self, request, obj=None, **kwargs):
ModelForm = super(MyModelAdmin, self).get_form(request, obj, **kwargs)
class ModelFormWithRequest(ModelForm):
def __new__(cls, *args, **kwargs):
kwargs['request'] = request
return ModelForm(*args, **kwargs)
return ModelFormWithRequest
Затем переопределите MyCustomForm.__init__
следующим образом:
class MyCustomForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyCustomForm, self).__init__(*args, **kwargs)
Затем вы можете получить доступ к объекту запроса из любого метода ModelForm
with self.request
.
__new__
kwargs, который позже будет передан __init__
методу класса . ModelFormWithRequest
Я думаю, что название класса гораздо понятнее по значению, чем ModelFormMetaClass
.
Как бы то ни было, если вы используете представления на основе классов , вместо представлений на основе функций, переопределите get_form_kwargs
в представлении редактирования. Пример кода для настраиваемого CreateView :
from braces.views import LoginRequiredMixin
class MyModelCreateView(LoginRequiredMixin, CreateView):
template_name = 'example/create.html'
model = MyModel
form_class = MyModelForm
success_message = "%(my_object)s added to your site."
def get_form_kwargs(self):
kw = super(MyModelCreateView, self).get_form_kwargs()
kw['request'] = self.request # the trick!
return kw
def form_valid(self):
# do something
Приведенный выше код представления будет request
доступен в качестве одного из аргументов ключевого слова __init__
функции конструктора формы . Поэтому в вашем деле ModelForm
:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
def __init__(self, *args, **kwargs):
# important to "pop" added kwarg before call to parent's constructor
self.request = kwargs.pop('request')
super(MyModelForm, self).__init__(*args, **kwargs)
request
объекта внутри get_form_kwargs
.
self.get_object
? CreateView
Расширяет SingleObjectMixin
. Но работает ли это или вызывает исключение, зависит от того, создаете ли вы новый объект или обновляете существующий; т.е. проверить оба случая (и удаление конечно).
Обычный подход - сохранить объект запроса в локальной ссылке потока с использованием промежуточного программного обеспечения. Затем вы можете получить к нему доступ из любого места вашего приложения, включая метод Form.clean ().
Изменение подписи метода Form.clean () означает, что у вас есть собственная модифицированная версия Django, которая может быть не той, которую вы хотите.
Количество благодарностей промежуточного программного обеспечения выглядит примерно так:
import threading
_thread_locals = threading.local()
def get_current_request():
return getattr(_thread_locals, 'request', None)
class ThreadLocals(object):
"""
Middleware that gets various objects from the
request object and saves them in thread local storage.
"""
def process_request(self, request):
_thread_locals.request = request
Зарегистрируйте это промежуточное ПО, как описано в документации Django.
**kwargs
, это означает, что вам нужно будет передать объект запроса как MyForm(request.POST, request=request)
.
Для администратора Django в Django 1.8
class MyModelAdmin(admin.ModelAdmin):
...
form = RedirectForm
def get_form(self, request, obj=None, **kwargs):
form = super(MyModelAdmin, self).get_form(request, obj=obj, **kwargs)
form.request = request
return form
Я столкнулся с этой конкретной проблемой при настройке админа. Я хотел, чтобы определенное поле было проверено на основе учетных данных конкретного администратора.
Поскольку я не хотел изменять представление, чтобы передать запрос в качестве аргумента формы, я сделал следующее:
class MyCustomForm(forms.ModelForm):
class Meta:
model = MyModel
def clean(self):
# make use of self.request here
class MyModelAdmin(admin.ModelAdmin):
form = MyCustomForm
def get_form(self, request, obj=None, **kwargs):
ModelForm = super(MyModelAdmin, self).get_form(request, obj=obj, **kwargs)
def form_wrapper(*args, **kwargs):
a = ModelForm(*args, **kwargs)
a.request = request
return a
return form_wrapper
obj=obj
нет obj=None
в строке 11.
'function' object has no attribute 'base_fields'
. Однако более простой (без закрытия) ответ @ François работает плавно.
Вы не всегда можете использовать этот метод (и, вероятно, это плохая практика), но если вы используете форму только в одном представлении, вы можете охватить его внутри самого метода представления.
def my_view(request):
class ResetForm(forms.Form):
password = forms.CharField(required=True, widget=forms.PasswordInput())
def clean_password(self):
data = self.cleaned_data['password']
if not request.user.check_password(data):
raise forms.ValidationError("The password entered does not match your account password.")
return data
if request.method == 'POST':
form = ResetForm(request.POST, request.FILES)
if form.is_valid():
return HttpResponseRedirect("/")
else:
form = ResetForm()
return render_to_response(request, "reset.html")
get_form_class
метода CBV , если знаю, что мне нужно сделать много вещей с запросом. При повторном создании класса могут возникнуть некоторые накладные расходы, но это просто перемещает его из времени импорта во время выполнения.
Ответ Дэниела Розмана по-прежнему остается лучшим. Однако я бы использовал первый позиционный аргумент для запроса вместо аргумента ключевого слова по нескольким причинам:
Наконец, я бы использовал более уникальное имя, чтобы избежать переопределения существующей переменной. Таким образом, Мой модифицированный ответ выглядит так:
class MyForm(forms.Form):
def __init__(self, request, *args, **kwargs):
self._my_request = request
super(MyForm, self).__init__(*args, **kwargs)
def clean(self):
... access the request object via self._my_request ...
свежий сыр от Cheesebaker @ pypi: django-requestprovider
У меня есть еще один ответ на этот вопрос, согласно вашему требованию, вы хотите получить доступ к пользователю с помощью чистого метода формы. Вы можете попробовать это. View.py
person=User.objects.get(id=person_id)
form=MyForm(request.POST,instance=person)
forms.py
def __init__(self,*arg,**kwargs):
self.instance=kwargs.get('instance',None)
if kwargs['instance'] is not None:
del kwargs['instance']
super(Myform, self).__init__(*args, **kwargs)
Теперь вы можете получить доступ к self.instance любым чистым методом в form.py
Если вы хотите получить к нему доступ через «подготовленные» представления классов Django, как будто CreateView
есть небольшая хитрость, которую нужно знать (= официальное решение не работает из коробки). По своему усмотрению CreateView
вам придется добавить такой код:
class MyCreateView(LoginRequiredMixin, CreateView):
form_class = MyOwnForm
template_name = 'my_sample_create.html'
def get_form_kwargs(self):
result = super().get_form_kwargs()
result['request'] = self.request
return result
= короче говоря, это решение для перехода request
к вашей форме с помощью представлений Django Create / Update.