How to Loop through enum in Django? - python

I have a model in Django
class Order(models.Model):
class Gender(models.IntegerChoices):
Male = (1,), _("Male")
Female = (2,), _("Female")
I want to send male and female in context
context["genders"] = Order.Gender
I use that in template like this
{% for gender in genders %}
<p>{{ gender }}</p>
{% endfor %}
I want to show male and female in front

Pass choices to the template, unpack and display them:
views.py
context["genders"] = Order.Gender.choices
template.html
{% for key, gender in genders %}
<p>{{ gender }}</p>
{% endfor %}

Related

FieldError at /teacher/8/. Cannot resolve keyword 'teacher' into field. Choices are: classroom, faculty, faculty_id, id, name

I reach the error in my django project when I was trying to display my view. The problem seems like related to the Course model but i honestly dont know where to begin with it.
My Teacher model:
class Teacher(models.Model):
GENDER_MALE = 0
GENDER_FEMALE = 1
GENDER_CHOICES = [(GENDER_MALE, 'Male'), (GENDER_FEMALE, 'Female')]
fname = models.TextField(max_length=20)
lname = models.TextField(max_length=20)
gender = models.IntegerField(choices=GENDER_CHOICES)
phone = models.IntegerField(default=None, blank=True, null=True)
email = models.TextField(max_length=30, default=None, blank=True, null=True)
faculty = models.ForeignKey('Faculty', on_delete=models.CASCADE )
def __str__(self):
return self.lname + ' ' + self.fname
My Course model:
class Course(models.Model):
name = models.TextField(max_length=50)
faculty = models.ForeignKey('Faculty', on_delete=models.CASCADE )
def __str__(self):
return f'{self.name}'
My Faculty model:
class Faculty(models.Model):
name = models.TextField(max_length=30)
def __str__(self):
return f'{self.name}'
My view:
def teacher(request, teacher_id):
teacher = get_object_or_404(Teacher, pk=teacher_id)
faculties = Faculty.objects.filter(teacher=teacher)
course = Course.objects.filter(teacher=teacher)
classrooms = Classroom.objects.filter(teacher=teacher)
students = Student.objects.filter(teacher=teacher)
# students = []
# for cls in classrooms:
# students.extend(Student.objects.filter(classroom=cls))
return render(request, 'polls/teacher.html', {'teacher': teacher,'faculties': faculties, 'courses':course,'classrooms':classrooms, 'students':students})
When i run the website, it point out in my view the code to be stoped at course = Course.objects.filter(teacher=teacher)
My template:
{% extends "polls/base.html" %}
{% block body %}
<h2>{{ teacher.fname }} {{ teacher.lname }}</h2>
<h3>Faculty</h3>
{% if faculties %}
{% for faculty in faculties %}
<p>{{ faculty.name }}</p>
{% endfor %}
{% else %}
<p> </p>
{% endif %}
<h3>Course</h3>
{%if courses %}
{% for course in courses %}
<p>{{ course.name }} </p>
{% endfor %}
{% else %}
<p> </p>
{% endif %}
<h3>Class</h3>
{% if classrooms %}
{% for class in classrooms %}
<p>{{ class.name }} </p>
{% endfor %}
{% else %}
<p> </p>
{% endif %}
<h3>Student</h3>
{% if students %}
{% for student in students %}
<p>{{ student.fname }} {{ student.lname }}</p>
{% endfor %}
{% else %}
<p> </p>
{% endif %}
{% endblock %}
This happens because of the following line:
course = Course.objects.filter(teacher=teacher)
The Course model has no field teacher, so you can't filter by it. To fix it there are two options:
Add a field to Course:
teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE)
and then add a Teacher to every Course that already exists (or make it null=True).
Or you can filter Course by the Faculty that the teacher is a member of, to get all courses that have a teacher that belongs to that faculty:
courses = Course.objects.filter(faculty=teacher.faculty)
Or, using reverse foreign key lookup:
courses = teacher.faculty.course_set.all()

django views many-to-many relationship field problem

