Related
I am trying to get specific querysets based when a customer-specific form loads, showing only that customer's name (embedded as an ID field), its respective locations and users.
The idea is to select one user and any number of locations from a multichoice box.
I've tried to pass the ID as a kwarg but am getting a KeyError. I've tried the kwarg.pop('id') as found on the web and same issue. Any advice?
forms.py
class LocGroupForm(forms.ModelForm):
class Meta:
model = LocationsGroup
fields = ('group_name', 'slug', 'customer', 'location', 'user_id',)
def __init__(self, *args, **kwargs):
qs = kwargs.pop('id')
super(LocGroupForm, self).__init__(*args, **kwargs)
self.fields['customer'].queryset = Customers.objects.get(pk=qs)
self.fields['location'].queryset = CustomerLocations.objects.filter(customer_id=qs)
self.fields['user_id'].queryset = CustomerUsers.objects.filter(customer_id=qs)
here is my view. it's just a generic view
views.py
class LocGroupCreate(LoginRequiredMixin, CreateView):
form_class = LocGroupForm
template_name = 'ohnet/a_gen_form.html'
the template is a dry template I use for all my forms- admittedly something I mostly stole from a tutorial
{% extends "ohnet/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% load static %}
<div class="container">
<h1>{{ title }}</h1>
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<input type="submit" name="submit" value="Submit">
</form>
</div>
{% endblock content %}
This is the KeyError from the form load.
You need to pass a value for the id when constructing the LocGroupForm, you can do that by overriding get_form_kwargs:
class LocGroupCreate(LoginRequiredMixin, CreateView):
form_class = LocGroupForm
template_name = 'ohnet/a_gen_form.html'
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['id'] = …
return kwargs
You will need to fill in the … that specifies the value passed as id to the form. This might for example be self.request.user.pk, or a URL parameter with self.kwargs['name-of-url-parameter']
I'm trying to edit fieldset.html template in order to add the hidden input under readonly div (in readonly case).
{% if field.is_readonly %}
<div class="readonly {% if field.field.name %} field-{{ field.field.name }}{% endif %}">{{ field.contents }}</div>
<input id="{% if field.field.name %} id-{{ field.field.name }}{% endif %}" type="hidden" value="{{ field.field.initial }}"/>
{% else %}
{{ field.field }}
{% endif %}
My problem is that if I set a field readonly with "get_readonly_fields", I can't submit the form because hidden field is required (I think this is a big error of django that uses div instead of the hidden input).
I tried to fix it with the code above but I'am not able to insert the value in to my field, because "field.field.initial" is empty for readonly field. How can I solve it?
UPDATE
My form.py:
class MyModelAdminForm(forms.ModelForm):
val1 = forms.CharField()
val2 = forms.ModelChoiceField(queryset=User.objects.filter(groups__name='Group1'))
val3 = forms.CharField(widget=forms.DateInput(attrs={'type': 'date'}))
class Meta:
model = MyModel
fields = ('val1', 'val2', 'val3')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self._meta.fields:
attrs = {'class':'form-control'}
self.fields[field].widget.attrs.update(attrs)
My admin.py
class CampaignAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
return MyModelAdminForm
def get_fieldsets(self, request, obj=None):
return [
(None, {'fields': ['val1', 'val2']}),
('Informations', {'fields': ['val3']}),
]
def get_readonly_fields(self, request, obj=None):
if obj:
return self.readonly_fields + ('val2',)
else:
return self.readonly_fields
I need that val2 is in readonly mode in edit page.
In general, you can add any fields to your form as you see fit. So, if you need the field to show up as read-only as well as a hidden field, you can just add two fields. You should name the hidden field correctly so that saving works. You can use label to change the label of the read-only field (https://docs.djangoproject.com/en/1.11/ref/forms/fields/#label).
EDIT - solution for your code:
For your solution, if you change the form to have val2 as readonly field instead of a regular field, you also need to change the form's Meta.fields setting from:
fields = ('val1', 'val2', 'val3')
to
fields = ('val1', 'val3')
Otherwise, the validators for val2 will run.
Or, you have to change the widget of val2 to HiddenInput and add its value as readonly_field using a different name with an explicit method in your django admin class. But that would require changing the fieldsets depending on the mode (edit or create).
Is it possible to inject a non-form element into a dynamic Django form's context? I have a "Delete user photos" form that I want to contain a thumbnail image of each user with a BooleanField checkbox and label right below it:
+------------+
| |
| photo |
| |
+------------+
[x] Delete <username>'s photos
Right now I know how to create the dynamic checkboxes and their labels but I'm not sure how to go about adding each user's photo. As can be seen from my code below, the name attribute of each HTML input tag will contain the user's ID and I'll examine this attribute when the user submits the form to determine whether to delete their photos or not. I'd like to insert an tag just above each input tag that links to the user's profile photo. The image tag's "src" attribute will contain the user's ID which creates the link to their photo. Is there a way to "inject" this non-form image tag into the context of this dynamic form in order to render an image tag just above each checkbox input tag?
Thanks.
# views.py
def remove_access_to_private_photos(request, template):
if request.method == 'POST':
form = RemovePrivatePhotoAccessForm(request.POST, this_user_id=request.user.id)
if form.is_valid():
for name, value in form.cleaned_data.items():
if value == True:
# Profile links to User via a OneToOneField
this_user = Profile.objects.get(user_id=request.user.id)
other_user = Profile.objects.get(user_id=name)
this_user.remove_private_access(other_user_prof)
return redirect('photos-home')
else:
form = RemovePrivatePhotoAccessForm(this_user_id=request.user.id)
context = {'form': form}
return render(request, template, context)
# models.py
class RemovePrivatePhotoAccessForm(forms.Form):
def __init__(self, *args, **kwargs):
this_user_id = kwargs.pop('this_user_id')
super(RemovePrivatePhotoAccessForm, self).__init__(*args, **kwargs)
user = User.objects.get(pk=this_user_id)
user_prof = Profile.objects.get(user=user)
other_user_id_list = user_prof.gave_private_access().values_list('user_id', flat=True)
for id in other_user_id_list:
other_user = User.objects.get(pk=id)
self.fields[str(id)] = forms.BooleanField(required=False)
self.fields[str(id)].label = mark_safe('%s') % (id, this_user_id, other_user.username)
# delete_photos.html
<form action="." method="post">
{% csrf_token %}
{% for field in form %}
{# I'D LIKE TO PUT <IMG> TAG HERE #}
{{ field }} Delete {{ field.label|safe }}'s photos
{% endfor %}
<input type="submit" value="Submit" />
</form>
A form field is just a class, so you can add whatever properties you need when or after you instantiate it. Your view remains unchanged given this example code.
# forms.py
from .models import Profile # or whatever
class RemovePrivatePhotoAccessForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
user_id = kwargs.pop('user_id')
user_profile = Profile.objects.get(pk=user_id)
other_profiles = user_profile.gave_private_access()
for profile in other_profiles:
id = str(profile.id)
field = forms.BooleanField(required=False)
field.label = mark_safe('%s') % (id, user_profile.id, profile.username)
field.photo = profile.photo
self.fields[id] = field
super(RemovePrivatePhotoAccessForm, self).__init__(*args, **kwargs)
# delete_photos.html
<form action="." method="post">
{% csrf_token %}
{% for field in form %}
<img src="{{ field.photo.url }}" />
{{ field }} Delete {{ field.label|safe }}'s photos
{% endfor %}
<input type="submit" value="Submit" />
</form>
Here's how I solved this problem. First I created a custom template tag:
# photos/templatetags/photos_extras.py
from django import template
from django.contrib.auth.models import User
from django.utils.safestring import mark_safe
register = template.Library()
#register.simple_tag
def render_image(uid):
user = User.objects.get(pk=uid)
src_string = ''.join([
'/photos/',
user.username, '_',
user.profile.image_id,
'_thumb.jpg'])
img_tag = ''.join([
'<img src="',
src_string,
'" alt="',
user.username,
'" />'])
return mark_safe(img_tag)
I then inserted the custom template tag into my template. field.name contains the desired user's user ID, and render_image returns the desired HTML img tag.
# delete_photos.html
<form action="." method="post">
{% csrf_token %}
{% for field in form %}
{% render_image field.name %}
{{ field }} Delete {{ field.label|safe }}'s photos
{% endfor %}
<input type="submit" value="Submit" />
</form>
I am trying to write a Bootstrap Form with Django ModelForm. I have read the Django Documentation Django Documentation about Forms, so I have this code:
<div class="form-group">
{{ form.subject.errors }}
<label for="{{ form.subject.id_for_label }}">Email subject:</label>
{{ form.subject }}</div>
The {{form.subject}} is rendered by Django, for example in CharField field model, as input tag,
<input type="text"....> etc.
I need add "form-control" class to every input in order to get Bootstrap input appearance (without third-party packages). I found this solution Django add class to form <input ..> field. Is there any way to add a class to every field by default without specifying it in every attribute of the class of Form class?
class ExampleForm(forms.Form):
name = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))
email = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))
address = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))
country = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control'}))
and so on ..
If you can't use a third-party app and want to add a class (e.g., "form-control") to every field in a form in a DRY manner, you can do so in the form class __init__() method like so:
class ExampleForm(forms.Form):
# Your declared form fields here
...
def __init__(self, *args, **kwargs):
super(ExampleForm, self).__init__(*args, **kwargs)
for visible in self.visible_fields():
visible.field.widget.attrs['class'] = 'form-control'
You might need to handle checking for existing classes in attrs too, if for some reason you'll be adding classes both declaratively and within __init__(). The above code doesn't account for that case.
Worth mentioning:
You specified that you don't want to use third-party packages. However, I'll take one second to mention that one of the simplest ways of automatically making forms render in the style of Bootstrap is to use django-crispy-forms, like this:
# settings.py
CRISPY_TEMPLATE_PACK = 'bootstrap3'
# forms.py
from crispy_forms.helper import FormHelper
class ExampleForm(forms.Form):
# Your declared form fields here
...
helper = FormHelper()
# In your template, this renders the form Bootstrap-style:
{% load crispy_forms_tags %}
{% crispy form %}
you can add CSS classes in forms.py
subject = forms.CharField(label='subject',
max_length=100,
widget=forms.TextInput(
attrs={'class': "form-control"}))
Since it took me more hours, than I would like to (django newbie), to figure this out, I will place my outcome here aswell.
Setting widget to each field just to add one class over and over again is against programming rule of repeating and leads to many unneccessary rows. This especially happens when working with bootstrap forms.
Here is my (working) example for adding not only bootstrap classes:
forms.py
class CompanyForm(forms.Form):
name = forms.CharField(label='Jméno')
shortcut = forms.CharField(label='Zkratka')
webpage = forms.URLField(label='Webové stránky')
logo = forms.FileField(label='Logo')
templatetags/custom_tags.py
from django import template
from django.urls import reverse
register = template.Library()
#register.filter('input_type')
def input_type(ob):
'''
Extract form field type
:param ob: form field
:return: string of form field widget type
'''
return ob.field.widget.__class__.__name__
#register.filter(name='add_classes')
def add_classes(value, arg):
'''
Add provided classes to form field
:param value: form field
:param arg: string of classes seperated by ' '
:return: edited field
'''
css_classes = value.field.widget.attrs.get('class', '')
# check if class is set or empty and split its content to list (or init list)
if css_classes:
css_classes = css_classes.split(' ')
else:
css_classes = []
# prepare new classes to list
args = arg.split(' ')
for a in args:
if a not in css_classes:
css_classes.append(a)
# join back to single string
return value.as_widget(attrs={'class': ' '.join(css_classes)})
reusable_form_fields.html (template)
{% load custom_tags %}
{% csrf_token %}
{% for field in form %}
<div class="form-group row">
{% if field|input_type == 'TextInput' %}
<div for="{{ field.label }}" class="col-sm-2 col-form-label">
{{ field.label_tag }}
</div>
<div class="col-sm-10">
{{ field|add_classes:'form-control'}}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
</div>
{% else %}
...
{% endif %}
</div>
{% endfor %}
Crispy forms are the way to go . Tips for Bootstrap 4. Adding to #Christian Abbott's answer, For forms , bootstrap says, use form-group and form-control .
This is how it worked for me .
My forms.py
class BlogPostForm(forms.ModelForm):
class Meta:
model = models.Post
fields = ['title', 'text', 'tags', 'author', 'slug']
helper = FormHelper()
helper.form_class = 'form-group'
helper.layout = Layout(
Field('title', css_class='form-control mt-2 mb-3'),
Field('text', rows="3", css_class='form-control mb-3'),
Field('author', css_class='form-control mb-3'),
Field('tags', css_class='form-control mb-3'),
Field('slug', css_class='form-control'),
)
My post_create.html
{% extends 'blog/new_blog_base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container">
<form method='POST' enctype="multipart/form-data">
{% csrf_token %}
{{ form.media }}
{% crispy form %}
<hr>
<input type="submit" name="Save" value="Save" class='btn btn-primary'> <a href="{% url 'home' %}" class='btn btn-danger'>Cancel</a>
</form>
</div>
{% endblock %}
Note : If you are using CK Editor RichTextField() for your model field , then that field wont be affected . If anyone knows about it , do update this .
You can also explicity mention the field that you want to apply the class to
class ProfileForm(ModelForm):
class Meta:
model = Profile
fields = ['avatar','company']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['avatar'].widget.attrs.update({'class': 'form-control'})
self.fields['company'].widget.attrs.update({'class':'form-control'})
I found it easier to identify the element via css and add the styling there. With django forms you get a unique id for each form field (user form prefixes if you display the form multiple times in your template).
# views.py
def my_view_function(request):
form_a = MyForm(prefix="a")
form_b = MyForm(prefix="b")
context = {
"form_a": form_a,
"form_b": form_b
}
return render(request, "template/file.html", context)
style
// file.css
form input#by_id {
width: 100%;
}
This is a answer complemeting #Christian Abbott correct answer.
If you use a lot of forms, a option for not having to override init every single time may be to create your own form class:
class MyBaseForm(forms.Form):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for visible in self.visible_fields():
visible.field.widget.attrs['class'] = 'form-control'
Then you can inherit from this class and it is going to automatically make the styles for you.
class ExampleForm(MyBaseForm):
# Your declared form fields here
...
Same thing can be done with ModelForm by simply creating a MyBaseModelForm that inherits from ModelForm.
This is very practical:
class CreateSomethingForm(forms.ModelForm):
class Meta:
model = Something
exclude = []
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self.fields.values():
field.widget.attrs['class'] = 'form-control'
In this way you don't have to go field by field.
One way is to create base form class and manually update the field's attribute inside __init__ method.
Another is by using already existing libraries like this one:
https://github.com/dyve/django-bootstrap3
There are plenty of these libraries around github. Look around.
Ok some time has passed but i had the same issues. I came to this solution:
class FormCssAttrsMixin():
cssAttrs = {}
def inject_css_attrs(self):
# iterate through fields
for field in self.fields:
widget = self.fields[field].widget
widgetClassName = widget.__class__.__name__
# found widget which should be manipulated?
if widgetClassName in self.cssAttrs.keys():
# inject attributes
attrs = self.cssAttrs[widgetClassName]
for attr in attrs:
if attr in widget.attrs: # attribute already existing
widget.attrs.update[attr] = widget[attr] + " " + attrs[attr] # append
else: # create attribute since its not existing yet
widget.attrs[attr] = attrs[attr]
class MyForm(FormCssAttrsMixin, forms.Form):
# add class attribute to all django textinputs widgets
cssAttrs = {"TextInput": {"class": "form-control"}}
name = forms.CharField()
email = forms.CharField()
address = forms.CharField()
country = forms.CharField()
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.inject_css_attrs()
With this Mixin class you can manipulate the attributes of form widgets in a generic way. Simply add a dictionary as class variable which contains the desired attributes and values per widget.
This way you can add your css classes at the same location where you define your fields. Only downside is, that you have to call the "inject_css_attrs" method somewhere but i think that is ok.
A generalized version of #christian-abbott response:
class ExampleForm(forms.Form):
_HTML_CLASSES = ('form-control', 'something-else')
# Your declared form fields here
...
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for visible in self.visible_fields():
missing_classes = list(self._HTML_CLASSES)
if 'class' in visible.field.widget.attrs:
current_classes = visible.field.widget.attrs['class'].split(' ')
for current_class in current_classes:
if current_class in missing_classes:
missing_classes.remove(current_class)
else:
current_classes = []
visible.field.widget.attrs['class'] = ' '.join(current_classes + missing_classes)
If you just need to change the class for bootstrap purposes, you can just add a script to the template.
<script>
const elementsInputs = document.querySelectorAll('input[id^="id_"]');
elementsInputs.forEach(element => {
element.classList.add("form-control");
});
const elementsLabels = document.querySelectorAll('label[for^="id_"]');
elementsLabels.forEach(element => {
element.classList.add("form-label");
});
</script>
then the form fields in the template should be something like:
<div class="fieldWrapper">
{{ form.subject.errors }}
{{ form.subject.label_tag }}
{{ form.subject }}
</div>
as described in Django.
You can add classes in your forms.py inside the Meta class:
class Form(forms.ModelForm):
class Meta:
model = ModelForm
fields = "__all__"
widgets = {
'name': forms.TextInput(attrs={'class':'form-control'})
}
I understood "no third-party libs", but this one django-widget-tweaks
really WORTH MENTIONING
is simple, DRY and powerfull.
give you full control over the widget rendering doesnt matter which css framework you are using ... still simple
you manage many html attributes you want on HTML not Django forms.
User template "filters" not template tags (as a "normal" form var)
You control the input and labels
django-widget-tweaks
-> https://github.com/jazzband/django-widget-tweaks
Sample ...
{{form.hours|attr:"class:form-control form-control-sm"}}
You can do it without any external libraries or code changes, right in the template. Like this:
{% for field in form %}
<div class="input_item">
<p class="title">{{ field.label }}:</p>
<div class="form-group">
<{{ field|cut:"<"|cut:">" }} class="form-control">
</div>
</div>
{% endfor %}
However, it is not the best solution. If you can create templatetag - go for it.
you can use row-cols-5
<div class="row row-cols-5">
<div class="col">1</div>
<div class="col">2</div>
<div class="col">3</div>
<div class="col">4</div>
<div class="col">5</div>
</div>
I know that author asked about Bootstrap for own Form, but there is an additional way to include Bootstrap class tag in Django form for authentication, password reset etc.
If we create template with standard form:
<form action="" method="post">
{% csrf_token %}
{{ form }}
</form>
then in browser source code we can see all the form fields with the tags:
<form action="" method="post">
<input type="hidden" name="csrfmiddlewaretoken" value="xxx">
<tr><th><label for="id_old_password">Old password:</label></th><td><input type="password" name="old_password" autofocus required id="id_old_password"></td></tr>
<tr><th><label for="id_new_password1">New password:</label></th><td><input type="password" name="new_password1" required id="id_new_password1"></td></tr>
<tr><th><label for="id_new_password2">New password confirmation:</label></th><td><input type="password" name="new_password2" required id="id_new_password2"></td></tr>
</form>
Variable {{ form }} in our template now can be replaced with this code and Bootstrap classes we needed:
<div class="fieldWrapper form-group" aria-required="true">
<label for="id_old_password">Old password:</label><span class="required">*</span>
<input type="password" **class="form-control"** name="old_password" autofocus required id="id_old_password">
</div>
Maybe it could be useful for redesign built-in static forms.
Is there a way in Django to add custom attributes to a model's fields (without resorting to subclassing fields)?
I would like to only display certain fields in certain sections of my template. This is because eventually each type of field will be displayed in a separate tab. I thought about adding a custom attribute to each field to identify which section/tab it should go in. But, so far, I've had no luck.
I have a few field types:
class Enum(set):
def __getattr__(self, name):
if name in self:
return name
raise AttributeError
FieldTypes = Enum(["one","two","three",])
And a few models:
class Model1(models.Model):
a = models.CharField()
b = models.ForeignKey('Model2')
c = models.IntegerField()
a.type = FieldTypes.one # this obviously doesn't work
b.type = FieldTypes.two # this obviously doesn't work
c.type = FieldTypes.three # this obviously doesn't work
class Model2(models.Model):
d = models.CharField()
And a form:
class Form1(forms.ModelForm):
class Meta:
model = Mode1
And a template:
{% for fieldType in FieldTypes %}
<div class="{{fieldType}}">
{% for field in form %}
{% if field.type = fieldType %}
{{ field }}
{% endif %}
{% endfor %}
</div>
{% endfor %}
But this doesn't work.
Ideas? Or other suggestions for only placing certain fields in certain sections of the page?
Thanks.
In general, I would keep this logic outside of the model class. Models shouldn't be tangled up with presentation elements if you can help it, and choosing which fields to display in a form seems like a presentation concern. Fortunately, the Form class provides a nice, UI-focused layer between the data layer (the model) and the presentation layer (the view and template).
Here's how I've addressed this in the past. In my Form class, I created a list of field groups, each with a title and a list of the names of the fields they contain:
class MyModelForm(forms.ModelForm):
field_groups = (
{'name':'Group One', 'fields':('a', 'b', 'c')},
{'name':'Group Two', 'fields':('d', 'e')},
)
class Meta:
model = MyModel
Then in the template, I looped through the groups, and within that loop conditionally included those fields:
{% for group in form.field_groups %}
<h3 class="groupheader">{{group.name}}</h3>
{% for field in form %}
{% if field.name in group.fields %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
</div>
{% endif %}
{% endfor %}
{% endfor %}
This allows you to control the grouping and display of form fields within the MyModelForm class, which is a reasonable place for presentation logic to live.
It's posible!
class Model1(models.Model):
a = models.CharField()
b = models.ForeignKey('Model2')
c = models.IntegerField()
And a form:
class Form1(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(Form1, self).__init__(*args, **kwargs)
self.fields['a'].type = FieldTypes.one
self.fields['b'].type = FieldTypes.two
self.fields['c'].type = FieldTypes.three
class Meta:
model = Mode1
Turns out, that I do want this logic in my model class; the field types are used for more than just working out where/how to display them (though they are used for that too). I have come up with the following solution.
I defined some classes to store a set of field types:
class FieldType(object):
def __init__(self, type=None, name=None):
self._type = type
self._name = name
def getType(self):
return self._type
def getName(self):
return self._name
class FieldTypeList(deque):
def __getattr__(self,type):
for ft in self:
if ft.getType() == type:
return ft
raise AttributeError
FieldTypes = FieldTypeList([FieldType("ONE","The Name Of Field One"),FieldType("TWO","The Name Of Field Two")])
And a few models each of which has a set of mappings from field types to particular field names (In this example, fields 'a', 'b', and 'c' are of type 'ONE' and field 'd' is of type 'TWO'):
class ParentModel(models.Model):
_fieldsByType = {}
a = models.CharField()
b = models.CharField()
def __init__(self, *args, **kwargs):
super(ParentModel, self).__init__(*args, **kwargs)
for ft in FieldTypes:
self.setFieldsOfType(ft, [])
self.setFieldsOfType(FieldTypes.ONE, ['a','b'])
def setFieldsOfType(self,type,fields):
typeKey = type.getType()
if typeKey in self._fieldsByType:
self._fieldsByType[typeKey] += fields
else:
self._fieldsByType[typeKey] = fields
class ChildModel(ParentModel):
_fieldsByType = {} # not really sure why I have to repeat this attribute in the derived class
c = models.CharField()
d = models.CharField()
def __init__(self, *args, **kwargs):
super(ChildModel, self).__init__(*args, **kwargs)
self.setFieldsOfType(FieldTypes. ['c'])
self.setFieldsOfType(FieldTypes. ['d'])
I have a basic form:
class MyForm(forms.ModelForm):
class Meta:
model = ChildModel
And a custom filter to return all fields of a given type from a particular form (note, the accessing the model from the form via its Meta class):
#register.filter
def getFieldsOfType(form,type):
return form.Meta.model._fieldsByType[type.getType()]
And, finally, a template to pull it all together (the template takes MyForm and FieldTypes):
{% for type in types %}
<div id="{{type.getType}}">
{% with fieldsOfType=form|getFieldsOfType:type %}
{% for field in form %}
{% if field.name in fieldsOfType %}
<p>
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
</p>
{% endif %}
{% endfor %}
{% endwith %}
</div>
{% endfor %}