2009-05-27 9 views
59

私は自分のウェブサイトでDjangoフォームを使用しており、フィールドの順序を制御したいと考えています。ここでDjangoフォーム、継承、フォームフィールドの順序

は、私は私のフォームを定義方法は次のとおりです。

class edit_form(forms.Form): 
    summary = forms.CharField() 
    description = forms.CharField(widget=forms.TextArea) 


class create_form(edit_form): 
    name = forms.CharField() 

名前は不変で、エンティティが作成されたときにのみ表示される必要があります。私は一貫性とDRY原則を追加するために継承を使用します。実際には完全に予想される、間違っていないことは、nameフィールドがview/htmlの最後にリストされていますが、名前フィールドを要約と説明の上にしたいと思います。私は簡単に概要と説明をcreate_formにコピーして継承を緩めることで簡単に修正できることを認識していますが、これが可能かどうかを知りたいと思います。

なぜですか? edit_formに100個のフィールドがあり、create_formの先頭に10個のフィールドを追加しなければならないと想像してください。 (これはではなく、私の例です)

この動作をどのように無効にすることができますか?

編集:

はどうやら厄介なハック(選択図】図属性をいじる)を経由せずにこれを行うには、適切な方法はありません。 .field属性はSortedDict(Djangoの内部データ構造の1つ)であり、key:valueのペアを並べ替えることはできません。どのようにしてアイテムを特定のインデックスに挿入するかは、クラスメンバからコンストラクタにアイテムを移動する方法を提供します。このメソッドはうまくいくが、コードを読みにくくする。私が適切と思う唯一の他の方法は、ほとんどの状況で最適ではないフレームワーク自体を変更することです。

要するにコードは次のようになる::)

+4

これは長年のことですが、私はあなたがすでにこれを知っていると確信していますが、Pythonのクラス名は常に "CamelCased"にする必要があります。メソッド名は "named_with_underscore"だけです。 –

+0

「キャメルケース」を意味しましたか? :) – jball037

+1

TitleCaseは正しい言葉ですが、私は信じています。 –

答えて

95

私はこの同じ問題を抱えていたと私は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

...動作するようだ、とSortedDictは「キー並べ替えるためにどのような方法を提供しません:valueのペアを」という前提を間違って証明しています。 – hannson

+6

を仕事ができる興味深い – akaihola

+1

これは素晴らしいですが、唯一のforms.Form' '由来の形でそれを使用することを忘れないでください。 'forms.ModelForm'の場合は、' fields'属性のネストされた 'class Meta'に設定してください。ここを参照してください:http://stackoverflow.com/questions/2893471/how-can-i-order-fields-in-django-modelformは –

3

Djangoの内部には、フィールドの順序を追跡する途中でthis SO questionでノートを参照してください私を黙ら

class edit_form(forms.Form): 
    summary = forms.CharField() 
    description = forms.CharField(widget=forms.TextArea) 


class create_form(edit_form): 
    def __init__(self,*args,**kwargs): 
     forms.Form.__init__(self,*args,**kwargs) 

     self.fields.insert(0,'name',forms.CharField()) 

。その答えには、あなたの好みに合わせてフィールドを "並べ替える"方法の提案が含まれています(最後には、.fields属性で厄介なことになります)。

2

代替方法:

ポップアンドインサート:

self.fields.insert(0, 'name', self.fields.pop('name')) 

ポップアンドアペンド:

self.fields['summary'] = self.fields.pop('summary') 
self.fields['description'] = self.fields.pop('description') 

ポップ・アンド・アペンドすべて:

for key in ('name', 'summary', 'description'): 
    self.fields[key] = self.fields.pop(key) 

順序付きコピー:

self.fields = SortedDict([ (key, self.fields[key]) 
          for key in ('name', 'summary' ,'description') ]) 

しかし、Djangoのクックブックからセレーネのアプローチは、まだすべての明確な感じ。

+0

あなたはOrderedDict' – chhantyal

11

Seleneが投稿したソリューションを使用しましたが、keyOrderに割り当てられていないすべてのフィールドが削除されていました。私がサブクラス化しているフォームには多くのフィールドがありますので、これは私にとってはうまく機能しませんでした。私はakaiholaの答えを使って問題を解決するためにこの関数をコード化しましたが、Seleneのように動作させたい場合はthrow_awayからTrueに設定してください。

def order_fields(form, field_list, throw_away=False): 
    """ 
    Accepts a form and a list of dictionary keys which map to the 
    form's fields. After running the form's fields list will begin 
    with the fields in field_list. If throw_away is set to true only 
    the fields in the field_list will remain in the form. 

    example use: 
    field_list = ['first_name', 'last_name'] 
    order_fields(self, field_list) 
    """ 
    if throw_away: 
     form.fields.keyOrder = field_list 
    else: 
     for field in field_list[::-1]: 
      form.fields.insert(0, field, form.fields.pop(field)) 

これは、私は自分のコードでそれを使用している方法です:

