Customizing inlineformset choice in Django template - django

I've got some forms I'm trying to customize.
I render the fields manually - and it all works fine until get to a particular field (which is an InlineFormset itself). I'm trying to customize those options but can't seem to figure out how to do so.
my forms.py looks like this:
class SummativeScoreForm(forms.ModelForm):
subdomain_proficiency_level = forms.ModelChoiceField(
empty_label="Undecided",
queryset=SubdomainProficiencyLevel.objects.none(),
widget=forms.RadioSelect,
required=False,
)
def __init__(self, request, *args, **kwargs):
super(SummativeScoreForm, self).__init__(*args, **kwargs)
if self.instance:
if request.user == self.instance.summative.employee:
self.fields["subdomain_proficiency_level"].disabled = True
self.fields[
"subdomain_proficiency_level"
].queryset = SubdomainProficiencyLevel.objects.filter(
subdomain=self.instance.subdomain
)
self.fields[
"subdomain_proficiency_level"
].label = f"""
{self.instance.subdomain.character_code}:
{self.instance.subdomain.short_description}
"""
class Meta:
model = SummativeScore
fields = "__all__"
SummativeScoreInlineFormset = inlineformset_factory(
Summative,
SummativeScore,
fields=("subdomain_proficiency_level",),
can_delete=False,
extra=0,
form=SummativeScoreForm,
)
My template for summative_score_form looks like this:
<form method="post" novalidate>
{% csrf_token %}
{% include "myapp/includes/summative_score_response_formset_snippet.html" with formset=form %}
<button type="submit" class="btn btn-primary"><i class="fal fa-clipboard-check"></i> Submit Updated Scores</button>
</form>
The summative_score_response_formset_snippet looks like this:
{{ formset.management_form }}
{% for formset_form in formset.forms %}
{% if formset_form.non_field_errors %}
<ul>
{% for error in formset_form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{% for hidden_field in formset_form.hidden_fields %}
{% if hidden_field.errors %}
<ul>
{% for error in hidden_field.errors %}
<li>
(Hidden field {{ hidden_field.name }}) {{ error }}
</li>
{% endfor %}
</ul>
{% endif %}
{{ hidden_field }}
{% endfor %}
{% for field in formset_form.visible_fields %}
{% if field.name == 'subdomain_proficiency_level' %}
<label class="form-check-label" for="{{ field.id_for_label }}">
{{ field.label }}
</label>
<ul id="{{ field.auto_id }}" class="form-check mt-2">
{% for choice in formset_form.subdomain_proficiency_level %}
<div class="form-check">
<!--
THIS IS THE PART I WOULD LIKE TO CUSTOMIZE:
Unsatisfactory (name) Lorum Ipsum (description)
Satisfactory (name) Lorum Ipsum (description)
Excellent (name) Lorum Ipsum (description)
CURRENTLY IT ONLY SHOWS THE NAME
-->
{{ choice }}
</div>
{% endfor %}
</ul>
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
{% else %}
{{ field }}
{% endif %}
{% endfor %}
{% endfor %}
My models look like this:
class SubdomainProficiencyLevel(CreateUpdateMixin):
"THIS IS THE 'UNSATISFACTORY' (name) 'LORUM IPSUM' (description)"
name = models.CharField(max_length=75)
description = models.TextField()
sequence = models.IntegerField()
class Meta:
ordering = ["sequence"]
verbose_name = "Subdomain Rank"
verbose_name_plural = "Subdomain Ranks"
def __str__(self):
"""
THIS IS WHAT IS 'CHOICE' IN THE FORM
I'm trying to edit this to add styles to the self.description on the form
"""
return f"{self.name}"
class SummativeScore(CreateUpdateMixin, CreateUpdateUserMixin):
summative = models.ForeignKey(Summative, on_delete=models.PROTECT)
subdomain = models.ForeignKey(Subdomain, on_delete=models.PROTECT)
subdomain_proficiency_level = models.ForeignKey(
SubdomainProficiencyLevel,
on_delete=models.PROTECT,
null=True,
blank=True,
)
class Meta:
ordering = ["subdomain__character_code"]
verbose_name = "SummativeScore"
verbose_name_plural = "SummativeScores"
def __str__(self):
"""Unicode representation of SummativeScore."""
return f"{self.subdomain_proficiency_level}"
The view is a Class Based FormView
class SummativeScoreFormView(
LoginRequiredMixin,
UserIsObserverOrObserveeMixin,
SingleObjectMixin,
FormView,
):
model = Summative
template_name = "myapp/summative_score_form.html"
pk_url_kwarg = "summative_id"
def get(self, request, *args, **kwargs):
summative_id = kwargs.pop("summative_id")
self.object = self.get_object(
queryset=Summative.objects.filter(id=summative_id)
)
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
summative_id = kwargs.pop("summative_id")
self.object = self.get_object(
queryset=Summative.objects.filter(id=summative_id)
)
return super().post(request, *args, **kwargs)
def get_form(self, form_class=None):
formset = SummativeScoreInlineFormset(
**self.get_form_kwargs(), instance=self.object
)
return formset
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["form_kwargs"] = {"request": self.request}
return kwargs
def form_valid(self, form):
form.save()
messages.success(self.request, "Changes were saved!")
return super().form_valid(form)
def form_invalid(self, form):
return super().form_invalid(form)
def get_success_url(self):
user_id = self.kwargs["user_id"]
summative_id = self.kwargs["summative_id"]
return reverse(
"myapp:summative_detail",
kwargs={
"user_id": user_id,
"summative_id": summative_id,
},
)
As you can see in the template - I render the SubdomainProficiencyLevel objects with the template variable {{ choice }}
I have tried doing {{ choice.description }} or {{ choice.name }} <span class="bold">{{ choice.description }}</span> but then nothing displays.
I have also tried adjusting the __str__ method on the model - which changes there work, but do not render as HTML (just as a string as expected).
What is the best way to customize that in the HTML?

I ended up creating a custom radio button class (similar to the documentation)
class CustomRadioSelect(forms.RadioSelect):
def create_option(
self, name, value, label, selected, index, subindex=None, attrs=None
):
option = super().create_option(
name, value, label, selected, index, subindex, attrs
)
if value:
option["attrs"]["description"] = value.instance.description
return option
Using that in the form:
subdomain_proficiency_level = forms.ModelChoiceField(
empty_label="Undecided",
queryset=SubdomainProficiencyLevel.objects.none(),
widget=CustomRadioSelect(),
required=False,
)
Then I could access it like this in the template:
{{ choice.data.attrs.description }}

Related

how can i get all attribute data from ManyToMany field Django?

i want to get all attribute data of articles in SetRundown forms like title, category, author via ManyToManyfield i want to show all article in Rundown form with title category and author name can anybody know how can i do this...? if i run my code with {% render_field form.articles %} then it will show the all articles title but i want the category and author name too with titles....
models.py
class Article(models.Model):
title = models.CharField(max_length=300, help_text="Short title")
category = models.ForeignKey(Category, on_delete=models.CASCADE)
author = models.ForeignKey(User, on_delete=models.CASCADE)
class SetRundown(models.Model):
pool_title = models.CharField(max_length=200)
articles = models.ManyToManyField(Article)
forms.py
from django import forms
class SetRundownForm(forms.ModelForm):
class Meta:
model = SetRundown
fields = ['pool_title', 'time_pool', 'articles']
def __init__(self, *args, **kwargs):
super(SetRundownForm, self).__init__(*args, **kwargs)
self.fields['articles'].queryset = Article.objects.filter(story_status='fr')
create_form.html
<form method="POST">{% csrf_token %}
{% render_field form.pool_title type="text" %}
{% render_field form.time_pool type="menu" %}
{% for article in form.articles %}
{{ article.title }}
{{ article.category }}
{{ article.author.username }}
{% endfor %}
<button class="btn btn-secondary" type="submit">Submit</button>
</form>
{% endblock %}
You can access the .queryset of the .field:
{% for article in form.articles.field.queryset %}
{{ article.title }}
{{ article.category }}
{{ article.author.username }}
{% endfor %}
In your SetRundownForm, you can make use of .select_related(…) [Django-doc] to avoid an N+1 problem:
class SetRundownForm(forms.ModelForm):
class Meta:
model = SetRundown
fields = ['pool_title', 'time_pool', 'articles']
def __init__(self, *args, **kwargs):
super(SetRundownForm, self).__init__(*args, **kwargs)
self.fields['articles'].queryset = Article.objects.select_related(
'author'
).filter(story_status='fr')

Django - Custom ModelMultipleChoiceField can't categorize choices based on their parent model

EDITS AVAILABLE BELOW!
My goal:
Category1
----Option1
----Option2
--Option3
Category2
----Option1
----Option2
etc.
I have a parent model (Venue) and a child model (Amenity). A venue can have many amenities.
while configuring my initial data and presenting it with {{form.as_p}} everything works as expected.
But when I try to render my own custom form, so that I can apply a loop, It doesn't pre-populate them.
Here is my template:
<form method="POST" class="ui form">
{% csrf_token %}
{% for category in categories %}
<h4 class="ui horizontal divider header">
<i class="list icon"></i>
{{category.category}}
</h4>
<p class="ui center aligned text"><u>{{category.description}}</u></p>
{% for amenity in category.amenity_set.all %}
<div class="inline field">
<label for="choices_{{amenity.id}}"></label>
<div class="ui checkbox">
<input id="choices_{{amenity.id}}" type="checkbox" value="{{amenity.id}}" name="choices">
<label><span data-tooltip="{{amenity.description}}" data-position="top left">{{amenity}}</span></label>
</div>
</div>
{% endfor %}
{% endfor %}
<button type="submit" name="submit" class="ui button primary">Next</button>
</form>
my ModelForm:
class AmenitiesForm(ModelForm):
class Meta:
model = Venue
fields = ('choices',)
choices = forms.ModelMultipleChoiceField(Amenity.objects.all(), widget=forms.CheckboxSelectMultiple,)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if kwargs.get('instance'):
initial = kwargs.setdefault('initial', {})
initial['choices'] = [c.pk for c in kwargs['instance'].amenity_set.all()]
forms.ModelForm.__init__(self, *args, **kwargs)
def save(self, commit=True):
instance = forms.ModelForm.save(self)
instance.amenity_set.clear()
instance.amenity_set.add(*self.cleaned_data['choices'])
return instance
and my views.py:
class AddAmenitiesView(LoginRequiredMixin, CreateView):
"""
AddAmenitiesView is the view that prompts the user to select the amenities of their venue.
"""
model = Venue
form_class = AmenitiesForm
template_name = 'venues/add_amenities.html'
def parent_venue(self):
"""
returns the parent_venue based on the kwargs
:return:
"""
parent_venue = Venue.objects.get(id=self.kwargs["venue_id"])
return parent_venue
def get_initial(self):
initial = super().get_initial()
initial['choices'] = self.parent_venue().amenity_set.all()
return initial
def form_valid(self, form):
venue = Venue.objects.get(id=self.kwargs['venue_id'])
form.instance = venue
# form.instance.owner = self.request.user
return super().form_valid(form)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["parent_venue"] = self.parent_venue()
context["categories"] = AmenitiesCategory.objects.all()
return context
def get_success_url(self):
return reverse('add-amenities', kwargs={'venue_id': self.object.id,})
I suppose it has to do with my template since rendering the form normally, it does prepopulate the model.
Thank you for taking the time!
EDIT:
With Raydel Miranda's answer below I managed to edit the templates for how the form gets presented:
forms.py:
class CustomAmenitiesSelectMultiple(CheckboxSelectMultiple):
"""
CheckboxSelectMultiple Parent: https://docs.djangoproject.com/en/2.1/_modules/django/forms/widgets/#CheckboxSelectMultiple
checkbox_select.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/checkbox_select.html
multiple_input.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/multiple_input.html
checkbox_option.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/checkbox_option.html
input_option.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/input_option.html
"""
template_name = "forms/widgets/custom_checkbox_select.html"
option_template_name = 'forms/widgets/custom_checkbox_option.html'
class AmenitiesForm(ModelForm):
class Meta:
model = Venue
fields = ('choices',)
choices = forms.ModelMultipleChoiceField(Amenity.objects.all(), widget=CustomAmenitiesSelectMultiple,)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if kwargs.get('instance'):
initial = kwargs.setdefault('initial', {})
initial['choices'] = [c.pk for c in kwargs['instance'].amenity_set.all()]
forms.ModelForm.__init__(self, *args, **kwargs)
def save(self, commit=True):
instance = forms.ModelForm.save(self)
instance.amenity_set.clear()
instance.amenity_set.add(*self.cleaned_data['choices'])
return instance
custom_checkbox_select.html:
{% with id=widget.attrs.id %}
<div class="inline field">
<div {% if id %} id="{{ id }}" {% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}" {% endif %}>
{% for group, options, index in widget.optgroups %}{% if group %}
<div>
{{ group }}
<div>
{% if id %} id="{{ id }}_{{ index }}" {% endif %}>{% endif %}{% for option in options %}
<div class="checkbox">{% include option.template_name with widget=option %}</div>
{% endfor %}{% if group %}
</div>
</div>
{% endif %}{% endfor %}
</div>
</div>
{% endwith %}
custom_checkbox_option.html :
<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %}>{% endif %}{% include "django/forms/widgets/input.html" %}{% if widget.wrap_label %} {{ widget.label }}</label>
As requested, also my models.py:
class TimeStampedModel(models.Model):
"""
An abstract base class model that provides self-updating
"created" and "modified" fields.
"""
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class VenueType(TimeStampedModel):
type = models.CharField(max_length=250)
description = models.TextField()
def __str__(self):
return self.type
class Venue(TimeStampedModel):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=250)
type = models.ForeignKey(VenueType, on_delete=models.CASCADE)
total_capacity = models.PositiveIntegerField(default=0)
description = models.TextField(blank=False)
contact_number = PhoneNumberField(blank=True)
contact_email = models.EmailField(blank=True)
published = models.BooleanField(default=False)
def __str__(self):
return self.name
class AmenitiesCategory(TimeStampedModel):
category = models.CharField(max_length=250)
description = models.TextField()
def __str__(self):
return self.category
class Amenity(TimeStampedModel):
category = models.ForeignKey(AmenitiesCategory, on_delete=models.CASCADE)
venues = models.ManyToManyField(Venue, blank=True)
space = models.ManyToManyField(Space, blank=True)
name = models.CharField(max_length=250)
description = models.TextField()
def __str__(self):
return self.name
class Meta:
ordering = ['category']
You said while configuring my initial data and presenting it with {{form.as_p}} everything works as expected, if so, use {{ form.choices }} in order to render that field.
<form method="POST" class="ui form">
{% csrf_token %}
{{form.choices}}
<button type="submit" name="submit" class="ui button primary">Next</button>
</form>
Then, what you need is have a custom CheckboxSelectMultiple with its own template (in case you want a custom presentation to the user), and use it in your form:
Custom CheckboxSelectMultiple could be:
class MyCustomCheckboxSelectMultiple(CheckboxSelectMultiple):
template_name = "project/template/custom/my_checkbox_select_multiple.html"
And in the form:
class AmenitiesForm(ModelForm):
# ...
choices = forms.ModelMultipleChoiceField(Amenity.objects.all(), widget=forms.MyCustomCheckboxSelectMultiple)
# ...
How to implement the template my_checkbox_select_multiple.html, is up to you.
If you're using some Django prior to 1.11, visit this link to learn about a others things you've to do in order to customize a widget template.
Django widget override template
Hope this help!

