मैं किसी फॉर्म की क्लीन () पद्धति में अनुरोध ऑब्जेक्ट या किसी अन्य चर का उपयोग कैसे करूं?


99

मैं एक फॉर्म की स्वच्छ विधि के लिए request.user करने का प्रयास कर रहा हूं, लेकिन मैं अनुरोध ऑब्जेक्ट तक कैसे पहुंच सकता हूं? क्या मैं चर इनपुट की अनुमति देने के लिए स्वच्छ विधि को संशोधित कर सकता हूं?

जवाबों:


157

बेर द्वारा उत्तर - इसे थ्रेडोकोल्स में संग्रहीत करना - एक बहुत बुरा विचार है। इस तरह से ऐसा करने का कोई कारण नहीं है।

__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)

4
आप इस मामले में सही हैं। हालाँकि, यह संशोधित रूप / दृश्य में वांछित नहीं हो सकता है। इसके अलावा, थ्रेड लोकल स्टोर के लिए उपयोग के मामले हैं जहां विधि पैरामीटर या उदाहरण के चर जोड़ना असंभव है। डेटा को अनुरोध करने के लिए पहुँच की आवश्यकता वाले क्वेरी फ़िल्टर के लिए कॉल करने योग्य तर्क के बारे में सोचें। आप न तो कॉल में कोई पैरामीटर जोड़ सकते हैं, न ही संदर्भ के लिए कोई उदाहरण है।
बेर

4
यह तब उपयोगी नहीं होता है जब आप किसी व्यवस्थापक प्रपत्र का विस्तार कर रहे होते हैं, क्योंकि आप अनुरोध फ़ॉर्म को पास करते हुए अपने फ़ॉर्म में प्रवेश कर सकते हैं। कोई उपाय?
मोड़ी

13
आप थ्रेड-लोकल स्टोरेज का उपयोग क्यों करते हैं, यह एक बहुत बुरा विचार है? यह हर जगह अनुरोध को पारित करने के लिए कोड छोड़ने से बचा जाता है।
माइकल माइर

9
मैं अनुरोध ऑब्जेक्ट को फ़ॉर्म में ही पास नहीं करूंगा, बल्कि अनुरोध के फ़ील्ड जिन्हें आपको (यानी उपयोगकर्ता) की आवश्यकता है, अन्यथा आप अनुरोध / प्रतिक्रिया चक्र के लिए अपने फ़ॉर्म तर्क को टाई करते हैं जो कठिन परीक्षण करता है।
एंड्रयू इंग्राम

2
क्रिस प्रैट भी एक अच्छा समाधान है, जब में admin.ModelAdmin रूपों से निपटने के लिए
radtek

34

अद्यतन 10/25/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


1
क्रिस, कि "डी __init __ (स्वयं, अनुरोध = कोई नहीं, * आर्ग्स, ** kwargs)" खराब है, क्योंकि यह पहली स्थिति वाले arg और kwargs दोनों में अनुरोध के साथ समाप्त होगा। मैंने इसे "__init __" (स्वयं, * args, ** kwargs) में बदल दिया और यह काम करता है।
slinkp

1
ओह। वह मेरी तरफ से सिर्फ एक गलती थी। जब मैंने दूसरा अपडेट किया तो मैंने कोड के उस हिस्से को अपडेट करने की उपेक्षा की। पकड़ने के लिए धन्यवाद। अपडेट किया गया।
क्रिस प्रैट

4
क्या यह वास्तव में एक रूपक है? मुझे लगता है कि यह सिर्फ सामान्य ओवरराइडिंग है, आप अनुरोधों को जोड़ते हैं __new__जो बाद में कक्षा की __init__विधि में पारित हो जाएगा । वर्ग का नामकरण ModelFormWithRequestमुझे लगता है कि इसमें बहुत स्पष्ट है ModelFormMetaClass
k4ml

2
यह एक मेटाक्लस नहीं है! देखें stackoverflow.com/questions/100003/…
frnhr

32

यदि आप क्लास बेस्ड व्यूज का उपयोग कर रहे हैं, तो फंक्शन बेस्ड व्यूज के बजाय, यह 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)

1
इसने मेरे लिए काम किया। मैं नोट बनाता हूं क्योंकि मैं जटिल विज़ार्डफॉर्म लॉजिक के कारण वैसे भी get_form_kwargs का उपयोग कर रहा था। कोई अन्य उत्तर नहीं मैंने देखा है कि विजार्डफार्म के लिए जिम्मेदार है।
डेटाकिड

2
क्या मेरे अलावा किसी को भी लगता है कि यह एक बड़ी गड़बड़ है जो एक वेब फ्रेमवर्क के लिए बहुत अल्पविकसित है? Django बहुत अच्छा है, लेकिन यह मुझे कभी भी CBV का उपयोग नहीं करना चाहता है।
trpt4him

1
सीबीएचओ के लाभ अब तक एफबीवी की कमियों को दूर करते हैं, खासकर यदि आप 25+ डेस राइटिंग कोड के साथ एक बड़े प्रोजेक्ट पर काम करते हैं जिसका उद्देश्य 100% यूनिट टेस्ट कवरेज है। सुनिश्चित नहीं है कि Django के नए संस्करण स्वचालित रूप से requestऑब्जेक्ट होने के लिए पूरा करते हैं get_form_kwargs
जोसेफ विक्टर ज़मीत जूल

