I had a difficult time understanding how to delete an item from a table within a template, using a modelform. I couldn't find a good example, so I wanted to post the code that ultimately worked.
If you require lots of forms in your project and do not want to be creating an extended template for each one I propose this solution.
Classes in the html correspond to bootstrap, you can work without them if you do not use bootstrap.
**Your model:**
class TicketItem(models.Model):
hours = models.DecimalField(decimal_places=2, max_digits=6)
day = models.DateField()
order = models.ForeignKey(Order)
tickets = models.ManyToManyField(Ticket)
Now you want to auto save m2m fields in your forms.TicketItemCreateForm:
1. inherit from m2mForm-Class
2. define m2m_field(s)
**Example:**
class TicketItemCreateForm(m2mForm):
m2m_field = 'tickets'
class Meta:
model = models.TicketItem
The admin site uses a CSS class for each kind of field so that they can be styled easily. This snippet gives ModelForms a similar feature.
See also: [James Bennett's explanation of formfield_callback](http://stackoverflow.com/questions/660929/how-do-you-change-the-default-widget-for-all-django-date-fields-in-a-modelform/661171#661171)
The important code really is just setting up the base site to use jquery and then using the javascript function to show the calendar on a widget with the .vDateField class set. The DateField modeltype automatically gets the css class .vDateField when using ModelForms.
Widget for TinyMCE 3.2.6, a WYSIWYG HTML editor for `textarea`.
**Note:**
> This snippet uses the TinyMCE package thats contains special jQuery build of TinyMCE and a jQuery integration plugin. Anyway, is easily to adapt to standard package.
Usage example:
from django.contrib.flatpages.admin import FlatpageForm
class MyFlatPageForm(FlatpageForm):
content = forms.CharField(widget=TinyMCEEditor())
[TinyMCE download page](http://tinymce.moxiecode.com/download.php)
As there is no straight way to re-produce the real tabular inline formsets you get in django-admin, here is how this template has to look like if you do it form your own formsets generated from formset factories.
Example view code:
lazy_field_options = {
'field_name_that_is_m2m': {
'queryset': YourRelatedModel.objects.filter(groups=request.user.groups.all()),
},
'field_name_that_is_fk': {
'queryset': YourOtherRelatedModel.objects.filter(slug=request_slug),
},
}
modelform = YourModelForm(jpic_field_options=lazy_field_options)
# after the modelform has called for parent __init__, it will set
# options for each field if possible.
from http://www.djangosnippets.org/snippets/792/
from utils.extjs import ExtJSONEncoder
from django.utils.safestring import mark_safe
class TestForm(forms.ModelForm):
class Meta:
model = TestModel
def as_ext(self):
return mark_safe(simplejson.dumps(self,cls=ExtJSONEncoder))
=== version 2 ===
> Parts of this code are based off of source from *davidcramer* on #django and I'd like to thank him for his assistance.
Example:
# forms.py
...
class ForumPostForm(FieldAccessForm):
class Meta:
model = ForumPost
class FieldAccess:
moderator = FieldAccessLevel(
lambda user, instance: user.get_profile().is_moderator,
enable = ('approve', 'delete', 'edit')
member = FieldAccessLevel(
lambda user, instance: user.is_active,
enable = ('edit',),
exclude = ('approve', 'delete')
...
# template
...
<form action="" method="POST">
<table>
{% for field in form %}
<tr><th>{{ field.label_tag }}</th><td>
{% if not field.field.disabled %}
{{ field }}
{% else %}
{{ field.field.value }}
{% endif %}
</td></tr>
{% endfor %}
</table>
<p><input type="submit" value="Update" /></p>
</form>
...
This class will grant or deny access to individual fields according to simple rules. The first argument must be a user object, but otherwise, this class is instantiated the same as a ModelForm.
To utilize this code, inherit your form from FieldAccessForm, and create an inner class on your form called FieldAccess. Variables added to this inner class must have the same structure as that provided by the FieldAccessLevel class, which defines an access level, and the fields which apply to that access level.
FieldAccessLevel takes as it's first argument a callable rule that validates this access level. That rule will be called with two arguments: 'user' (current user requesting access) and 'instance' (model instance in question).
The keyword arguments to FieldAccessLevel are field groups which are used to determine which fields on this form are to be enabled and/or excluded, when the current user matches this access level. The term exclude indicates fields which are not to be rendered in the form at all.
Any fields not grouped in either 'enable' or 'exclude' will be disabled by default.
Superusers are always assumed to have full access. Otherwise, if a field is not specified with the FieldAccess inner class, then it is disabled by default. In other words, all users (except superusers) are denied access to all fields, unless they are
specifically given access on a per-field basis.
It is worth mentioning that multiple access levels can apply simultaneously, giving a user access to fields from all levels for which he matches the rule.
If a user is denied access to a field, then the widget for that field is flagged as disabled and readonly. The field is also given two new attributes: a boolean 'disabled', and a 'value' containing the instanced model field. These two attributes allow a template author to have great control over the display of the form. For
example, she may render the plain text value of a field instead of the disabled widget.
The FieldAccess inner class also allows one to conditionally exclude fields from being rendered by the form. These exclusions operate very similarly to the standard Meta exclude option, except that they apply only to the access level in question.
Note: The FieldAccess inner class may be used on both the form and the model; however, generally it makes more sense on the form. If you do use FieldAccess on both the form and model, be aware that both definitions will apply simultaneously. All access levels for which the user passes the rule will be processed, regardless of whether they were found on the form or the model.
I will change a model form widget attribute without define the complete field. Because many "meta" information are defined in the model (e.g. the help_text) and i don't want to repeat this.
I found a solution: Add/change the widget attribute in the __init__, see example code.
Sometimes the order of the fields you get from a model needs to be adjusted when displaying its modelform. If it's just a few fields you can do it in the template, but what if you want to iterate over the form?
The fields are stored in a SortedDict, so you can change the order in the __init__ of the form. A bit clunky, yes.