How input date in my template ListView (request.POST.get) in Django

I have a class jourListView(ListView). I want to input date in my html template and then retrieve the date to make a filter.
My class jourListView(ListView) refers to two linked tables.
I am stuck at level. How to make my code functional?
here are my models, views and template.
class jour(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE, related_name='jour')
date = models.DateField(blank=True, null=True)
commentaire = models.CharField(max_length=500, blank=True, null=True)
class Meta:
managed = False
db_table = 'jour'
unique_together = (('id'),)
verbose_name = 'JOUR'
verbose_name_plural = 'JOUR'
id = models.AutoField(primary_key=True)
def get_absolute_url(self):
return reverse("jour_detail",kwargs={'pk':self.pk})
def __str__(self):
return str(self.date) ##
class activite(models.Model):
jour = models.ForeignKey('blog.jour',on_delete=models.CASCADE, related_name='jour' )
name= models.CharField(max_length=500, blank=True, null=True)
class Meta:
managed = False
db_table = 'activite'
unique_together = (('id'),)
verbose_name = 'ACTIVITÉ'
verbose_name_plural = 'ACTIVITÉ'
id = models.AutoField(primary_key=True)
def __str__(self):
return self.type
def get_absolute_url(self):
return reverse("jour_list")
My view:
class jourListView(ListView):
model = jour
def get_context_data(self, **kwargs):
if request.method == 'POST':
date_insert = request.POST.get('date_ref')
context = super(jourListView, self).get_context_data(**kwargs)
context['count'] = self.get_queryset().count()
return context
def get_queryset(self):
return jour.objects.filter(date__lte=timezone.now()).filter(user=self.request.user).filter(date__in=date_insert)
My html template:
{% if user.is_authenticated %}
<div class="container text-center">
<form class="form-signin" id="login_form" method="post" action="/blog/list/">
{% csrf_token %}
<br>
<input type="date" name="date_ref" class="form-control" placeholder="SAISIE DATE " value="" required autofocus>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">OK</button>
</form>
</div>
<div class="centerstage">
{% for jour in jour_list %}
<div class="post">
<p class='postcontent' ><strong>Date:</strong> {{ jour.date }}</p>
<p class='postcontent' ><strong>Commentaire:</strong> {{ jour.commentaire }}</p>
<a class="btn btn-primary" href="{% url 'jour_edit' pk=jour.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>
<h1>Détails activités</h1>
</div>
-----------------
{% endfor %}
</div>
{% endif %}
I changed my view but it does not work.
class jourListView(ListView):
model = jour
template_name = "blog/list.html"
def get_context_data(self, **kwargs):
if request.method == 'POST':
date_insert = request.POST.get('date_ref')
context = super(jourListView, self).get_context_data(**kwargs)
context['count'] = self.get_queryset().count()
return context
def get_queryset(self):
queryset = jour.objects.filter(date__lte=timezone.now()).filter(user=self.request.user)
date_insert = request.POST.get('date_ref')
if date_insert:
queryset = queryset.filter(date=date_insert)
return queryset
In addition I have another error:
NameError at /blog/list/
name 'request' is not defined
Request Method:
GET
Request URL:
http://127.0.0.1:8000/blog/list/
Django Version:
2.0.2
Exception Type:
NameError
Exception Value:
name 'request' is not defined
You need to define date_insert inside the get_queryset method before you use it. For example:
class jourListView(ListView):
model = jour
def get_context_data(self, **kwargs):
if self.request.method == 'POST':
date_insert = self.request.POST.get('date_ref')
context = super(jourListView, self).get_context_data(**kwargs)
context['count'] = self.get_queryset().count()
return context
def get_queryset(self):
queryset = jour.objects.filter(date__lte=timezone.now()).filter(user=self.request.user)
date_insert = self.request.POST.get('date_ref')
if date_insert:
queryset = queryset.filter(date=date_insert)
return queryset
Once that's working, you may want to consider some further improvements
Renaming the model to Jour to match the Django style
Make sure you return a context in get_context_data for GET requests as well as POST requests.
Using LoginRequiredMixin to make sure that only logged in users can access the view
Adding checks to handle the case where date_insert isn't a valid date string.
I found the solution to my problem.
Here is the result:
I was inspired by the example in this link:
Django: Search form in Class Based ListView
My view:
class jourListView(ListView):
model = jour
template_name = "blog/list.html"
def get_context_data(self, **kwargs):
context = super(jourListView, self).get_context_data(**kwargs)
# FILTER BY CURRENT MONTH, USER
filter_ = jour.objects.filter(date__lte=timezone.now()).filter(user_id=self.request.user).order_by('-date')
if self.request.GET.get('date_ref'):
date_insert = self.request.GET.get('date_ref')
filter_ = filter_.filter(date=date_insert)
context['jourListView'] = filter_
return context
My template (blog/list.html):
{% extends 'blog/base.html' %}
{% block content %}
{% if user.is_authenticated %}
<form class="navbar-form navbar-right" action="." method="get">
{{ form.as_p }}
<input id="date_ref" name="date_ref" type="date" placeholder="Localizar..." class="form-control">
<button type="submit" class="btn btn-success form-control"><span class="glyphicon glyphicon-search"></span></button>
</form>
{% if jourListView %}
{% for select_value in jourListView %}
<div class="post">
<p class='postcontent' ><strong>Date:</strong> {{ select_value.date}}</p>
<p class='postcontent' ><strong>User ID:</strong> {{ select_value.user_id}}</p>
<p class='postcontent' ><strong>Status:</strong> {{ select_value.status}}</p>
</div>
-----------------
{% endfor %}
{% endif %}
{% endif %}
{% endblock %}

