I'm trying to solve following issue:
I have a web page that can see only moderators.
Fields displayed on this page (after user have registered):
Username, First name+Last name, Email, Status, Relevance, etc.
I need to display table with information of all users stored in db with this fields, but two of fields have choices, so I want to make option that moderators can choose another option and after clicking on "Update" button this fields will be updated for selected user.
I can to display all choices of "status" and "relevance" fields, and after I choose new options from dropdown db is updated.
I want to display dropdowns and option stored in db should be selected.
I've tried a lot of options, I googled a lot of my time, and searched for answer or for right direction in StackOverFlow too, but didn't find anything.
Sorry for my bad english and thank you in advance for help!
Below is part of my code:
models.py:
class Profile(models.Model):
user = models.OneToOneField(User)
status = models.IntegerField(choices=((1, _("Not relevant")),
(2, _("Review")),
(3, _("Maybe relevant")),
(4, _("Relevant")),
(5, _("Leading candidate"))),
default=1)
relevance = models.IntegerField(choices=((1, _("Unread")),
(2, _("Read"))),
default=1)
forms.py:
class CViewerForm(forms.Form):
status = forms.ChoiceField(label="",
initial='',
widget=forms.Select(),
required=True)
relevance = forms.ChoiceField(widget=forms.Select(),
required=True)
views.py:
#group_required('Managers')
#render_to('reader/view.html')
def admins_view(request):
users_list = Profile.objects.select_related('user').all()
users_dict = dict()
if request.method and request.method == 'POST':
form = CViewerForm(request.POST)
if form.is_valid():
d = form.cleaned_data
# get all selected choices
status_list = request.POST.getlist('status')
relevance_list = request.POST.getlist('relevance')
# get all usernames viewed on page
users_list = request.POST.getlist('username')
# create dict from all those lists
users_dict = zip([user for user in users_list], [status for status in status_list], [rel for rel in relevance_list])
# run through dict and do bulk update
for user_dict in users_dict:
Profile.objects.filter(user__username=user_dict[0]).update(status=user_dict[1], relevance=user_dict[2])
return HttpResponseRedirect(reverse('reader:admins_view'))
else:
form = CViewerForm()
return {'users_list': users_list,
'user': request.user,
'form': form}
template:
<form class="form-horizontal" action="" method="post" name="update-form" class="well form-inline" id="view_form">
{% csrf_token %}
{{ form.non_field_errors }}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% if user.is_staff %}
<div>
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>{% trans 'Username' %} </th>
<th>{% trans 'E-mail' %} </th>
<th>{% trans 'Status' %} </th>
<th>{% trans 'Relevance' %} </th>
</tr>
</thead>
<tbody>
{% for user in users_list %}
<tr>
<td><input type="text" READONLY name="username" value="{{ user.user.username }}"></td>
<td>{{ user.user.first_name }}</td>
<td>{{ user.user.last_name }}</td>
<td>{{ user.user.email }}</td>
<td>{{ user.get_status_display }}</td>
<td>{{ user.get_relevance_display }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
<br>
{% endif %}
<div class="form-actions">
<input type="hidden" name="_cmd_personal">
<input type="submit" class="btn btn-info" value="{% trans 'Update' %}" name="update" class="default">
</div>
</form>
Below is a solution:
forms.py (as #Liarez wrote).
template:
<form class="form-horizontal" action="" method="post" name="update-form" class="well form-inline" id="view_form">
{% csrf_token %}
{% if user.is_staff %}
{% if users_list %}
<div>
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>{% trans 'Username' %} </th>
<th>{% trans 'First name' %} </th>
<th>{% trans 'Last name' %} </th>
<th>{% trans 'E-mail' %} </th>
<th>{% trans 'CV Status' %} </th>
<th>{% trans 'CV Relevance' %} </th>
</tr>
</thead>
<tbody>
{% for user in users_list %}
<tr>
<td><input type="text" READONLY name="username" value="{{ user.user.username }}"></td>
<td>{{ user.user.first_name }}</td>
<td>{{ user.user.last_name }}</td>
<td>{{ user.user.email }}</td>
<td>
<select name="cv_status">
{% for key, status in status_choices %}
{% ifequal user.get_cv_status_display status %}
<option value="{{ user.cv_status }}" selected>{{ user.get_cv_status_display }}</option>
{% else %}
<option value="{{ key }}">{{ status }}</option>
{% endifequal %}
{% endfor %}
</select>
</td>
<td>
<select name="cv_signal">
{% for key, signal in signal_choices %}
{% ifequal user.get_cv_signal_display signal %}
<option value="{{ user.cv_signal }}" selected>{{ user.get_cv_signal_display }}</option>
{% else %}
<option value="{{ key }}">{{ signal }}</option>
{% endifequal %}
{% endfor %}
</select>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
<br>
{% endif %}
<div class="form-actions">
<input type="submit" class="btn btn-info" value="{% trans 'Update' %}" name="update" class="default">
</div>
First I recommend you as #ChrisHuang-Leaver suggested to define a new file with all the choices you need it there, like choices.py:
STATUS_CHOICES = (
(1, _("Not relevant")),
(2, _("Review")),
(3, _("Maybe relevant")),
(4, _("Relevant")),
(5, _("Leading candidate"))
)
RELEVANCE_CHOICES = (
(1, _("Unread")),
(2, _("Read"))
)
Now you need to import them on the models, so the code is easy to understand like this(models.py):
from myApp.choices import *
class Profile(models.Model):
user = models.OneToOneField(User)
status = models.IntegerField(choices=STATUS_CHOICES, default=1)
relevance = models.IntegerField(choices=RELEVANCE_CHOICES, default=1)
And you have to import the choices in the forms.py too:
forms.py:
from myApp.choices import *
class CViewerForm(forms.Form):
status = forms.ChoiceField(choices = STATUS_CHOICES, label="", initial='', widget=forms.Select(), required=True)
relevance = forms.ChoiceField(choices = RELEVANCE_CHOICES, required=True)
Anyway you have an issue with your template, because you're not using any {{form.field}}, you generate a table but there is no inputs only hidden_fields.
When the user is staff you should generate as many input fields as users you can manage. I think django form is not the best solution for your situation.
I think it will be better for you to use html form, so you can generate as many inputs using the boucle: {% for user in users_list %} and you generate input with an ID related to the user, and you can manage all of them in the view.
Better Way to Provide Choice inside a django Model :
from django.db import models
class Student(models.Model):
FRESHMAN = 'FR'
SOPHOMORE = 'SO'
JUNIOR = 'JR'
SENIOR = 'SR'
GRADUATE = 'GR'
YEAR_IN_SCHOOL_CHOICES = [
(FRESHMAN, 'Freshman'),
(SOPHOMORE, 'Sophomore'),
(JUNIOR, 'Junior'),
(SENIOR, 'Senior'),
(GRADUATE, 'Graduate'),
]
year_in_school = models.CharField(
max_length=2,
choices=YEAR_IN_SCHOOL_CHOICES,
default=FRESHMAN,
)
New method in Django 3
you can use Field.choices Enumeration Types new update in django3 like this :
from django.db import models
class Status(models.TextChoices):
UNPUBLISHED = 'UN', 'Unpublished'
PUBLISHED = 'PB', 'Published'
class Book(models.Model):
status = models.CharField(
max_length=2,
choices=Status.choices,
default=Status.UNPUBLISHED,
)
django docs
If your choices are not pre-decided or they are coming from some other source, you can generate them in your view and pass it to the form .
Example:
views.py:
def my_view(request, interview_pk):
interview = Interview.objects.get(pk=interview_pk)
all_rounds = interview.round_set.order_by('created_at')
all_round_names = [rnd.name for rnd in all_rounds]
form = forms.AddRatingForRound(all_round_names)
return render(request, 'add_rating.html', {'form': form, 'interview': interview, 'rounds': all_rounds})
forms.py
class AddRatingForRound(forms.ModelForm):
def __init__(self, round_list, *args, **kwargs):
super(AddRatingForRound, self).__init__(*args, **kwargs)
self.fields['name'] = forms.ChoiceField(choices=tuple([(name, name) for name in round_list]))
class Meta:
model = models.RatingSheet
fields = ('name', )
template:
<form method="post">
{% csrf_token %}
{% if interview %}
{{ interview }}
{% endif %}
{% if rounds %}
<hr>
{{ form.as_p }}
<input type="submit" value="Submit" />
{% else %}
<h3>No rounds found</h3>
{% endif %}
</form>
Related
I am making a Django application (for the first time in my life). As part of the application, a timetable needs to be implemented. Loading data (from the databse) into the timetable works fine:
Timetable view
The thing is that the data should be editable. So users need to be able to change the time or the yes/no parameter. I've created a POST handler in views.py, but when I press save, the page quickly reloads and the old values are back. What am I doing wrong?
models.py
class timeTable(models.Model):
key = models.CharField(max_length=200, unique=True, null=True)
value = models.CharField(max_length=200, null=True)
def __str__(self):
return self.key
views.py
#login_required(login_url='login')
def timetable(request):
timeTableFormset = modelformset_factory(timeTable, fields='__all__' ,extra=0)
timetableform = timeTableFormset(queryset=timeTable.objects.all())
if request.method == 'POST':
form = timeTableFormset(request.POST)
if form.is_valid():
form.save()
return render(request, 'VulnManager/timetable.html', {'timetableform': timetableform})
timetable.html:
<form method="POST">
{% csrf_token %}
<table id="tablePreview" class="table table-borderless table-hover">
<!--Table head-->
<thead>
<tr>
<th></th>
<th>Monday</th>
<th>Tuesday</th>
<th>Wednesday</th>
<th>Thursday</th>
<th>Friday</th>
<th>Saturday</th>
<th>Sunday</th>
</tr>
</thead>
<!--Table head-->
<!--Table body-->
<tbody>
<tr>
<th scope="row">Scan?</th>
{{ timetableform.management_form }}
{% for timeTableValue in timetableform.forms %}
{% if forloop.counter <= 7 %}
<td><select class="form-control" id="{{ timeTableValue.key.value }}" disabled="true">
<option>{{ timeTableValue.value.value }}</option>
<option>
{% if timeTableValue.value.value == "true" %}
false
{% elif timeTableValue.value.value == "false" %}
true
{% endif %}
</option>
</select></td>
{% if forloop.counter == 7 %}
</tr>
<tr>
<th scope="row">Time begin</th>
{% endif %}
{% elif forloop.counter >= 8 and forloop.counter <= 14 %}
<td><input type="text" id="{{ timeTableValue.key.value }}" onchange="validateHhMm(this);" value="{{ timeTableValue.value.value }}" readonly /></td>
{% if forloop.counter == 14 %}
</tr>
<tr>
<th scope="row">Time end</th>
{% endif %}
{% elif forloop.counter >= 15 and forloop.counter <= 21 %}
<td><input type="text" id="{{ timeTableValue.key.value }}" onchange="validateHhMm(this);" value="{{ timeTableValue.value.value }}" readonly /></td>
{% endif %}
{% endfor %}
</tr>
</tbody>
<!--Table body-->
</table>
<input type="button" class="btn-primary" id="edit" value="Edit" />
<input type="submit" class="btn-primary" id="save" value="Save" />
</form>
Your "form" variable has the formset in it, but you have to loop through the forms in the formset individually:
if form.is_valid():
for form_line in form:
form_line.save()
Your view is always rendering the "get" form for lack of a better term.
I think if you keep your variable names the same, it'll make things a bit simpler and consistent. So to explain this;
views.py
#login_required(login_url='login')
def timetable(request):
timeTableFormset = modelformset_factory(timeTable, fields='__all__' ,extra=0)
timetableform = timeTableFormset(queryset=timeTable.objects.all())
if request.method == 'POST':
form = timeTableFormset(request.POST) # This form just gets left in this block
if form.is_valid():
form.save()
return render(
request,
'VulnManager/timetable.html',
{'timetableform': timetableform} # The context includes the fresh new form, with no post data
)
What you should do, is just call it formset, because it makes life easier;
from django.contrib import messages
#login_required(login_url='login')
def timetable(request):
timeTableFormset = modelformset_factory(timeTable, fields='__all__' ,extra=0)
formset = timeTableFormset(queryset=timeTable.objects.all())
if request.method == 'POST':
formset = timeTableFormset(data=request.POST, queryset=timeTable.objects.all())
if formset.is_valid():
formset.save()
# Do something here to reassure the user it saved. Redirect or add a message
messages.success(request, 'Form saved.')
return render(
request,
'VulnManager/timetable.html',
{'timetableform': formset}
)
There's an article here which may provide some worthy reading for you; https://medium.com/#MicroPyramid/understanding-djangos-model-fromsets-in-detail-and-their-advanced-usage-131dfe66853d
I am trying to get the data from a form that is made dynamically using Flask and WTForms. To do that I've created a list that gets populated when a user opens the link, but when I try to get the data from html I only get the data from the first element of the list.
Forms:
class Details_Form(FlaskForm):
preschool_groups = []
classes = []
continue_button = SubmitField('Continuă')
def appeend_group(self):
preschool_details = Preschool_Details()
self.preschool_groups.append(preschool_details)
def appeend_class(self, choices):
class_details = Classes_Details()
class_details.class_type.choices = choices
self.classes.append(class_details)
class Preschool_Details(FlaskForm):
group_name = StringField('', validators=[DataRequired()])
group_size = IntegerField('', validators=[DataRequired()])
class Classes_Details(FlaskForm):
class_name = StringField('', validators=[DataRequired()])
class_size = IntegerField('', validators=[DataRequired()])
class_type = SelectField('', validators=[DataRequired()])
Routes:
#app.route('/detalii-scoala/<school>/<groups>/<classes>', methods=['GET','POST'])
#login_required
def school_details_page(school, groups, classes):
groups = int(groups)
classes = int(classes)
details_form = Details_Form()
details_form.classes.clear()
details_form.preschool_groups.clear()
school_db_item = db.session.query(School).join(User, User.id == School.psychologist_id).filter(User.id == current_user.id).filter(School.school==school).first()
education_types = school_db_item.education_type.split(',')
for _ in range(groups):
details_form.appeend_group()
for _ in range(classes):
details_form.appeend_class(education_types)
if details_form.continue_button.data and details_form.validate_on_submit():
for preschool_details in details_form.preschool_groups:
group = Group(name=preschool_details.group_name.data, number_of_pupils=preschool_details.group_size.data, school_id=school_db_item.id)
db.session.add(group)
for class_details in details_form.classes:
print(class_details.class_name.data)
c = Classes(name=class_details.class_name.data, number_of_students=class_details.class_size.data, class_type=class_details.class_type.data, school_id=school_db_item.id)
db.session.add(c)
db.session.commit()
details_form.classes.clear()
details_form.preschool_groups.clear()
flash('Detaliile au fost inregistrate')
return redirect(url_for('session_page'))
return render_template('detalii-scoala.html', details_form=details_form)
html:
<form action="" method="post">
{{ details_form.hidden_tag() }}
<table>
{% for preschool in details_form.preschool_groups %}
<tr>
<td><p>
{{ preschool.group_name(class_="form-control") }}<br>
{% for error in preschool.group_name.errors %}
<span class="error">[{{ error }}]</span>
{% endfor %}
</p></td>
<td><p>
{{ preschool.group_size(class_="form-control") }}<br>
{% for error in preschool.group_size.errors %}
<span class="error">[{{ error }}]</span>
{% endfor %}
</p></td>
</tr>
{% endfor %}
</table>
<br>
<table>
<tr>
<td>Denumire clasă</td>
<td>Nr. elevi înscrişi</td>
<td>Ciclul</td>
</tr>
{% for class in details_form.classes %}
<tr>
<td><p>
{{ class.class_name(class_="form-control") }}<br>
{% for error in class.class_name.errors %}
<span class="error">[{{ error }}]</span>
{% endfor %}
</p></td>
<td><p>
{{ class.class_size(class_="form-control") }}<br>
{% for error in class.class_size.errors %}
<span class="error">[{{ error }}]</span>
{% endfor %}
</p></td>
<td><p>
{{ class.class_type(class_="form-control") }}<br>
{% for error in class.class_type.errors %}
<span class="error">[{{ error }}]</span>
{% endfor %}
</p></td>
</tr>
{% endfor %}
</table>
<p>{{ details_form.continue_button(class_="btn btn-primary") }}</p>
</form>
Front end works, the only problem is when I try to add the data from thee form in the database.
The problem was that HTML fields were having the same name. To solve that I used request.form.getlist('name) to create the lists
Title is pretty self-explanatory the thing is when I try to submit a new entry django deletes the previous one. I think that the problem is in the delete function because when I disable it I can sumbit as many entries as I want. Here are my files:
Form.py
class FinancesForm(forms.Form):
description = forms.CharField(max_length = 50)
value = forms.DecimalField(max_digits = 10, decimal_places = 2)
Models.py
class Finances(models.Model):
date = models.DateField(auto_now = True)
description = models.CharField(max_length = 50)
value = models.DecimalField(max_digits = 10, decimal_places = 2)
total = models.DecimalField(max_digits = 10, decimal_places = 2, null = True)
Views.py
#login_required
def finances(request):
if request.method == 'POST':
form = FinancesForm(request.POST)
if form.is_valid():
newEntry = Finances()
newEntry.description = form.cleaned_data['description']
newEntry.value = form.cleaned_data['value']
if Finances.objects.all().aggregate(Sum('value')).values()[0] == None:
newEntry.total = newEntry.value;
else:
newEntry.total = Finances.objects.all().aggregate(Sum('value')).values()[0] + newEntry.value
newEntry.save()
return HttpResponseRedirect(reverse('finances'))
form = Finances()
entries = Finances.objects.all()
total = Finances.objects.all().aggregate(Sum('value')).values()[0]
return render(request, 'coop/finances.html', {'entries': entries, 'form':form, 'total': total})
#login_required
def fdelete(request):
if request.method != 'POST':
raise HTTP404
entryId = request.POST.get('entry', None)
entToDel = get_object_or_404(Finances, pk = entryId)
entToDel.delete()
return HttpResponseRedirect(reverse('finances'))
Finances.html
<tbody>
{% if entries %}
{% for entry in entries %}
{% if forloop.last %}
<tr>
<td>{{ entry.date }}</td>
<td>{{ entry.description }}</td>
{% if entry.value >= 0 %}
<td class="positive">{{ entry.value }}</td>
{% else %}
<td class="negative">{{ entry.value}}</td>
{% endif %}
<td>{{entry.total}}</td>
<td>
<form action="{% url "fdelete" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="entry" value="{{ entry.pk }}"/>
<input class="btn btn-primary" type="submit" value="Eliminar"/>
</td>
</tr>
{% else %}
<tr>
<td>{{ entry.date }}</td>
<td>{{ entry.description }}</td>
{% if entry.value >= 0 %}
<td class="positive">{{ entry.value }}</td>
{% else %}
<td class="negative">{{ entry.value}}</td>
{% endif %}
<td>{{entry.total}}</td>
<td></td>
</tr>
{% endif %}
{% endfor %}
{% endif %}
<tr>
<td></td>
<form class="input-group" action="{% url "finances" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<td><input class="form-control" type="text" placeholder="Concepte" name="description"/></td>
<td><input class="form-control" type="text" placeholder="Quantitat €" name="value" onkeydown="if (event.keyCode == 13) { this.form.submit(); return false; }"/></td>
</form>
<td></td>
<td></td>
</tbody>
Thanks for yout time
You have not closed your first form
<td>
<form action="{% url "fdelete" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="entry" value="{{ entry.pk }}"/>
<input class="btn btn-primary" type="submit" value="Eliminar"/>
</td>
Add closing </form> tag
In this view, I'm passing it the user's favorite albums and songs:
#login_required
def my_favorites(request):
fav_albums = request.user.album_set.all()
fav_songs = request.user.song_set.all()
return render(request, "billyjoel/my_favorites.html", {"fav_albums": fav_albums, "fav_songs" : fav_songs})
It's basically the "my account" page in my project.
I'm iterating through each of the songs ("fav_songs"), and then, for each song, iterating through all albums on which that song exists.
{% if fav_songs.count > 0 %}
...
{% for song in fav_songs %} <!-- No colon after "fav_songs" -->
...
{% for albumsong in song.albums.all %}
<BR/><I>Number {{ albumsong.sequence_num }} on
{##}{{ albumsong.name }}</I>
{% endfor %}
But while it's printing the correct number of albums, the name and id and sequence_num are all the empty-string. (This is why the url is commented out)
I noticed if I pre-pend {{ albumsong }} to it, the album's name prints out, but I'm not sure how to tell what kind of object it really is, given the limited Python available in Django templates.
How do I access the album's properties, and are there any template tags that would help me diagnose this?
(I'm noticing this is similar to a question I asked a couple weeks ago, but I'm not sure if it's connected yet.)
models.py:
from django.db import models
from django.contrib.auth.models import User
from time import time
def get_upload_file_name(instance, filename):
return "uploaded_files/%s_%s" % (str(time()).replace(".", "_"), filename)
class Album(models.Model):
OFFICIALITY = (
('J', 'Major studio release'),
('I', 'Non-major official release'),
('U', 'Unofficial'),
)
title = models.CharField(max_length=70)
description = models.TextField(max_length=500, default="", null=True, blank=True)
pub_date = models.DateField('release date')
officiality = models.CharField(max_length=1, choices=OFFICIALITY)
is_concert = models.BooleanField(default=False)
main_info_url = models.URLField(blank=False)
thumbnail = models.FileField(upload_to=get_upload_file_name, blank=True, null=True)
#virtual field to skip over the through table.
songs = models.ManyToManyField("Song", through="AlbumSong")
users_favorited_by = models.ManyToManyField('auth.User')
def __str__(self):
return self.title
class Meta:
#Default ordering is by release date, ascending.
ordering = ['pub_date']
class Song(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=500, default="", null=True, blank=True)
length_seconds = models.IntegerField()
lyrics_url = models.URLField(default="", blank=True, null=True)
albums = models.ManyToManyField("Album", through="AlbumSong")
users_favorited_by = models.ManyToManyField(User)
def get_length_desc_from_seconds(self):
if(self.length_seconds == -1):
return "-1"
m, s = divmod(self.length_seconds, 60)
h, m = divmod(m, 60)
if(h):
return "%d:%02d:%02d" % (h, m, s)
else:
return "%d:%02d" % (m, s)
def __str__(self):
return self.name
class AlbumSong(models.Model):
song = models.ForeignKey(Song)
album = models.ForeignKey(Album)
sequence_num = models.IntegerField()
class Meta:
unique_together = ('album', 'sequence_num',)
unique_together = ('album', 'song',)
def __str__(self):
return str(self.album) + ": " + str(self.sequence_num) + ": " + str(self.song)
my_favorites.html
{% extends "base.html" %}
{% load bj_filters %}
{% block title %}My Favorites{% endblock %}
{% block content %}
<H1>Billy Joel Album Browser: Favorite albums and songs for user {{ user. }} </H1>
<H1>Albums</H1>
{% if fav_albums.count > 0 %}
<TABLE ALIGN="center" WIDTH="100%" BORDER="1" CELLSPACING="0" CELLPADDING="4" BGCOLOR="#EEEEEE"><TR ALIGN="center" VALIGN="middle">
<TD><B><U>Title</U></B><BR><I><FONT SIZE="-1">(click a title to view its song list)</FONT></I></TD>
<TD><B><U>Released</U></B></TD>
<TD>Officiality</TD>
<TD>Concert</TD>
<TD>Wiki</TD>
<TD>Favorite?</TD>
{% for album in fav_albums %} <!-- No colon after "fav_albums" -->
</TR><TR>
<TD VALIGN="top">
{% if album.thumbnail %}
<img src="/static/{{ album.thumbnail }}" width="25"/>
{% else %}
<img src="/static/images/white_block.jpg" width="25"/>
{% endif %}
{{ album.title }}
{% if album.description %}
<BR/><FONT SIZE="-1"><I>{{ album.description|truncatewords:10 }}</I></FONT>
{% endif %}
<TD>{{ album.pub_date|date:"m/y" }}</TD>
<TD><IMG SRC="/static/images/{{ album.officiality|multival_to_str:"J,I,U->major,minor,unofficial,broken_image"}}.jpg" height="20"/></TD>
<TD>{{ album.is_concert|yesno:"Yes,No" }}</TD>
<TD>Wiki</TD>
<TD><I>unfavorite</I></TD>
{% endfor %}
</TR></TABLE>
{% else %}
<P><I>You have no favorite albums.</I></P>
{% endif %}
<H2>Songs</H2>
{% if fav_songs.count > 0 %}
<TABLE ALIGN="center" WIDTH="100%" BORDER="1" CELLSPACING="0" CELLPADDING="4" BGCOLOR="#EEEEEE"><TR ALIGN="center" VALIGN="middle"><TR>
<TD><B><U>Len</U></B></TD>
<TD><B><U>Name</U></B></TD>
<TD><B><U>Lyrics</U></B></TD>
</TR>
{% for song in fav_songs %} <!-- No colon after "fav_songs" -->
<TR>
<TD>{% if song.get_length_desc_from_seconds == "-1" %}
<I>n/a</I>
{% else %}
{{ song.get_length_desc_from_seconds }}
{% endif %}
</TD>
<TD>{{ song.name }}
{% if song.description %}
<BR/><FONT SIZE="-1"><I>{{ song.description|truncatewords:50 }}</I></FONT>
{% endif %}
{% for albumsong in song.albums.all %}
<BR/><I>Number {{ albumsong.sequence_num }} on {##}{{ albumsong.name }}</I>
{% endfor %}
</TD>
<TD>
{% if song.lyrics_url %}
Lyrics (direct link)
{% else %}
Lyrics (search)
{% endif %}
</TD>
</TR>
{% endfor %}
</TABLE>
{% else %}
<P><I>You have no favorite songs.</I></P>
{% endif %}
{% endblock %}
Got it. This
{% for albumsong in song.albums.all %}
<BR/><I>#{{ albumsong.sequence_num }} on
{{ albumsong.name }}</I>
{% endfor %}
needs to be changed to this
{% for albumsong in song.albumsong_set.all %}
<BR/><I>#{{ albumsong.sequence_num }} on
{{ albumsong.album.title }}</I>
{% endfor %}
I wish there were diagnostic error messages to help figure this kind of stuff out, instead of just printing empty strings.
I'd like to display a row with a label, a textfield and a checkbox for each item in a database. I've managed to do this except for the checkbox that's on a new line. I wan't:
<tr>
<td>Label</td>
<td>Input</td>
<td>Checkbox</td>
<tr>
But all I get is:
<tr>
<td>Label</td>
<td>Input</td>
</tr>
<tr>
<td>Checkbox</td>
</tr>
Anyone knows how to do this?
EDIT:
To generate the form I do:
forms.py
class AttributeForm(forms.Form):
def __init__(self, *args, **kwargs):
extra = kwargs.pop('extra')
super(AttributeForm, self).__init__(*args, **kwargs)
for key in extra:
self.fields[key] = forms.CharField(label=key, initial=extra[key], required=False)
self.fields['delete_'+key] = forms.BooleanField(label='', required=False)
views.py
attribute_form = AttributeForm(extra=user)
return render_to_response('user.html', {'username': username, 'attribute_form': attribute_form})
template (user.html)
<form action="" method="post">
<table>{{ attribute_form.as_table }}</table>
<input type="submit" value="Save attributes">
</form>
EDIT 2:
My template ended up like this:
<form action="" method="post">
<table>
<tr>
{% for field in attribute_form %}
{% cycle '<th>' '' %}{% cycle field.label_tag '' %}{% cycle '</th>' '' %}
<td>{{ field }}{{ attribute_form.field.errors }}</td>
{% if not forloop.last %}{% cycle '' '</tr><tr>' %}{% endif %}
{% endfor %}
</tr>
</table>
<input type="submit" value="Save attributes">
</form>
.as_table renders each form field in seperate table row. You should render the form manually.