During work on my 1st app(kind of cookery book where it will be possible also to create meal plans) i have a problem to addapt one field from many-to-many(through) model to my html template. Field name is 'meal' in RecipeMealPlan model.
Here are my models:
class Recipe(models.Model):
title = models.CharField(max_length=50)
cooking_time = models.IntegerField(help_text='in minutes', validators=[MinValueValidator(1), MaxValueValidator(5000)])
difficulty_level = models.IntegerField(choices=DIFFICULTY_LEVELS, default=1)
description = models.TextField()
created = models.DateTimeField(auto_now_add=True)
cuisine = models.ForeignKey('Cuisine', on_delete=models.CASCADE, null=True)
ingredient = models.ManyToManyField(Ingredient, through='IngredientRecipe')
meal_plan = models.ManyToManyField('MealPlan', through='RecipeMealPlan')
class RecipeMealPlan(models.Model):
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
meal_plan = models.ForeignKey('MealPlan', on_delete=models.CASCADE)
meal = models.IntegerField(choices=MEALS)
MEALS = (
(1, 'Breakfast'),
(2, '2nd breakfast'),
(3, 'Lunch'),
(4, 'Snack'),
(5, 'Dinner')
)
class MealPlan(models.Model):
name = models.CharField(max_length=50)
amount = models.IntegerField(validators=[MinValueValidator(4), MaxValueValidator(6)])
Here is my view created to show mealplan details on my app:
class MealPlanDetailsView(View):
def get(self, request, id):
mealplan = MealPlan.objects.get(id=id)
recipes = mealplan.recipe_set.all()
return render(request, 'diet_app/mealplan_details.html', {'mealplan': mealplan, 'recipes': recipes})
And html template:
{% extends 'diet_app/base.html' %}
{% block title %}{{ mealplan|upper }}{% endblock %}
{% block content %}
<h2>{{ mealplan|upper }}</h2>
<ul> <p>Posiłki:</p>
{% for recipe in mealplan.recipemealplan_set.all %}
<li>{{ recipe.get_meal_display}}: {{ recipe }}</li>
{% endfor %}
</ul>
{% endblock %}
Everything looks fine but link to receipe details doestnt work:
<a href="/recipe/{{recipe.id}}/">
Link works if i write the loop like this:
{% for recipe in recipes %}
<li>{{ recipe.title }} </li>
{% endfor %}
But then i dont see meal name before recipe (meal name means Breakfast, dinner etc.). I don't how to write it down to see together meal name and recipe with link to recipe details.
I succeed only when i wrote those 2 loops combined but then i see my meal plan repeated few times.
Any ideas what should i do to make it work the way i want?
recipe.id is the id of the through model RecipeMealPlan, and not Recipe, so instead of recipe.id, you need to use recipe.recipe.id.
Also for sanity's sake, you could use something like recipemealplan instead of recipe as the variable name, so:
{% for recipemealplan in mealplan.recipemealplan_set.all %}
<li>{{ recipemealplan.get_meal_display}}: {{ recipemealplan }}</li>
{% endfor %}

Reverse M2M query in Django-template

I would like to fetch the names of the speakers in the template. I marked it with xxxx. How can I do this? Thank you so much for helping out. My files:
models.py
class City(models.Model):
name = models.CharField(max_length=100)
class Speaker(models.Model):
name = models.CharField(max_length=100)
url = models.URLField(max_length=100)
city = models.ManyToManyField(City, blank=True)
views.py
def home(request):
cities = City.objects.all().exclude(speaker__isnull=True)
return render(request, "index.html", {"cities":cities})
index.html
{% for i in cities %}
{{ i.name }},xxx{{ i.speaker.name }}xxx<br>
{% endfor %}
You can access the speakers for each city as speaker_set:
{% for cit in cities %}
{{ cit.name }}
{% for spkr in cit.speaker_set.all %}
{{ spkr.name }}
<br>
{% endfor %}
{% endfor %}

Django Filter Objects and Get First Corresponding Values

