How to split render django's ModelMultipleChoiceField in template file? - django

I want to make (ordered) Song list form.
models.py
class Song(models.Model):
title = models.CharField(max_length=60)
class List(models.Model):
title = models.CharField(max_length=100)
songs = models.ManyToManyField(Song, through='Order')
class Order(models.Model):
list = models.ForeignKey(List)
song = models.ForeignKey(Song)
order = models.IntegerField(unique=True)
and,
forms.py
class ListEditForm(forms.Form):
title = forms.CharField(
label='List Title',
widget=forms.TextInput(attrs={'size':100})
)
songs = forms.ModelMultipleChoiceField(
label= 'Song Order',
required= False,
widget=forms.CheckboxSelectMultiple,
queryset= Song.objects.none()
)
and then,
ListEditForm.py
<form id="edit-form" method="post" action="/list/edit/">
<p>
{{ form.title.errors }}
{{ form.title.label_tag }}
{{ form.title }}
</p>
<p>
{% for song in form.songs %}
{{ song.label_tag }}
{{ song }}
{% endfor %}
</p>
<input type="submit" value="save" />
</form>
This template raises following error:
Caught an exception while rendering: 'BoundField' object is not iterable
How do I split render each form field in 'form.songs'?

You're getting a not iterable error because ListEditForm.songs is a single field that contains a list of song choices, rather than a list of individual song fields. From your description I'm not sure how you wanted the list to be rendered.
I would suggest looking into using a Django formset. http://docs.djangoproject.com/en/dev/topics/forms/formsets/

Related

Django Model Objects cannot seen in Django Template

Rendered django model object cannot give any output in template. My Code is:
model.py:
class MyModel(models.Model):
address = models.GenericIPAddressField(
max_length=15,
verbose_name=_('address')
)
Path = models.CharField(
max_length=300,
verbose_name='path',
)
activate = models.CharField(max_length=5, default='off', )
views.py:
class MyView(ListView):
model = models.MyModel.objects.all()[0]
template_name = '../on_off.html'
context_object_name = 'obj_list'
admin.py:
class MyAdmin(admin.ModelAdmin):
list_display = ('address', 'Path', )
exclude = ('activate', )
change_list_template = '../on_off.html'
on_off.html:
{% extends 'admin/change_list.html' %}
{% block object-tools %}
{% if obj_list %}
<form id="on_off_status" method="POST">
<label id="onoff" class="switch">
{% csrf_token %}
<input type="checkbox" id="togBtn" value=" {{ obj_list.activate }} ">
<div class="slider round"></div>
</label>
</form>
{% endif %}
...
In Django model, the system accepts only one object and I want to give to toggle switch button value in template using activate field in MyModel model. But it is not rendered in template, I couldn't get any object data even if I try <h1> {{ obj_list }} </h1>, it turns <h1> </h1> . Any help or suggestion appreciated.
Render the field manually
<label id="onoff" class="switch">
{% csrf_token %}
{{ obj_list.activate }}
<div class="slider round"></div>
</label>
Instead of using the views.py, django-admin provide a function named changelist_view(). Now it is working, I deleted the funtion in views.py and I added changelist_view() function to my admin.py looks like:
class MyAdmin(admin.ModelAdmin):
list_display = ('address', 'Path',)
exclude = ('activate',)
change_list_template = '../nfs_on_off.html'
def changelist_view(self, request, extra_context=None):
object = self.model.objects.all()
context={
'obj_list': object,
}
return super(MyAdmin, self).changelist_view(request, context)

Django template reading individual keys from dictionary instead of iterating