class NestableCommentForm(ExtendedCommentSecurityForm): 
    # TODO: Have min and max length be determined through settings. 
    comment = forms.CharField(widget=forms.Textarea, max_length=100) 
    parent_id = forms.IntegerField(widget=forms.HiddenInput, required=False) 

    def __init__(self, *args, **kwargs): 
     super(NestableCommentForm, self).__init__(*args, **kwargs) 
     order_fields(self, ['comment', 'captcha']) 
+1

私は本当にこのような 'に挿入を行うことはできません!ありがとう。 –

7

ます。また、(ジョシュアのソリューションに触発さ)フィールドを注文するデコレータを作成することができます。

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 

これにより、デコレータに渡されたすべてのフィールドが最初に来るようになります。 あなたはこのようにそれを使用することができます:

@order_fields('name') 
class CreateForm(EditForm): 
    name = forms.CharField() 
1

@akaiholaによって解答に基づいており、self.fields.insert最新のDjango 1.5で動作するように更新さdepreciatedされています。上記で

from easycontactus.forms import * 
from django import forms 
class CustomEasyContactUsForm(EasyContactUsForm): 
    ### form settings and configuration 
    CAPTHCA_PHRASE = 'igolf' 

    ### native methods 
    def __init__(self, *args, **kwargs): 
     super(CustomEasyContactUsForm, self).__init__(*args, **kwargs) 
     # re-order placement of added attachment field 
     self.fields.keyOrder.insert(self.fields.keyOrder.index('captcha'), 
            self.fields.keyOrder.pop(self.fields.keyOrder.index('attachment')) 
            ) 

    ### field defintitions 
    attachment = forms.FileField() 

それはdjango-easycontactusパッケージで定義されているように、我々はEasyContactUsFormベースクラスを拡張しています。

10

いくつかの点で、フィールドオーダーの基本的な構造は、このようにPythonの標準OrderedDict

からSordedDict特定ジャンゴから変更された1.7で、私は次のことをしなければならなかったことが表示されます:

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 

誰かが2〜3行にゴルフをすることができると確信していますが、SO私はそれがどのように動作するかを明確に示すことは、食料品よりも優れていると思います。

+4

[ここ](https://github.com/pennersr/django-allauth/issues/356#issuecomment-24758824)は、Djangoの新旧両方のバージョンのonelinerを使った美しい例です。これは、フィールドのSortedDictとOrderedDictの両方の実装がサポートされるように、機能の検出を使用します。 – aruseni

+0

答えTedとコメント@aruseniに感謝します。これは私の意見では、Djangoのコアで実際には深くはないので、これを実行する最善の方法です。私はそれがまだ1.9で動作することを確認します。 – Yoone

6

答えは、Django 1.7で変更された内部DjangoフォームAPIを使用しています。 The project team's opinion is that it should never have been used in the first place.この関数を使用してフォームを並べ替えるようになりました。このコードOrderedDictを使用しています:

私はこのようなクラスで使用
def reorder_fields(fields, order): 
    """Reorder form fields by order, removing items not in order. 

    >>> reorder_fields(
    ...  OrderedDict([('a', 1), ('b', 2), ('c', 3)]), 
    ...  ['b', 'c', 'a']) 
    OrderedDict([('b', 2), ('c', 3), ('a', 1)]) 
    """ 
    for key, v in fields.items(): 
     if key not in order: 
      del fields[key] 

    return OrderedDict(sorted(fields.items(), key=lambda k: order.index(k[0]))) 

class ChangeOpenQuestion(ChangeMultipleChoice): 

    def __init__(self, *args, **kwargs): 
     super(ChangeOpenQuestion, self).__init__(*args, **kwargs) 
     key_order = ['title', 
        'question', 
        'answer', 
        'correct_answer', 
        'incorrect_answer'] 

     self.fields = reorder_fields(self.fields, key_order) 
15

ジャンゴ1.9から:https://docs.djangoproject.com/en/1.10/ref/forms/api/#notes-on-field-ordering


オリジナルの答え: Djangoの1.9意志フォームにデフォルトでこれをサポートしますfield_order

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

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

+1

ドキュメントについては、https://docs.djangoproject.com/en/1.10/ref/forms/api/#notes-on-field-orderingを参照してください。 –

0

私は、フォームを構築し 'ExRegistrationForm' ジャンゴ・登録-再来から 'RegistrationForm' から継承されました。私は2つの問題に直面しました。そのうちの1つは、新しいフォームが作成されると、html出力ページのフィールドを並べ替えることでした。

私は次のようにそれらを解決:ISSUE 2 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:

1. ISSUE 1:登録フォームからユーザー名を削除する姓を作成し、姓は一番上に表示されます:テンプレート/登録/ registration_form.html

では、個別にしたいという順序でフィールドを表示することができます。これはではなく、あなたはそれが実際にそれをフォームに書き込みすることは事実上不可能になるフィールドの数が多い場合は、フィールドの数が少ない場合には役立つだろう。

 {% 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 %} 
関連する問題