Джанго и наборы полей на ModelForm - PullRequest
37 голосов
/ 06 февраля 2009

Я знаю, что вы можете указать наборы полей в django для помощников администратора. Тем не менее, я не могу найти ничего полезного для 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.

Ответы [ 5 ]

50 голосов
/ 08 февраля 2009

Я думаю этот фрагмент делает именно то, что вы хотите. Он предоставляет вам подкласс Form, который позволяет вам декларативно подразделять вашу форму на наборы полей и перебирать их в вашем шаблоне.

Обновление: этот фрагмент с тех пор стал частью django-form-utils

34 голосов
/ 06 февраля 2009

Наборы полей в модельных формах все еще находятся на стадии «проектирования». В трассе Джанго есть билет с низкой активностью.

Это то, что мне было интересно в ближайшее время исследовать себя, но, поскольку я еще не сделал этого, лучшее, что я могу предложить, это следующие фрагменты:

Редактировать: Я только что заметил этот вопрос еще раз, и я понимаю, что требуется редактирование, чтобы указать на проект Карла django-form-utils , который содержит класс BetterForm, который может содержать наборы полей. Если вам нравится этот проект, дайте ему +1 за ответ ниже:)

16 голосов
/ 07 февраля 2009

Одна вещь, которую вы можете сделать, это разбить ваши логические наборы полей на отдельные классы формы модели.

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-формы.

Это вводит немного сложности, когда вы вызываете сохранить в форме. Возможно, вы захотите передать commit = False и затем объединить получившиеся объекты. Или просто избегайте использования ModelForm.save и заполняйте вручную объект модели с помощью 'cleaned_data'

4 голосов
/ 08 октября 2010

Дэниел Гринфелдс django-uni-form решает эту проблему с помощью вспомогательного класса Layout. Я пробую это прямо сейчас, и это выглядит довольно чистым для меня.

Унифицированные помощники могут использовать объекты макета. Макет может состоять из наборов полей, строк, столбцов, HTML и полей .

Я изначально выбрал Django-уни-форму, потому что она соответствует разделу 508 .

0 голосов
/ 07 мая 2015

Это был код, который я разработал для понимания пользовательских тегов (со ссылками). Я применил его для создания набора полей.

Отказ от ответственности: я рекомендую использовать любой из вышеперечисленных ответов, это было только ради обучения.

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>
...