I'm having trouble passing data from a Django model to a a Django template. The code below works, but I'm it seems clunky and I'm a bit confused by why it works. I'm trying to read a random entry from my database for each one of my models. I then want to print the data from each model on my home template. I thought I could add each model to a single dictionary, then iterate through the dictionary of dictionaries in my template, but that didn't work ( I know the models have different fields, but I was planning on working around that later). I played around with it for a while, and realized that my for loops weren't actually iterating through the dictionary of dictionaries, but was actually just reading each individual entry in the dictionary through its key. Additionally, it doesn't seem like the for loops are doing any iterating, since I can access the fields of my model directly with the .field notation. This seems to be the only method that works but I'm still not entirely sure why. Could anyone clarify why this works, or let me know if there is a more straightforward way of reading the dictionary? Here is the function that renders the template:
def home(request):
# Get a random song and album from the database
randomSong = randint(1,501)
randomAlbum = randint(1,501)
songChoice = Songs.objects.filter(rank = randomSong).values()
albumChoice = Albums.objects.filter(rank = randomAlbum).values()
entry = {'ent': songChoice, 'entry': albumChoice}
return render(request,'rollingStone/home.html', entry)
And this is the template that home renders:
{% extends "rollingStone/layout.html" %}
{% block title %}
A Record A Day
{% endblock %}
{% block body %}
{% for song in ent %}
<div class = "container">
<div class = "row">
<h1>#{{song.rank}}: {{song.title}} </h1>
</div>
<div class = "row ">
<div class = "col-sm">
<img src = {{song.cover}} alt = "No cover">
</div>
<div class = "col-sm">
<p>
<strong>{{song.releaseInfo}}</strong>
<br>
<br>
<strong>Artist:</strong> {{song.artist}}
<br>
<strong>Writer(s):</strong> {{song.writers}}
<br>
<strong>Producer(s):</strong> {{song.producer}}
<br>
<br>
{{song.description}}
</p>
</div>
</div>
</div>
{% endfor %}
{% for album in entry %}
<div class = "container">
<div class = "row">
<h1>#{{album.rank}}: {{album.title}} </h1>
</div>
<div class = "row ">
<div class = "col-sm">
<img src = {{album.cover}} alt = "No cover">
</div>
<div class = "col-sm">
<p>
<strong>Artist:</strong> {{album.artist}}
<br>
<strong>Label:</strong> {{album.label}}
<br>
<strong>Release Year:</strong> {{album.year}}
<br>
<br>
{{album.description}}
</p>
</div>
</div>
</div>
{% endfor %}
{% endblock %}
And the definitions of the models themselves, if that helps:
# Model to store a Rolling Stone top 500 song
class Songs(models.Model):
rank = models.IntegerField()
artist = models.CharField(max_length=50)
title = models.CharField(max_length=50)
cover = models.ImageField()
writers = models.CharField(max_length=100)
producers = models.CharField(max_length=100)
releaseInfo = models.CharField(max_length=100)
description = models.TextField()
used = models.BooleanField(default=False)
def __str__(self):
return self.title
# Model to store a Rolling Stone top 500 album
class Albums(models.Model):
rank = models.IntegerField()
artist = models.CharField(max_length=50)
title = models.CharField(max_length=50)
cover = models.ImageField()
label = models.CharField(max_length=100)
year = models.CharField(max_length=100)
description = models.TextField()
used = models.BooleanField(default=False)
def __str__(self):
return self.title
It works because you are filtering and retrieving .values(), which sort of means it's returning a queryset of probably 1.
In other words {% for song in ent %} is equivalent to for song in ent_queryset.
If you changed the filter to retrieve multiple songs/albums, you would see more than one song/album show up.
If you just want to retrieve one song/album, then you would need to do something like:
songChoice = Songs.objects.filter(rank = randomSong).values().first()
albumChoice = Albums.objects.filter(rank = randomAlbum).values().first()
entry = {'ent': songChoice, 'entry': albumChoice}
return render(request,'rollingStone/home.html', entry)
And then in your template you can access them directly:
{{ ent }} # this is your song obj
{{ ent.writers }}
{{ ent.artist }}
{{ entry }} # this is your album entry

Modeling a restaurant menu with django