Django: ModelFormSet saving first entry only

Update:
The issue seemed to be in the coding for Django-formset. I was processing it as an inline formset and not a model formset. The answer below was also correct. Thanks!
I am working with a model formset for an intermediate model. I am using django-formset js to add additional formset fields on the template. Most everything works OK except that when I go to save the formset only the first entry is being saved to the DB. The first entry is saved and assigned correctly but any after than just disappear. It is not throwing any errors so I am not sure what is going wrong. Thanks!
The Model
class StaffAssignment(models.Model):
study = models.ForeignKey(Study, related_name='study_set', null=True, on_delete=models.CASCADE)
staff = models.ForeignKey('account.UserProfile', related_name='assigned_to_set', null=True, on_delete=models.CASCADE)
role = models.CharField(max_length=100, null=True)
assigned_on = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-role',)
def __str__(self):
return '{} is assigned to {}'.format(self.staff, self.study)
The Form:
class AddStaff(forms.ModelForm):
model = StaffAssignment
fields = ('staff',)
def __init__(self, *args, **kwargs):
super(AddStaff, self).__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].widget.attrs.update({'class': 'form-control'})
The View:
def add_staff(request, study_slug):
study = get_object_or_404(Study, slug=study_slug)
staff_formset = modelformset_factory(StaffAssignment, form=AddStaff, fields=('staff',), can_delete=True)
if request.method == 'POST':
staffList = staff_formset(request.POST, request.FILES)
if staffList.is_valid():
for assignment in staffList:
assigned = assignment.save(commit=False)
assigned.study = study
assigned.role = assigned.staff.job_title
assigned.save()
return HttpResponseRedirect(reverse('studies:studydashboard'))
else:
HttpResponse('Something is messed up')
else:
staffList = staff_formset(queryset=StaffAssignment.objects.none())
return render(request, 'studies/addstaff.html', {'staffList': staffList, 'study': study})
The Template:
<form action="{% url 'studies:addstaff' study.slug %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="box-body">
{% for list in staffList %}
<div class="form-group" id="formset">
{% if list.instance.pk %}{{ list.DELETE }}{% endif %}
{{ list.staff }}
{% if list.staff.errors %}
{% for error in list.staff.errors %}
{{ error|escape }}
{% endfor %}
{% endif %}
</div>
{% endfor %}
{{ staffList.management_form }}
</div>
<div class="box-footer">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
You are not including the primary key field in the template, as required by the docs. Add
{% for list in staffList %}
{{ list.pk }}
...
{% endfor %}

