कैसे Django पता करने के लिए आदेश प्रपत्र फ़ील्ड्स प्रदान करता है?


91

अगर मेरे पास एक Django रूप है जैसे:

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    message = forms.CharField()
    sender = forms.EmailField()

और मैं इस फॉर्म के उदाहरण के as_table () विधि को कॉल करता हूं, Django फ़ील्ड को उसी आदेश के रूप में प्रस्तुत करेगा जैसा कि ऊपर निर्दिष्ट किया गया है।

मेरा सवाल यह है कि Django को उस वर्ग चर का क्रम कैसे पता है जहां परिभाषित किया गया है?

(इसके अलावा मैं कैसे उदाहरण के लिए इस आदेश को ओवरराइड करते हैं, जब मैं classe के से कोई फ़ील्ड जोड़ना चाहते हैं init विधि?)

जवाबों:


89

[नोट: यह उत्तर अब पूरी तरह से पुराना हो गया है - कृपया नीचे चर्चा देखें, और अधिक हाल के उत्तर]।

यदि fएक रूप है, तो इसके क्षेत्र हैं f.fields, जो कि एक है django.utils.datastructures.SortedDict (यह आइटम उसी क्रम में प्रस्तुत करता है, जो उन्हें जोड़ा जाता है)। प्रपत्र निर्माण के बाद f.fields में एक कीऑडर विशेषता होती है, जो एक सूची होती है जिसमें उन्हें प्रस्तुत किए जाने वाले क्रम में फ़ील्ड के नाम होते हैं। आप इसे सही क्रम में सेट कर सकते हैं (हालांकि आपको यह सुनिश्चित करने के लिए देखभाल करने की आवश्यकता है कि आप आइटम नहीं छोड़ें या अतिरिक्त न जोड़ें)।

यहाँ एक उदाहरण है जो मैंने अभी अपनी वर्तमान परियोजना में बनाया है:

class PrivEdit(ModelForm):
    def __init__(self, *args, **kw):
        super(ModelForm, self).__init__(*args, **kw)
        self.fields.keyOrder = [
            'super_user',
            'all_districts',
            'multi_district',
            'all_schools',
            'manage_users',
            'direct_login',
            'student_detail',
            'license']
    class Meta:
        model = Privilege

20
कुछ समय के लिए, फ़ील्ड्स को एक मॉडलफ़ॉर्म के 'फ़ील्ड्स' विशेषता द्वारा निर्दिष्ट किया जाएगा। से docs.djangoproject.com/en/1.3/topics/forms/modelforms/... जिस क्रम में क्षेत्रों के नाम उस सूची में निर्दिष्ट कर रहे हैं जब प्रपत्र उन्हें renders सम्मान दिया जाता है:। यह केवल मॉडलफ़ॉर्म के लिए काम करता है - आपका दृष्टिकोण अभी भी नियमित रूपों के लिए काफी उपयोगी है, विशेष रूप से उपवर्गों में जो अतिरिक्त क्षेत्रों को जोड़ते हैं।
क्रिस लॉलर

3
यह तब काम करता है जब आप कुछ क्षेत्रों को ओवरराइड कर रहे होते हैं, लेकिन दूसरों को नहीं। +1
नाथन केलर

"यह" क्रिस लॉयर का सुझाव है? यह उत्तर काफी पुराना है कि यह शायद वर्तमान नहीं है (लेकिन शायद 1.2 के लिए अच्छा था)। यह सुनिश्चित करना महत्वपूर्ण है कि अविश्वसनीय जानकारी को ध्वजांकित किया जाए, अन्यथा नए लोगों को पता नहीं है कि क्या भरोसा करना है। आपके सहयोग के लिए धन्यवाद।
होल्डनवेब

72

Django 1.9 के लिए नया फॉर्म है ।field_order और Form.order_fields ()

# forms.Form example
class SignupForm(forms.Form):

    password = ...
    email = ...
    username = ...

    field_order = ['username', 'email', 'password']


# forms.ModelForm example
class UserAccount(forms.ModelForm):

    custom_field = models.CharField(max_length=254)

    def Meta:
        model = User
        fields = ('username', 'email')

    field_order = ['username', 'custom_field', 'password']

1
यह वह उत्तर है जिसकी मुझे तलाश है!
शिवाबुध

1
1.9 के रूप में यह उत्तर होना चाहिए नए खोजकर्ताओं को देखना चाहिए, स्पष्ट रूप से अभी भी 1.10 में काम करता है
ब्रायन एच।

2
नोट: यह "फ़ील्ड_ऑर्डर" नहीं है, लेकिन "फ़ील्ड_ऑर्डर" (कोई 'एस') नहीं है
डेवी

1
आप अपने इच्छित प्रपत्र फ़ील्ड के केवल एक सबसेट को भी निर्दिष्ट कर सकते हैं
danleyb2

40

मैंने आगे बढ़कर अपने प्रश्न का उत्तर दिया। यहाँ भविष्य के संदर्भ के लिए जवाब है:

Django में अपने वर्ग चर को अंततः कक्षा में परिभाषित क्रम में लोड करने form.pyकी __new__विधि का उपयोग करके कुछ काला जादू करता है self.fieldsself.fieldsएक Django SortedDictउदाहरण (में परिभाषित datastructures.py) है।

इसलिए इसे ओवरराइड करने के लिए, मेरे उदाहरण में कहें कि आप प्रेषक को पहले आना चाहते थे, लेकिन इसे एक इनिट विधि में जोड़ने की जरूरत थी , आप यह करेंगे:

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    message = forms.CharField()
    def __init__(self,*args,**kwargs):
        forms.Form.__init__(self,*args,**kwargs)
        #first argument, index is the position of the field you want it to come before
        self.fields.insert(0,'sender',forms.EmailField(initial=str(time.time())))

12
आप 'प्रेषक' फ़ील्ड को शीर्ष पर सामान्य रूप से परिभाषित कर सकते हैं और फिर अपनी प्रविष्टि लाइन में भिन्नता का उपयोग कर सकते हैं:self.fields.insert( 0, 'sender', self.fields['sender'] )
EvdB

4
यह अब Django 1.7 में काम नहीं करता है क्योंकि प्रपत्र फ़ील्ड ऑर्डरडेड का उपयोग करते हैं जो एपेंड का समर्थन नहीं करता है। नीचे मेरा अद्यतन उत्तर देखें (टिप्पणी के लिए बहुत लंबा है) ...
पॉल केनजोरा

11

फ़ील्ड को उस क्रम में सूचीबद्ध किया जाता है जिसे वे ModelClass._meta.fields में परिभाषित करते हैं। लेकिन अगर आप फॉर्म में ऑर्डर बदलना चाहते हैं, तो आप keyOrder फ़ंक्शन का उपयोग करके कर सकते हैं। उदाहरण के लिए :

class ContestForm(ModelForm):
  class Meta:
    model = Contest
    exclude=('create_date', 'company')

  def __init__(self, *args, **kwargs):
    super(ContestForm, self).__init__(*args, **kwargs)
    self.fields.keyOrder = [
        'name',
        'description',
        'image',
        'video_link',
        'category']

6

Django के साथ = = 1.7 आपके ContactForm.base_fieldsनीचे के रूप में संशोधित करना चाहिए :

from collections import OrderedDict

...

class ContactForm(forms.Form):
    ...

ContactForm.base_fields = OrderedDict(
    (k, ContactForm.base_fields[k])
    for k in ['your', 'field', 'in', 'order']
)

इस ट्रिक का उपयोग Django Admin PasswordChangeForm: Source on Github में किया जाता है


3
मज़ेदार, मैंने खेतों के ऑर्डर की तलाश की जब यह पता लगाने की कोशिश की गई कि सबक्लासिंग PasswordChangeFormने खेतों के क्रम को क्यों बदल दिया, इसलिए आपका उदाहरण मेरे लिए बहुत उपयोगी हुआ। ऐसा लगता है कि यह इसलिए base_fieldsहै क्योंकि उपवर्ग पर नहीं ले जाया जाता है। समाधान PasswordChangeFormSubclass.base_fields = PasswordChangeForm.base_fieldsकी परिभाषा के बाद कह रहा है लगता है 'PasswordChangeFormSubclass
orblivion

@orblivion: ऑर्डर किए गए तानाशाही के ContactForm.base_fields[k]निर्माण के दौरान उपयोग करें । एक टाइपो n उत्तर है, मैं संपादित करूँगा
ब्लूफैस्ट

5

प्रपत्र फ़ील्ड में निर्माण क्रम के लिए एक विशेषता होती है, जिसे कहा जाता है creation_counter.fieldsविशेषता एक डिक्शनरी है, इसलिए डिक्शनरी creation_counterमें सभी को जोड़ना और नए ऑर्डर को प्रतिबिंबित करने के लिए सभी क्षेत्रों में विशेषताओं को बदलना पर्याप्त होना चाहिए (कभी भी यह कोशिश नहीं की, हालांकि)।


5

फ़ील्ड क्लास में एक काउंटर का उपयोग करें। उस काउंटर के आधार पर छाँटें:

import operator
import itertools

class Field(object):
    _counter = itertools.count()
    def __init__(self):
        self.count = Field._counter.next()
        self.name = ''
    def __repr__(self):
        return "Field(%r)" % self.name

class MyForm(object):
    b = Field()
    a = Field()
    c = Field()

    def __init__(self):
        self.fields = []
        for field_name in dir(self):
            field = getattr(self, field_name)
            if isinstance(field, Field):
                field.name = field_name
                self.fields.append(field)
        self.fields.sort(key=operator.attrgetter('count'))

m = MyForm()
print m.fields # in defined order

आउटपुट:

[Field('b'), Field('a'), Field('c')]


4

Django के रूप में 1.7 फॉर्म ऑर्डरडीड का उपयोग करते हैं जो एपेंड ऑपरेटर का समर्थन नहीं करता है। तो आपको स्क्रैच से शब्दकोश फिर से बनाना होगा ...

