Django forms, inheritance and order of form fields

前端 未结 11 1628
终归单人心
终归单人心 2020-12-12 12:15

I\'m using Django forms in my website and would like to control the order of the fields.

Here\'s how I define my forms:

class edit_form(forms.Form):
         


        
相关标签:
11条回答
  • 2020-12-12 13:06

    From Django 1.9: https://docs.djangoproject.com/en/1.10/ref/forms/api/#notes-on-field-ordering


    Original answer: Django 1.9 will support this by default on the form with field_order:

    class MyForm(forms.Form):
        ...
        field_order = ['field_1', 'field_2']
        ...
    

    https://github.com/django/django/commit/28986da4ca167ae257abcaf7caea230eca2bcd80

    0 讨论(0)
  • 2020-12-12 13:07

    From Django 1.9+

    Django 1.9 adds a new Form attribute, field_order, allowing to order the field regardless their order of declaration in the class.

    class MyForm(forms.Form):
        summary = forms.CharField()
        description = forms.CharField(widget=forms.TextArea)
        author = forms.CharField()
        notes = form.CharField()
    
        field_order = ['author', 'summary']
    

    Missing fields in field_order keep their order in the class and are appended after the ones specified in the list. The example above will produce the fields in this order: ['author', 'summary', 'description', 'notes']

    See the documentation: https://docs.djangoproject.com/en/stable/ref/forms/api/#notes-on-field-ordering

    Up to Django 1.6

    I had this same problem and I found another technique for reordering fields in the Django CookBook:

    class EditForm(forms.Form):
        summary = forms.CharField()
        description = forms.CharField(widget=forms.TextArea)
    
    
    class CreateForm(EditForm):
        name = forms.CharField()
    
        def __init__(self, *args, **kwargs):
            super(CreateForm, self).__init__(*args, **kwargs)
            self.fields.keyOrder = ['name', 'summary', 'description']
    
    0 讨论(0)
  • 2020-12-12 13:07

    I built a form 'ExRegistrationForm' inherited from the 'RegistrationForm' from Django-Registration-Redux. I faced two issues, one of which was reordering the fields on the html output page once the new form had been created.

    I solved them as follows:

    1. ISSUE 1: Remove Username from the Registration Form: In my_app.forms.py

        class ExRegistrationForm(RegistrationForm):
              #Below 2 lines extend the RegistrationForm with 2 new fields firstname & lastname
              first_name = forms.CharField(label=(u'First Name'))
              last_name = forms.CharField(label=(u'Last Name'))
    
              #Below 3 lines removes the username from the fields shown in the output of the this form
              def __init__(self, *args, **kwargs):
              super(ExRegistrationForm, self).__init__(*args, **kwargs)
              self.fields.pop('username')
    

    2. ISSUE 2: Make FirstName and LastName appear on top: In templates/registration/registration_form.html

    You can individually display the fields in the order that you want. This would help in case the number of fields are less, but not if you have a large number of fields where it becomes practically impossible to actually write them in the form.

         {% extends "base.html" %}
         {% load i18n %}
    
         {% block content %}
         <form method="post" action=".">
              {% csrf_token %}
    
              #The Default html is: {{ form.as_p }} , which can be broken down into individual elements as below for re-ordering.
              <p>First Name: {{ form.first_name }}</p>
              <p>Last Name:  {{ form.last_name }}</p>
              <p>Email: {{ form.email }}</p>
              <p>Password: {{ form.password1 }}</p>
              <p>Confirm Password: {{ form.password2 }}</p>
    
              <input type="submit" value="{% trans 'Submit' %}" />
          </form>
          {% endblock %}
    
    0 讨论(0)
  • 2020-12-12 13:11

    It appears that at some point the underlying structure of field order was changed from a django specific SordedDict to a python standard OrderedDict

    Thus, in 1.7 I had to do the following:

    from collections import OrderedDict
    
    class MyForm(forms.Form):
    
        def __init__(self, *args, **kwargs):
            super(MyForm, self).__init__(*args, **kwargs)
            original_fields = self.fields
            new_order = OrderedDict()
            for key in ['first', 'second', ... 'last']:
                new_order[key] = original_fields[key]
            self.fields = new_order
    

    I'm sure someone could golf that into two or three lines, but for S.O. purposes I think clearly showing how it works is better than cleaver.

    0 讨论(0)
  • 2020-12-12 13:13

    You could also create a decorator to order fields (inspired by Joshua's solution):

    def order_fields(*field_list):
        def decorator(form):
            original_init = form.__init__
            def init(self, *args, **kwargs):
                original_init(self, *args, **kwargs)        
                for field in field_list[::-1]:
                    self.fields.insert(0, field, self.fields.pop(field))
            form.__init__ = init
            return form            
        return decorator
    

    This will ensure that all the fields passed to the decorator come first. You can use it like this:

    @order_fields('name')
    class CreateForm(EditForm):
        name = forms.CharField()
    
    0 讨论(0)
提交回复
热议问题