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. t выглядит так, как BoundFields генерируются на лету... это меня огорчает. Могу ли я создать свой собственный подкласс форм .Form, который содержит концепцию полей (даже грубая, которая не соответствует обратной совместимости... это только для моего собственного проекта), и если да, можете ли вы дать какой-либо указатель? Я не хочу возиться с кодом django.
Ответы
Ответ 1
Поля в модельных формах все еще находятся в стадии "проектирования". Там ticket в Django trac с низкой активностью.
Это то, что мне было интересно исследовать в ближайшем будущем, но поскольку я еще не сделал этого, лучшее, что я могу предложить, это следующие фрагменты:
Изменить: Я только что снова заметил этот вопрос, и я понимаю, что ему нужно отредактировать, чтобы указать проект Carl django-form-utils, который содержит класс BetterForm, который может содержать поля. Если вам нравится этот проект, дайте ему +1 для его ответа ниже:)
Ответ 2
Я думаю, этот фрагмент делает именно то, что вы хотите. Он предоставляет вам подкласс Form, который позволяет декларативно подразделять вашу форму на поля и прокручивать их в вашем шаблоне.
Обновление: этот фрагмент с тех пор стал частью django-form-utils
Ответ 3
Одна вещь, которую вы можете сделать, - разбить ваши логические поля на отдельные классы форм модели.
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 и затем объединить результирующие объекты. Или просто избегайте использования ModelMorm.save в целом и заполняйте объект модели вручную с помощью 'cleaned_data'
Ответ 4
Даниэль Гринфельдс django-uni-form решает это с помощью класса помощника Layout. Я пытаюсь это сделать прямо сейчас, и это выглядит довольно чистым для меня.
Унифицированные помощники могут использовать объекты макета. Макет может состоять из полей, строк, столбцов, HTML и полей.
Я изначально выбрал Django-uni-form, потому что он соответствует разделу 508.
Ответ 5
Это был код, который я разработал, чтобы понять пользовательские теги (со ссылками). Я применил его для создания набора полей.
Отказ от ответственности: я рекомендую использовать любой из приведенных выше ответов, это было только ради изучения.
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 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>