class ChecklistForm(forms.ModelForm):

  class Meta:
    model = Checklist
    fields = ['name', 'email', 'website']

  def __init__(self, guide, *args, **kwargs):
    self.guide = guide
    super(ChecklistForm, self).__init__(*args, **kwargs)

    new_fields = OrderedDict()
    for tier, tasks in guide.tiers().items():
      questions = [(t['task'], t['question']) for t in tasks if 'question' in t]
      new_fields[tier.lower()] = forms.MultipleChoiceField(
        label=tier,
        widget=forms.CheckboxSelectMultiple(),
        choices=questions,
        help_text='desired set of site features'
      )

    new_fields['name'] = self.fields['name']
    new_fields['email'] = self.fields['email']
    new_fields['website'] = self.fields['website']
    self.fields = new_fields 

पाइथन 3.2 के बाद से आप आइटम को प्रीपेन्ड या अपेंड करने के लिए ऑर्डरडीडिक्ट.move_to_end () का उपयोग कर सकते हैं।
bparker

3

भविष्य के संदर्भ के लिए: हालात कुछ नए होने के बाद से बदल गए हैं। यह उन आधार फ़ार्मक्लासेस से फ़ील्ड्स को पुन: क्रमबद्ध करने का एक तरीका है जिन पर आपका कोई नियंत्रण नहीं है:

def move_field_before(form, field, before_field):
    content = form.base_fields[field]
    del(form.base_fields[field])
    insert_at = list(form.base_fields).index(before_field)
    form.base_fields.insert(insert_at, field, content)
    return form

इसके अलावा, base_fieldsयहाँ इस्तेमाल होने वाले SortedDict के बारे में थोड़ा सा प्रलेखन है: http://code.djangoproject.com/wiki/creadDict


मेरी कक्षा में 'फ़ील्ड' का उपयोग करना मेटा मेरे लिए काम कर रहा था (एक मॉडलफार्म के साथ) जब तक कि मेरे पास MyFormSet.form.base_fields का उपयोग करके एक विदेशी कुंजी फ़ील्ड के लिए प्रारंभिक मान सेट करने का कोई कारण नहीं था, जिस बिंदु पर 'फ़ील्ड' में आदेश नहीं था अब सम्मानित किया गया। मेरा समाधान वास्तव में अंतर्निहित मॉडल में खेतों को फिर से आदेश देना था।
पॉल जे

2

यदि या तो fields = '__all__':

class AuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = '__all__'

या excludeउपयोग किया जाता है:

class PartialAuthorForm(ModelForm):
    class Meta:
        model = Author
        exclude = ['title']

फिर Django मॉडल में परिभाषित क्षेत्रों के क्रम को संदर्भित करता है । यह सिर्फ मुझे पकड़ा, तो मैंने सोचा कि मैं इसका उल्लेख करूंगा। यह ModelForm डॉक्स में संदर्भित है :

यदि इनमें से किसी एक का उपयोग किया जाता है, तो फ़ील्ड जिस रूप में प्रकट होता है वह क्रम होगा जिस क्रम को मॉडल में फ़ील्ड परिभाषित किया गया है, जिसमें कईToManyField इंस्टेंस दिखाई देते हैं।


2

Django 1.9 फॉर्म में फ़ील्ड ऑर्डर करने का सबसे आसान तरीका field_orderआपके फॉर्म Form.field_order में उपयोग करना है

यहाँ एक छोटा सा उदाहरण है

class ContactForm(forms.Form):
     subject = forms.CharField(max_length=100)
     message = forms.CharField()
     sender = forms.EmailField()
     field_order = ['sender','message','subject']

यह वह सब कुछ दिखाएगा जिस क्रम में आप निर्दिष्ट करते हैं field_order


1

fieldsआंतरिक Metaकक्षा में उपयोग करना मेरे लिए क्या काम करता है Django==1.6.5:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Example form declaration with custom field order.
"""

from django import forms

from app.models import AppModel


class ExampleModelForm(forms.ModelForm):
    """
    An example model form for ``AppModel``.
    """
    field1 = forms.CharField()
    field2 = forms.CharField()

    class Meta:
        model = AppModel
        fields = ['field2', 'field1']

इतना सरल है।


1
ऐसा लगता है कि यह विधि केवल मॉडलफॉर्म के लिए मान्य है, सामान्य रूप django.formsकाम नहीं करता है
Pengfei.X

1

मैंने इसका उपयोग खेतों को स्थानांतरित करने के लिए किया है:

def move_field_before(frm, field_name, before_name):
    fld = frm.fields.pop(field_name)
    pos = frm.fields.keys().index(before_name)
    frm.fields.insert(pos, field_name, fld)

यह 1.5 में काम करता है और मुझे यकीन है कि यह अभी भी अधिक हाल के संस्करणों में काम करता है।


0

यह मेटा क्लास के साथ करना है जो फॉर्म क्लास को परिभाषित करने में उपयोग किया जाता है। मुझे लगता है कि यह खेतों की एक आंतरिक सूची रखता है और यदि आप सूची के बीच में डालें तो यह काम कर सकता है। उस कोड को देखे हुए मुझे कुछ समय हो गया है।

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