100

次のような Django フォームがある場合:

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

そして、このフォームのインスタンスの as_table() メソッドを呼び出すと、Django は上記で指定したのと同じ順序でフィールドをレンダリングします。

私の質問は、クラス変数が定義されている順序を Django がどのように認識しているのかということです。

(また、クラスのinitメソッドからフィールドを追加する場合など、この順序をオーバーライドするにはどうすればよいですか?)

4

16 に答える 16

95

New to Django 1.9 is Form.field_order and 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']
于 2015-12-28T23:05:23.590 に答える
90

[注: この回答はかなり完全に古くなっています。その下のディスカッションと、より最近の回答を参照してください]。

がフォームの場合f、そのフィールドはf.fieldsですdjango.utils.datastructures.SortedDict (項目は追加された順に表示されます)。フォームの作成後、f.fields は keyOrder 属性を持ちます。これは、表示される順序でフィールド名を含むリストです。これを正しい順序に設定できます (ただし、項目を省略したり余分なものを追加したりしないように注意する必要があります)。

現在のプロジェクトで作成したばかりの例を次に示します。

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
于 2009-07-28T00:12:20.463 に答える
40

私は先に進み、自分の質問に答えました。今後の参考のための答えは次のとおりです。

Djangoでは、クラスで定義された順序で 最終的にクラス変数をロードするメソッドをform.py使用して、いくつかのダーク マジックを実行します。Djangoインスタンスです ( で定義)。__new__self.fieldsself.fieldsSortedDictdatastructures.py

したがって、これをオーバーライドするには、たとえば、送信者が最初に来て、initメソッドに追加する必要があるとします。次のようにします。

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())))
于 2008-12-08T21:12:56.517 に答える
11

フィールドは、ModelClass._meta.fields で定義されている順序でリストされます。ただし、Form 内で順序を変更したい場合は、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']
于 2011-04-21T16:53:43.070 に答える
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

于 2014-12-22T00:13:52.920 に答える
5

フォーム フィールドには、 と呼ばれる作成順序の属性がありますcreation_counter.fieldsattribute はディクショナリであるため、ディクショナリに単純に追加しcreation_counter、すべてのフィールドの属性を変更して新しい順序を反映するだけで十分です (ただし、これを試したことはありません)。

于 2008-12-08T20:52:25.027 に答える
5

Field クラスでカウンターを使用します。そのカウンターで並べ替えます。

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')]

于 2009-05-15T22:03:32.970 に答える
4

Django 1.7 フォームでは、追加演算子をサポートしていない OrderedDict を使用します。そのため、辞書を最初から再構築する必要があります...

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 
于 2015-03-03T22:18:34.967 に答える
3

将来の参考のために:新しいフォーム以来、物事は少し変わっています。これは、制御できない基本フォームクラスからフィールドを並べ替える1つの方法です。

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/SortedDict

于 2010-03-31T09:53:37.127 に答える
3

いずれかの場合fields = '__all__':

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

またはexclude使用されます:

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

次に、Djangoはモデルで定義されているフィールドの順序を参照します。これはちょうど私を捕まえたので、私はそれについて言及しようと思いました. ModelForm docsで参照されています:

これらのいずれかが使用される場合、フィールドがフォームに表示される順序は、フィールドがモデルで定義されている順序になり、ManyToManyField インスタンスが最後に表示されます。

于 2014-12-05T18:19:05.613 に答える
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これにより、 dictで指定した順序ですべてが表示されます。

于 2016-09-09T13:17:11.593 に答える
1

I've used this to move fields about:

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)

This works in 1.5 and I'm reasonably sure it still works in more recent versions.

于 2014-12-05T12:05:19.150 に答える
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']

それと同じくらい簡単です。

于 2014-08-22T14:14:27.560 に答える
0

フォーム クラスの定義に使用されるメタ クラスと関係があります。フィールドの内部リストを保持していると思います。リストの途中に挿入するとうまくいくかもしれません。そのコードを見てからしばらく経ちました。

于 2008-12-08T20:41:55.983 に答える