2009-02-06 2 views
34

Я знаю, что вы можете указать поля в django для помощников Admin. Однако я не могу найти ничего полезного для ModelForms. Просто некоторые исправления, которые я не могу использовать. Я что-то упускаю? Есть ли способ, которым я мог бы достичь чего-то вроде полей, не вручную выписывая каждое поле на моем шаблоне в соответствующем теге.Django и fieldsets на ModelForm

В идеале я хотел бы перебирать набор 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. t выглядит так, как BoundFields генерируются на лету ... это меня огорчает. Могу ли я создать свой собственный подкласс форм.Form, который содержит концепцию полей (даже грубая, которая не соответствует обратной совместимости ... это только для моего собственного проекта), и если да, можете ли вы дать какой-либо указатель? Я не хочу связываться с кодом django.

ответ

34

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

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

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

+1

Второе звено дал мне подсказку, что мне нужно, чтобы осуществить свою элементарную поддержку Fieldset. Спасибо. –

+1

Nov. 2010, используется django-form-utils успешно с 1.2.3. Спасибо за подсказку. – Boldewyn

16

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

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

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

Передайте их в шаблон в различных переменных и разбить FormSets:

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

+1

Это слишком много усилий, особенно в слое представления. – Greg

+3

@Greg, downvote меня не беспокоит, но ваш комментарий запутан. Что вы подразумеваете под слишком большим усилием? Разрыв монолитной формы на отдельные фрагменты формы, которые вы можете манипулировать независимо друг от друга, является идиоматическим подходом к этой проблеме. Django, возможно, добавил больше утилит «fieldset» за два года с тех пор, как я представил этот ответ, но подход все же остается в силе. –

+1

С точки зрения Грега ужасно недействительно! .. Этот вариант применим и гибкий. Единственный раз, когда это не сработало, было, когда в «чистом» методе могут потребоваться данные из двух или более полей форм-полей! – StefanNch

50

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

Update: что фрагмент кода с тех пор стал частью django-form-utils

+0

Отлично, это происходит в моем текущем проекте! –

+0

Спасибо за django-form-utils! Работает как шарм. – Boldewyn

+0

Я также использую form-utils, и я также написал расширение для форм-utils, которое позволяет упорядочивать поля в строках в наборе полей, точно так же, как admin. Я планирую связаться с автором формы-utils, чтобы узнать, примет ли он его как патч. Между тем, если вы хотите, просто спросите ... –

4

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

Uniform helpers can use layout objects. A layout can consist of fieldsets, rows, columns, HTML and fields10.

Первоначально я выбрал Django-uni-form, потому что он соответствует section 508.

0

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

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

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>