web-dev-qa-db-ja.com

DjangoおよびModelFormのフィールドセット

Django Adminヘルパー用にフィールドセットを指定できることを知っています。しかし、ModelFormsに役立つものは何も見つかりません。使用できないパッチがいくつかあります。何か不足していますか?できる方法はありますか?テンプレートの各フィールドを適切なタグで手動で書き出すことなく、フィールドセットのようなものを実現します。

理想的には、BoundFieldsのセットを反復処理したいと思います。しかし、私のModelFormの最後で次のようなことをしています:

    fieldsets = []
    fieldsets.append(('Personal Information',
                      [username,password,password2,first_name,last_name,email]),) # add a 2 element Tuple of string and list of fields
    fieldsets.append(('Terms & Conditions',
                      [acceptterms,acceptprivacy]),) # add a 2 element Tuple of string and list of fields

私のデータ構造に含まれる項目は、BoundFieldsではなく、生のフィールドであるため失敗します。 BoundFieldsがその場で生成されるように見えます...これは私を悲しくさせます。私はフィールドセットの概念を含むフォームの独自のサブクラスを作成できますか?(下位互換性のないラフなものでも...これは自分のプロジェクトのためだけです)そうであれば、ポインタを与えることができますか? Djangoコードをいじりたくありません。

39

モデルフォームのフィールドセットは、まだ「設計」段階にあります。アクティビティが少ないDjangoトラックに ticket があります。

これは私が近い将来自分自身を調査することに興味を持っていたものですが、まだ行っていないので、提供できる最善の方法は次のスニペットです。

編集:私はこの質問に再び気づきましたが、Carlのプロジェクトを指摘するには編集が必要であることに気付きました Django-form-utils フィールドセットを含むことができるBetterFormクラスが含まれています。このプロジェクトが気に入ったら、彼に以下の答えを+1してください。

35
Van Gale

私は this snippet があなたが望んでいることを正確に実行すると思います。宣言的にフォームをフィールドセットに細分割し、テンプレート内でそれらを反復できるようにするFormサブクラスを提供します。

更新:そのスニペットは Django-form-utils の一部になりました

50
Carl Meyer

実行できることの1つは、論理フィールドセットを個別のモデルフォームクラスに分割することです。

class PersonalInfoForm (forms.ModelForm):
    class Meta:
        model=MyModel
        fields=('field1', 'field2', ...)

class TermsForm (forms.ModelForm):
    class Meta:
        model=MyModel
        fields=('fieldX', 'fieldY', ...)

それらを異なる変数でテンプレートに渡し、フォームセットを分割します。

<form ...>
   <fieldset><legend>Personal Information</legend>
       {{ personal_info_form }}
   </fieldset>
   <fieldset><legend>Terms and Conditions</legend>
       {{ terms_form }}
   </fieldset>
</form>

その意味で、各フォームクラスは実際のHTMLフォームの一部にすぎません。

フォームでsaveを呼び出すと、少し複雑になります。おそらくcommit = Falseを渡して、結果のオブジェクトをマージする必要があります。または、ModelForm.saveの使用を完全に避け、モデルオブジェクトに 'cleaned_data'を手動で入力する

16
Joe Holloway

Daniel Greenfelds Django-uni-formは、レイアウトヘルパークラスでこれを解決します。私は今それを試しています、そしてそれは私にはかなりきれいに見えます。

ユニフォームヘルパーはレイアウトオブジェクトを使用できます。レイアウトはフィールドセット、行、列、HTMLおよびフィールドで構成できます

セクション508 に準拠しているため、最初にDjango-uni-formを選択しました。

4
oivvio

これは、カスタムタグ(リンク付き)を理解するために開発したコードです。フィールドセットを作成するためにそれを適用しました。

免責事項:私は上記の答えのいずれかを使用することをお勧めします。これは単に学習のためです。

templatetags/myextras.py

from Django import template
from Django.template import Context

register = template.Library()


class FieldsetNode(template.Node):
    """ Fieldset renderer for 'fieldset' tag """
    def __init__(self, nodelist, fieldset_name):
        """ Initialize renderer class
        https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/#writing-the-renderer
        :param nodelist: a list of the template nodes inside a block of 'fieldset'
        :param fieldset_name: the name of the fieldset
        :return: None
        """
        self.nodelist = nodelist
        self.fieldset_name = fieldset_name

    def render(self, context):
        """ Render the inside of a fieldset block based on template file
        https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/#auto-escaping-considerations
        :param context: the previous template context
        :return: HTML string
        """
        t = context.template.engine.get_template('myapp/fieldset.html')
        return t.render(Context({
            'var': self.nodelist.render(context),
            'name': self.fieldset_name,
        }, autoescape=context.autoescape))


@register.tag
def fieldset(parser, token):
    """ Compilation function for fieldset block tag
    Render a form fieldset
    https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/#writing-the-compilation-function
    https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/#parsing-until-another-block-tag
    :param parser: template parser
    :param token: tag name and variables
    :return: HTML string
    """
    try:
        tag_name, fieldset_name = token.split_contents()
    except ValueError:
        raise template.TemplateSyntaxError("%r tag requires a single argument" % token.contents.split()[0])
    if not (fieldset_name[0] == fieldset_name[-1] and fieldset_name[0] in ('"', "'")):
        raise template.TemplateSyntaxError("%r tag's argument should be in quotes" % tag_name)
    nodelist = parser.parse(('endfieldset',))
    parser.delete_first_token()
    return FieldsetNode(nodelist, fieldset_name[1:-1])

templates/myapp/fieldset.html

<div class="fieldset panel panel-default">
    <div class="panel-heading">{{ name }}</div>
    <div class="panel-body">{{ var }}</div>
</div>

templates/myapp/myform.html

<form action="{% url 'myapp:myurl' %}" method="post">
    {% csrf_token %}
    {% fieldset 'General' %}
        {{form.myfield1 }}
    {% endfieldset %}
    {# my submit button #}
</form>
0
Wtower