Respostas:
A resposta de Ber - armazená-lo em locais de discussão - é uma ideia muito ruim. Não há absolutamente nenhuma razão para fazer dessa maneira.
Uma maneira muito melhor é sobrescrever o __init__método do formulário para obter um argumento de palavra-chave extra request,. Isso armazena a solicitação no formulário , onde é necessária e de onde você pode acessá-la em seu método de limpeza.
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 ...
e na sua opinião:
myform = MyForm(request.POST, request=request)
ATUALIZADO em 25/10/2011 : Agora estou usando isso com uma classe criada dinamicamente em vez do método, já que o Django 1.3 exibe algumas estranhezas de outra forma.
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
Em seguida, substitua da MyCustomForm.__init__seguinte forma:
class MyCustomForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(MyCustomForm, self).__init__(*args, **kwargs)
Você pode acessar o objeto de solicitação de qualquer método de ModelFormcom self.request.
__new__kwargs de que mais tarde será passada para o __init__método da classe . Nomeando a classe ModelFormWithRequest, acho muito mais claro em seu significado do que ModelFormMetaClass.
Por que vale a pena, se você estiver usando visualizações baseadas em classe , em vez de visualizações baseadas em função, substitua get_form_kwargsem sua visualização de edição. Código de exemplo para um personalizado 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
O código de exibição acima será requestdisponibilizado como um dos argumentos de palavra-chave para a __init__função de construtor do formulário . Portanto, em seu ModelFormfazer:
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)
requestobjeto get_form_kwargsautomaticamente.
self.get_object? O CreateViewestende o SingleObjectMixin. Mas se isso funciona ou gera uma exceção depende se você está criando um novo objeto ou atualizando um existente; ou seja, teste ambos os casos (e exclusão, é claro).
A abordagem usual é armazenar o objeto de solicitação em uma referência de thread local usando um middleware. Em seguida, você pode acessar isso de qualquer lugar em seu aplicativo, incluindo o método Form.clean ().
Mudar a assinatura do método Form.clean () significa que você possui sua própria versão modificada do Django, que pode não ser o que você deseja.
Obrigado, a contagem de middleware parece algo assim:
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
Registre este middleware conforme descrito na documentação do Django
**kwargs, o que significa que você terá que passar o objeto de solicitação como MyForm(request.POST, request=request).
Para Django admin, em 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
Corri para este problema específico ao personalizar o administrador. Eu queria que um determinado campo fosse validado com base nas credenciais do administrador específico.
Como não queria modificar a visualização para passar a solicitação como um argumento para o formulário, fiz o seguinte:
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=objnão está obj=Nonena linha 11.
'function' object has no attribute 'base_fields'. No entanto, a resposta mais simples (sem encerramento) @ François funciona sem problemas.
Você nem sempre pode usar este método (e provavelmente é uma prática ruim), mas se você estiver usando o formulário em apenas uma visão, você pode escopo dentro do próprio método de visão.
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_classmétodo CBV , se sei que preciso fazer muitas coisas com a solicitação. Pode haver alguma sobrecarga na criação repetida da classe, mas isso apenas a move do tempo de importação para o tempo de execução.
A resposta de Daniel Roseman ainda é a melhor. No entanto, eu usaria o primeiro argumento posicional para a solicitação em vez do argumento de palavra-chave por alguns motivos:
Por último, eu usaria um nome mais exclusivo para evitar a substituição de uma variável existente. Assim, Minha resposta modificada se parece com:
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 ...
queijo fresco de cheesebaker @ pypi: django-requestprovider
Eu tenho outra resposta a esta pergunta de acordo com sua exigência de que você deseja acessar o usuário no método limpo do formulário. Você pode tentar isso. 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)
Agora você pode acessar o self.instance em qualquer método limpo em form.py
Quando você deseja acessá-lo por meio de visualizações de classe "preparadas" do Django, como se CreateViewhouvesse um pequeno truque para saber (= a solução oficial não funciona fora da caixa). Por conta própria, CreateView você terá que adicionar um código como este:
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
= resumidamente, esta é a solução para passar requestpara o seu formulário com as visualizações Criar / Atualizar do Django.