समान नस में, क्या get_form_kwargs में ऑब्जेक्ट इंस्टेंस की आईडी तक पहुंचने का कोई तरीका है?
हसन बेग

1
@HassanBaig संभवतः उपयोग कर रहे हैं self.get_object? CreateViewफैली हुई है SingleObjectMixin। लेकिन क्या यह काम करता है या एक अपवाद उठाता है, इस पर निर्भर करता है कि आप एक नई वस्तु बना रहे हैं या किसी मौजूदा को अपडेट कर रहे हैं; यानी दोनों मामलों का परीक्षण करें (और पाठ्यक्रम को हटाने)।
जोसेफ विक्टर ज़मीत

17

सामान्य aproach एक थ्रेडवेयर का उपयोग करके थ्रेड-स्थानीय संदर्भ में अनुरोध ऑब्जेक्ट को संग्रहीत करना है। फिर आप इसे आप एप में कहीं से भी एक्सेस कर सकते हैं, जिसमें फॉर्म.क्लाइन () विधि भी शामिल है।

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 डॉक्स में बताए अनुसार रजिस्टर करें


2
उपरोक्त टिप्पणियों के बावजूद, यह विधि काम करती है जबकि दूसरी विधि नहीं है। Init में फॉर्म ऑब्जेक्ट की एक विशेषता सेट करना मज़बूती से स्वच्छ तरीकों पर नहीं ले जाता है, जबकि थ्रेड लोकल सेट करना इस डेटा को ले जाने की अनुमति देता है।
rplevy

4
जब आप प्रपत्र का एक उदाहरण बनाते हैं तो @rplevy ने वास्तव में अनुरोध ऑब्जेक्ट पास किया है? यदि आपने ध्यान नहीं दिया है, तो यह कीवर्ड तर्कों का उपयोग करता है **kwargs, जिसका अर्थ है कि आपको अनुरोध ऑब्जेक्ट को पास करना होगा MyForm(request.POST, request=request)
अनकोड

13

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

1
वास्तव में ऊपर दी गई शीर्ष-रेटेड विधि वास्तव में Django 1.6 और 1.9 के बीच कहीं काम करना बंद कर देती है। यह काम करता है और बहुत छोटा है। धन्यवाद!
रायक २

9

मैं व्यवस्थापक को अनुकूलित करते समय इस विशेष समस्या में भाग गया। मैं चाहता था कि एक विशेष क्षेत्र को विशेष व्यवस्थापक की साख के आधार पर मान्य किया जाए।

चूँकि मैं फॉर्म के लिए एक तर्क के रूप में अनुरोध पारित करने के लिए दृश्य को संशोधित नहीं करना चाहता था, इसलिए मैंने जो किया वह निम्न है:

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

उसके लिए धन्यवाद। त्वरित टाइपो: लाइन 11 पर obj=objनहींobj=None
फ्रैंकोइस कॉन्स्टेंट

वास्तव में अच्छा जवाब, मुझे यह पसंद है!
ल्यूक डुपिन

Django 1.9 उद्धार 'function' object has no attribute 'base_fields':। हालांकि, सरल (बिना बंद किए) @ फ्रांस्वा जवाब सुचारू रूप से काम करता है।
रतिरु ११'१६

5

आप हमेशा इस विधि का उपयोग नहीं कर सकते (और शायद इसका बुरा अभ्यास), लेकिन यदि आप केवल एक दृश्य में फ़ॉर्म का उपयोग कर रहे हैं, तो आप इसे दृश्य पद्धति के अंदर ही ले जा सकते हैं।

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पद्धति में ऐसा करता हूं, अगर मुझे पता है कि मुझे अनुरोध के साथ बहुत सारे सामान करने की आवश्यकता है। बार-बार क्लास बनाने में कुछ ओवरहेड हो सकता है, लेकिन यह सिर्फ इम्पोर्ट टाइम से लेकर रन-टाइम तक चलता है।
मैथ्यू Schinckel

5

द्वारा जवाब डैनियल रोज़मैन का अभी भी सबसे अच्छा है। हालाँकि, मैं कुछ कारणों से कीवर्ड तर्क के बजाय अनुरोध के लिए पहले स्थितीय तर्क का उपयोग करूंगा:

  1. आप एक ही नाम के साथ एक क्वार को ओवरराइड करने का जोखिम नहीं उठाते हैं
  2. अनुरोध वैकल्पिक है जो सही नहीं है। अनुरोध विशेषता कभी भी इस संदर्भ में नहीं होनी चाहिए।
  3. आप बिना किसी को संशोधित किए बगैर मूल कक्षा में आर्ग और क्वार्ग को साफ कर सकते हैं।

अंत में, मैं एक मौजूदा चर को ओवरराइड करने से बचने के लिए और अधिक अद्वितीय नाम का उपयोग करूंगा। इस प्रकार, मेरा संशोधित जवाब इस तरह दिखता है:

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 ...


3

मेरे पास इस प्रश्न का एक और उत्तर है कि आपकी आवश्यकता के अनुसार आप उपयोगकर्ता को फॉर्म के स्वच्छ तरीके से एक्सेस करना चाहते हैं। आप यह कोशिश कर सकते हैं। 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.in में किसी भी साफ तरीके से self.instance को एक्सेस कर सकते हैं


0

जब आप इसे "तैयार" 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 के बनाएँ / अद्यतन विचारों के साथ अपने फॉर्म को पास करने का उपाय है ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.