Django 'unicode' object has no attribute 'field'

I recently added crispy_forms to my django project and it caused me to get the 'unicode' object has no attribute 'field' error. Can't figure out why.
models.py
class Trip(models.Model):
location_name = models.CharField(max_length=60)
trip_date = models.DateField()
trip_rating = models.IntegerField(validators=[MinValueValidator(1),MaxValueValidator(5)])
fishing_vehicle = models.ForeignKey(FishingVehicle)
water_body = models.ForeignKey(WaterBody)
user = models.ForeignKey(User)
def __unicode__(self):
return self.location_name
views.py
#login_required
def logtrip(request):
if request.method == 'POST':
form = forms.TripForm(request.POST)
if form.is_valid():
trip = form.save(commit=False)
trip.user = request.user
trip.save()
return redirect('home')
else:
print form.errors
else:
form = forms.TripForm()
return render_to_response('logtrip.html', {'form': form}, context_instance=RequestContext(request))
forms.py
class TripForm(ModelForm):
CHOICES = (('1', 'None',), ('2', 'Below Average Amount',), ('3', 'Average Amount',), ('4', 'Above Average Amount',), ('5', 'A Lot/Limited Out',))
trip_rating = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES, label='Fish Caught')
class Meta:
model = Trip
exclude = ['user']
widgets = {'trip_date': forms.DateInput(attrs={'class':'datepicker'})}
logtrip.html
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container">
<!-- Example row of columns -->
<div class="row">
<div class="col-md-4">
<form action="/logtrip/" method="post">
{% csrf_token %}
{{ form.as_p|crispy }}
<input type="submit" value="Submit" />
</form>
</div>
</div>
</div>
{% endblock %}
Everything works correctly when I remove the |crispy filter.
For anyone else getting this error, my problem was solved by changing {{ form.as_p|crispy }} to {{ form|crispy }}.