I have two models.
class House(models.Model):
name= models.Charfield(max_length=100)
city= models.Charfield(max_length=100)
area= models.CharField(max_length=200)
country=models.CharField(max_length=30)
class HouseRooms(models.Model):
room_name=models.Charfield(max_length=200)
house= models.ForeignKey(House, related_name='house_hr')
room_price=models.PositiveIntegerField()
When a user run a keyword search, I want to return the name of each 'House' and the first room_price of the corresponding 'HouseRooms'. See my views below.
def my_house_search(request):
query_string= ''
rms= None
sms=None
if ('q' in request.GET) and request.GET['q'].strip():
query_string = request.GET['q']
entry_query= get_query(query_string, ['city','country',])
rms= House.objects.filter(entry_query).order_by('-pub_date')
sms= HouseRooms.objects.filter(house_id__in=rms)
return render(request, 'search/my_house_search.html',{'rms':rms, 'sms':sms, 'query_string':query_string})
Template:
{% if query_string %}
<p> Results </p>
{% if rms %}
{% for m in rms %}
<p> Name: {{ m.name }} </p>
{% empty %}
<p> No house found </p>
{% endfor %}
{% for sd in sms %}
<p> price: {{ sd.room_price }} for {{sd.room_name}}</p>
{% empty %}
<p> no price found </p>
{% endfor %}
{% endif %}
{% endif %}
With the code I wrote, it will return the name of each house and show all prices to all houses like this:
Coker House
Klopp House
$50/day for small room
$100/day for medium room
$200/day for big room
$200/day for quack room
$400/day for master room
$500/day for big room
I just want it to return the result like this.
Coker House
$50/day for small room
Klopp House
$200/day for quack room
What am I missing? How do I go about this?
You shouldn't query HouseRooms explicitly in the view. Instead, you can use the reverse relationship accessor inside your iteration in the template itself.
{% for m in rms %}
<p> Name: {{ m.name }} </p>
{% with m.house_hr.first as sd %}
{% if sd %}
<p> price: {{ sd.room_price }} for {{sd.room_name}}</p>
{% else %}
<p> no price found </p>
{% endif %}
{% endwith %}
{% empty %}
<p> No house found </p>
{% endfor %}

Django template filters 2 ManytoMany fields

I am writing an application in Django that takes all of the athletes in an event, sorts them into categories (lightweight, heavyweight, etc), and then displays the athletes in each category sorted from the top scoring athlete to the bottom scoring athlete. I can't get my template to sort the athletes into classes; either it displays all of the athletes or none.
Here are the relevant sections of my models and template:
An athlete may be in multiple categories and each category has multiple athletes. Also the categories are ordered by date.
models.py
class Entry(models.Model):
athlete = models.ForeignKey(Athlete, related_name='entries')
event = models.ForeignKey(Event, related_name='entries')
athlete_category = models.ManyToManyField(Category, related_name='entries')
athlete_score = models.CharField(max_length=20, blank=True)
placing = models.SmallIntegerField(blank=True, null=True)
class Category(models.Model):
category_name = models.CharField(max_length=100)
class CategoryOrder(models.Model):
event = models.ForeignKey(Event)
category = models.ForeignKey(Classes)
category_order = models.SmallIntegerField()
event_placings.html
{% for category in categories %}
<p>{{ category.category_name }}</p>
{% for entry in entries %}
{% for athlete_category in entry.athlete_category %}
{% if athlete_category == category %}
<p>{{ entry.athlete.first_name }} {{ entry.athlete.last_name }} - {{ entry.placing }}</p>
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
The template is supposed to list each of the categories and then all of the athletes in that category based on his placing. The output should be:
Men's Lightweight
John Doe - 1
Joe Public - 2
Women's Lightweight
Jane Doe - 1
Eva Braun - 2
etc.
Currently I get:
Men's Lightweight
Women's Lightweight
It lists the categories, but not the athletes. Where am I going wrong?
Looks like you have unnecessary loop in your template. It could be just like this:
{% for category in categories %}
<p>{{ category.category_name }}</p>
{% for entry in category.entries %}
<p>{{ entry.athlete.first_name }} {{ entry.athlete.last_name }} - {{ entry.placing }}</p>
{% endfor %}
{% endfor %}
To maintane ordering of athletes you can use Meta ordering on your Entry class or make method def athletes_ordered(self) on your Category class with something like
def athletes_ordered(self):
return self.entries.order_by('athlete_score')
In the second case you'll have to replace category.entries by category.athletes_ordered in the template.

Categories