I am creating a website with a collection of menus from restaurants in my town (since none of them seem to be on grubhub or the internet). I am having trouble creating a model for this. As you know every restaurant menu has sections(I.e Appetizers, Chicken, Steak) and entries under each section(I.e under Appetizers: Mozzarella Sticks, Nachos, etc.) I am trying to create a Menu model so that each section of the menu and all of its entries can automatically fill a template:
<h1>{{section}}</h1> <!--I.e:"Appetizers"-->
<p>{{food}} </p><!--I.e:"Mozzarella Sticks"-->
<p>{{ food_details }}</p>
With the above template, I can use a loop to loop through each section, then another inner loop to loop through each food and food_details belonging to that specific section, but I am not sure how to model this properly:
from django.db import models
class Restaurant(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
phoneNumber = models.CharField(max_length=10)
def __str__(self):
return "%s the place" % self.name
class Menu(models.Model):
restaurant = models.OneToOneField(
Restaurant,
on_delete=models.CASCADE,
primary_key=True,
)
# not sure how to build menu fields
#if I do the following each menu will only have one of these fields, which will not work:
section = models.CharField(max_length=50)
food = models.CharField(max_length=50)
food_details = models.CharField(max_length=200)
How can I create a model of a menu that has multiple section's and multiple food and food_details entries under each section? I hope this made sense, let me know if there is anything I can add and thanks in advance for any help.
You could try something like this:
# models.py
FOOD_TYPES = (
('appetizer', 'appetizer'),
('entree', 'entree'),
('dessert', 'dessert'),
)
class FoodItem(models.Model):
name = models.CharField(max_length=30)
description = models.CharField(max_length=100)
type = models.CharField(max_length=100, choices=FOOD_TYPES)
class Menu(models.Model):
restaurant = models.OneToOneField(
Restaurant,
on_delete=models.CASCADE,
primary_key=True,
)
food_items = models.ManyToManyField(FoodItem)
In a view:
# views.py
class Restaurant(TemplateView):
model = Restaurant
template_name = 'name'
...
def get_context_data
context = super(Menu, self).get_context_data(**kwargs)
restaurant = Restaurant.objects.get(name='McDonalds')
context['restaurant'] = Restaurant.objects.get(name='McDonalds')
context['menu'] = Menu.objects.get(restaurant=restaurant)
return context
In the template:
# template.html
<h1>{{ restaurant.name }}</h1>
<h2>Menu</h2>
{% for item in menu.food_items %}
{% if item.type = 'appetizer' %}
<p>
{{ item.name }}
{{ item.description }}
{{ item.type }}
</p>
{% else %}
<p>No appetizers</p>
{% endif %}
{% if item.type = 'entree' %}
<p>
{{ item.name }}
{{ item.description }}
{{ item.type }}
</p>
{% else %}
<p>No entrees</p>
{% endif %}
{% if item.type = 'dessert' %}
<p>
{{ item.name }}
{{ item.description }}
{{ item.type }}
</p>
{% else %}
<p>No dessert</p>
{% endif %}
{% endfor %}

Display foriegnkey fields in Django template for a CreateView

I am trying to display a checklist in the CreateView using the values in the ForeignKey fields for descriptions.
models.py
class Structure(models.Model):
name = models.CharField(max_length = 30)
description =models.CharField(max_length = 300, null=True, blank=True)
def __str__(self):
return self.name
class SelectedFramework(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
structure = models.ForegignKey(Structure)
selected = models.BooleanField(default = False)
views.py
class FrameworkCreateView(generic.CreateView):
model = SelectedFramework
fields =['structure', 'selected']
template_name = 'catalogue/structure.html'
def form_valid(self, form):
form.instance.user = self.request.user
return super(FrameworkCreateView, self).form_valid(form)
structure.html
{% extends 'catalogue\base.html' %}
{% block container %}
<h2>{% block title %}Structures{% endblock title %}</h2>
<form action="" method="post">
{% csrf_token %}
{% for field in form %}
<div class="col-sm-10">{{form.structure}} {{form.selected}}</div><br>
{% endfor %}
</div>
</form>
{% endblock %}
The code above works but will display the ForeignKey 'structure' as a dropdown list with the values of __str__. Is there a way to display string for structure.name and structure.description with the checkbox from selected in the CreateView?
In your template use:
{{ form.structure.name }}
{{ form.structure.description}}
You can write custom form, override the save method and create Structure object manually there:
class FrameworkForm(forms.ModelForm):
structure_name = forms.CharField(required=True)
structure_description = forms.CharField(required=False)
class Meta:
model = SelectedFramework
fields = [
'structure_name', 'structure_description', 'selected'
]
def save(self, commit=False):
instance = super(FrameworkForm, self).save(commit=False)
structure = Structure(
name=self.cleaned_data.get('structure_name'),
description=self.cleaned_data.get('structure_description')
)
structure.save()
instance.structure = structure
instance.save()
return instance
Also add form_class = FrameworkForm to your view instead of fields = ['structure', 'selected']
EDIT:
Perhaps you want something like this:
<ul>
{% for structure in form.fields.structure.choices.queryset %}
<li>{{ structure.name }} - {{ structure.description }}</li>
{% endfor %}
</ul>
If you want to get fields by iterating in the template. You have to use-
{% for field in form %}
{{ field }}
{% endfor %}
don't have to use any dot notation to get the field. If you want to get the label of the field you can use {{ field.label}} usually before {{field}}

Django - why don't my radio buttons render?

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
forms.py
class TripForm(ModelForm):
class Meta:
model = Trip
exclude = ['user']
CHOICES = (('1', 'First',), ('2', 'Second',))
trip_rating = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)
logtrip.html
{% extends "base.html" %}
{% 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 }}
<input type="submit" value="Submit" />
</form>
</div>
</div>
</div>
{% endblock %}
My form renders without error, but instead of getting a pair of radio buttons for the trip_rating field, a number field is rendered,
<input id="id_trip_rating" name="trip_rating" type="number">
How can I get those radio buttons?
The form field in the modelform is a class level property, and not a Meta property
class TripForm(ModelForm):
CHOICES = (('1', 'First',), ('2', 'Second',))
trip_rating = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)
class Meta:
model = Trip
exclude = ['user']
should do the trick.