Django表单设置字段顺序

8

我正在尝试设置表单的字段顺序,但不知何故它仍然保持按字母顺序排列。有人有建议吗?我尝试了class Meta: fields = ["field", "field"]和在init中添加keyOrder。

表单:

class HangarFilterForm(forms.Form):

    FIELDS = [
        ("", ""),
        ("warp", "Warp"),
        ("cargo_space", "Cargo Space"),
        ("smuggle_bay", "Smuggle Bay"),
        ("dock", "Dock/Undock"),
        ("enter_warp", "Enter Warp"),
        ("fuel_bay", "Fuel Bay"),
        ("fuel_cost", "Fuel Cost"),
    ]

    PER_PAGE = [
        (10, ""),
        (5, "5 ships"),
        (10, "10 ships"),
        (25, "25 ships"),
        (50, "50 ships"),
    ]

    field_1 = forms.ChoiceField(choices=FIELDS, label="1st attribute", required=False)
    field_2 = forms.ChoiceField(choices=FIELDS, label="2nd attribute", required=False)
    per_page = forms.ChoiceField(choices=PER_PAGE, required=False)

    def __init__(self, *args, **kwargs):
        super(HangarFilterForm, self).__init__(*args, **kwargs)
        self.fields['planet'] = forms.ChoiceField(
                        choices=[("", "")] + [ (o.id, o.name) for o in    lanet.objects.all().order_by("name")], 
                        required=False)
        self.fields['type'] = forms.ChoiceField(
                        choices=[("", "")] + [ (o[0], o[1]) for o in ShipTemplate.SHIP_TYPES], required=False)
        self.fields.keyOrder = ["planet", "type", "field_1", "field_2", "per_page"]
5个回答

12
在Django 1.9中,新增了一种强制表单字段顺序的方法:field_order
请查看(链接到1.9版本): https://docs.djangoproject.com/en/1.9/ref/forms/api/#django.forms.Form.field_order (以及开发版本的链接): https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.Form.field_order 以下是一个简短的示例(使用Django 1.9)
models.py:
from django.db import models

class Project(models.Model):
     end_date = models.DateField(verbose_name='End date',
                                blank=True)

    start_date = models.DateField(verbose_name='Start date',
                                  blank=True)

    title = models.CharField(max_length=255,
                             blank=False,
                             verbose_name='Title')

    def __str__(self):
        return self.title

表单.py

from django.forms import ModelForm, DateTimeField, SelectDateWidget

from XXX.models import Project

class ProjectForm(ModelForm):
    class Meta:
        model = Project
        fields = '__all__'

    start_date = DateTimeField(widget=SelectDateWidget)
    end_date = DateTimeField(widget=SelectDateWidget)

    field_order = ['start_date', 'end_date']

在这个例子中,字段将被重新排列为:

  1. start_date <== 使用表单类别中的列表
  2. end_date <== 使用表单类别中的列表
  3. title <== 没有在列表中提及,因此使用默认排序

3

我尝试在Django 2.1的表单Meta中设置fields,并且也成功了:

class MyForm(forms.ModelForm):
    ...

    class Meta:
        model = Contact
        fields = ('field_1', 'field_2', 'field_3', 'field_4',)

你的回答对于ModelForms很好用。上述问题是关于普通Forms的。 - guettli

2

这是我过去用来重新排列表单字段顺序的一些代码,它已经可行了;你可能可以将其放入一个mixin中以供其他地方使用。让我知道它的进展如何。

from django.utils.datastructures import SortedDict


class HangarFilterForm(forms.Form):

    ordered_field_names = ['planet', 'type', 'field_1', 'field_2', 'per_page']

    def __init__(self, *args, **kwargs):
        super(HangarFilterForm, self).__init__(*args, **kwargs)
        # Your field initialisation code
        self.rearrange_field_order()

    def rearrange_field_order(self):

        original_fields = self.fields
        new_fields = SortedDict()

        for field_name in self.ordered_field_names:
            field = original_fields.get(field_name)
            if field:
                new_fields[field_name] = field

        self.fields = new_fields

如果出于某些原因您希望跟踪原始文件的顺序,您可以在rearrange_field_order中将original_fields更改为self.original_fields

看起来完美无缺。谢谢 :) 至少现在我可以循环我的表单而不是手动设置每个表单字段 :) - Hans de Jong

1
可能会有点跑题。使用Django Crispy Forms它们的Layout对象可以帮助您以您想要的方式格式化表单,包括重新排列字段顺序。
以下是一个示例:
class UpdateUserForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.layout = Layout(
            Field('email'),
            Field('quote'),
            Field('website', placeholder="http://"),
            Field('logo', template="user/logoInput.html"),
            HTML('<label class="control-label">Other settings</label>'),
            Field('emailVisible'),
            Field('subscribeToEmails'),
            Field('mpEmailNotif'),
            Field('showSmileys'),
            Field('fullscreen'),
        )

    class Meta:
        model = ForumUser
        fields = ('email', 'emailVisible', 'subscribeToEmails', 'mpEmailNotif',
                  'logo', 'quote', 'website', 'showSmileys', 'fullscreen')

0

我使用了bspink的方法并进行了一些改进。您不需要定义那些您不想更改其排序的字段。只需定义您想要按照它们自己的顺序置于顶部的内容。

(请确保您正在使用Python 3.7+)

class SomeForm(forms.Form):
    # define only you want to put top, no need to define all of them
    # unless you need more specific ordering        
    ordered_field_names = ['planet', 'type']

    def __init__(self, *args, **kwargs):
        super(SomeForm, self).__init__(*args, **kwargs)
        # call initialization code
        self.rearrange_field_order()

    def rearrange_field_order(self):
        # add defined fields first 
        new_fields = {field_name: self.fields.get(field_name) for field_name in self.ordered_field_names}

        # then add others whose not defined in order list
        for key, value in self.fields.items():
            if key not in new_fields:
                new_fields[key] = value

        self.fields = new_fields

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接