Відповіді:
Відповідь Бер - зберігати його в потоці передач - дуже погана ідея. Немає абсолютно ніяких причин робити це так.
Набагато кращий спосіб, щоб перевизначити форму по __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
з 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'
. Однак простіша (без закриття) відповідь @ Франсуа працює безперебійно.
Ви не завжди можете використовувати цей метод (і його, мабуть, погана практика), але якщо ви використовуєте форму лише в одному представленні, ви можете застосувати її всередині самого методу перегляду.
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 ...
свіжий сир від сирника @ pypi: django-requestprovider
У мене є ще одна відповідь на це питання відповідно до вашої вимоги, яку ви бажаєте отримати доступ до користувача в чистому методі форми. Ви можете спробувати це. View.py
person=User.objects.get(id=person_id)
form=MyForm(request.POST,instance=person)
form.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.in вещества будь-яким чистим методом у 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.