How does Django Know the Order to Render Form Fields?

后端 未结 14 1329
不知归路
不知归路 2020-11-28 05:21

If I have a Django form such as:

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


        
相关标签:
14条回答
  • 2020-11-28 06:05

    Use a counter in the Field class. Sort by that counter:

    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
    

    Output:

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

    0 讨论(0)
  • 2020-11-28 06:06

    As of Django 1.7 forms use OrderedDict which does not support the append operator. So you have to rebuild the dictionary from scratch...

    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 
    
    0 讨论(0)
  • 2020-11-28 06:07

    The easiest way to order fields in django 1.9 forms is to use field_order in your form Form.field_order

    Here is a small example

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

    This will show everything in the order you specified in field_order dict.

    0 讨论(0)
  • 2020-11-28 06:09

    If either fields = '__all__':

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

    or exclude are used:

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

    Then Django references the order of fields as defined in the model. This just caught me out, so I thought I'd mention it. It's referenced in the ModelForm docs:

    If either of these are used, the order the fields appear in the form will be the order the fields are defined in the model, with ManyToManyField instances appearing last.

    0 讨论(0)
  • 2020-11-28 06:10

    [NOTE: this answer is now pretty completely outdated - please see the discussion below it, and more recent answers].

    If f is a form, its fields are f.fields, which is a django.utils.datastructures.SortedDict (it presents the items in the order they are added). After form construction f.fields has a keyOrder attribute, which is a list containing the field names in the order they should be presented. You can set this to the correct ordering (though you need to exercise care to ensure you don't omit items or add extras).

    Here's an example I just created in my current project:

    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
    
    0 讨论(0)
  • 2020-11-28 06:11

    For future reference: things have changed a bit since newforms. This is one way of reordering fields from base formclasses you have no control over:

    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
    

    Also, there's a little bit of documentation about the SortedDict that base_fields uses here: http://code.djangoproject.com/wiki/SortedDict

    0 讨论(0)
提交回复
热议问题