回答:
Berによる答え-スレッドローカルに保存することは非常に悪い考えです。このようにする理由はまったくありません。
より良い方法は、フォームの__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)
更新日2011/10/25: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)
その後、ModelFormwithの任意のメソッドからリクエストオブジェクトにアクセスできますself.request。
__new__。後でクラスの__init__メソッドに渡されるのkwargsにリクエストを追加します。クラス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__コンストラクター関数へのキーワード引数の1つとして利用可能になります。したがって、あなたの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の回答はスムーズに機能します。
常にこのメソッドを使用できるわけではありません(そしておそらくその悪い習慣です)が、1つのビューでのみフォームを使用している場合は、viewメソッド自体の中にスコープを設定できます。
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)
これで、form.pyのすべてのクリーンメソッドでself.instanceにアクセスできます。
「準備済み」の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
=つまり、これはrequestDjangoのCreate / Updateビューでフォームに渡すソリューションです。