Reverse M2M query in Django-template - python

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 %}

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()

Cant get data from view to django template

Problem as in title. I can not get data from view to template I get <QuerySet [{'id': 3, 'order_user_id': 13, 'ordered': False, 'total': Decimal('0.00')}]> when i use
{{ order }}. I would like to get OrderedItems and Total from Order Model. How can i do that?
views.py
def cart(request):
order = Order.objects.values()
context = {'order': order}
return render(request, 'shop/cart.html', context)
models.py:
class OrderItem(models.Model):
order_item = models.ForeignKey(Item, on_delete=CASCADE, null=True)
quantity = models.IntegerField(default=1)
class Order(models.Model):
order_user = models.OneToOneField(User, on_delete=CASCADE)
order_items = models.ManyToManyField(OrderItem)
ordered = models.BooleanField(default=False)
total = models.DecimalField(default=0.00, decimal_places=2, max_digits=11)
class Item(models.Model):
title = models.CharField(max_length=150)
price = MoneyField(
decimal_places=2,
default=0,
default_currency='USD',
max_digits=11,
)
cart.html
{% extends 'shop/base.html' %}
{% block content %}
<div class="container">
{% include 'shop/navbar.html' %}
<div>
{{order}}
{{order.total}}
</div>
</div>
{% endblock content %}
You have to use for loop to iterate over the items.
First, change this: order = Order.objects.values() to order = Order.objects.all()
{% extends 'shop/base.html' %}
{% block content %}
<div class="container">
{% include 'shop/navbar.html' %}
<div>
{% for item in order %}
<li>User: {{ item.order_user }}<li/>
<li>Items:
{% for order_item in item.order_items %}
<li>{{ order_item }}</li>
{% endfor %}
<li/>
<li>Is ordered: {{ item.ordered }}<li/>
<li>Total: {{ item.total }}<li/>
{% endfor %}
</div>
</div>
{% endblock content %}

python django how to only show the information about an individual employee when I click on his name

I'm new to python django, trying to create an employee records project, on the django admin site I added some employees and their information, on the django site, I had the hyperlink for the individual employee, but when I click on the individual name, the next page comes all the employees information instead of the particular one, how can I only make it come out the information of the employee I click? Please help, thank you!
models.py
from django.db import models
import datetime
class Employee(models.Model):
'''An employee's information.'''
full_name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
city = models.CharField(max_length=100)
state = models.CharField(max_length=100)
zip = models.CharField(max_length=100)
hire_date = models.DateField(default=datetime.date.today)
def __str__(self):
'''Return a string representation of the model.'''
return self.full_name
return self.address
return self.city
return self.state
return self.zip
return self.hire_date
views.py
from django.shortcuts import render
from .models import Employee
def index(request):
'''The home page for employee_record.'''
return render(request, 'employee_records/base.html')
def employees(request):
'''Shows all employees'''
employees = Employee.objects.order_by('full_name')
context = {'employees': employees}
return render(request, 'employee_records/employees.html', context)
def employee(request, employee_id):
'''Show a single employee and all his records.'''
employee = Employee.objects.get(id=employee_id)
objects = Employee.objects.all
context = {'employee': employee, 'objects': objects}
return render(request, 'employee_records/employee.html', context)
urls.py
'''Defines URL patterns for employee_records.'''
from django.urls import path
from . import views
app_name = 'employee_records'
urlpatterns = [
# Home page
path('', views.employees, name='employees'),
# Detail page for a single employee
path('employees/<int:employee_id>/', views.employee, name='employee'),
]
base.html
<p>
Employee-Record
</p>
{% block content %}{% endblock content %}
employees.py
{% extends 'employee_records/base.html' %}
{% block content %}
<ul>
{% for employee in employees %}
<li>
{{ employee }}
</li>
{% empty %}
{% endfor %}
</ul>
{% endblock content %}
employee.html
{% extends 'employee_records/employees.html' %}
{% block content %}
<p>{{ employee }}
{% for object in objects %}
<li>{{ object.full_name }}</li>
<li>{{ object.address }}</li>
<li>{{ object.city }}</li>
<li>{{ object.state }}</li>
<li>{{ object.zip }}</li>
<li>{{ object.hire_date }}</li>
{% empty %}
<li>There are no records for this employee yet.</li>
{% endfor %}
</p>
{% endblock content %}
models.py
# you should have only one return statement
class Employee(models.Model):
'''An employee's information.'''
full_name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
city = models.CharField(max_length=100)
state = models.CharField(max_length=100)
zip = models.CharField(max_length=100)
hire_date = models.DateField(default=datetime.date.today)
def __str__(self):
'''Return a string representation of the model.'''
return self.full_name
views.py
# you have to change employee function
def employee(request, employee_id):
'''Show a single employee'''
try:
employee = Employee.objects.get(id=employee_id)
except Employee.DoesNotExist:
employee = None
context = {'employee': employee}
return render(request, 'employee_records/employee.html', context)
employee.html
{% extends 'employee_records/employees.html' %}
{% block content %}
{% if employee %}
<ul>
<li>{{ employee.full_name}}</li>
<li>{{ employee.address}}</li>
<li>{{ employee.city}}</li>
<li>{{ employee.state}}</li>
<li>{{ employee.zip}}</li>
<li>{{ employee.hire_date}}</li>
</ul>
{% endif %}
{% endblock content %}
other way to achieve it is with a built in get_object_or_404 method
individual view
from django.shortcuts import get_object_or_404
def employee(request, employee_id):
employee = get_object_or_404(Employee, employee_id=employee_id)
context = {'employee': employee}
return render(request, 'employee_records/employee.html', context)

How to retrieve object that a different object is linked to in template? Django

I have a quiz model and a view where I'm displaying a list of all the quizzes on the page. I want to show the score that they got alongside each quiz. Currently, I have a score model that links to each quiz and the user that took the quiz. I want to do something like Score.objects.filter(user=request.user, quiz=quiz).get_percentage() to show the percentage achieved for that quiz. However this doesn't work in template code of course.
def learn(request): #Quiz Screen
context = {
'quizzes':Quiz.objects.all(),
'scores':Score.objects.filter(user=request.user),
}
return render(request, 'quiz_app/learn.html', context)
{% extends "quiz_app/base.html" %}
{% block content %}
New Quiz
{% for quiz in quizzes %}
<a id="quiz-anchor" href="{% url 'quiz-detail' quiz.id %}">
<article class="quiz-thumbnail-large">
<h2>{{ quiz.title }}</h2>
<h3>{{ quiz.question_amount }} Questions</h3>
<p>Score: {{ quiz.score.get_percentage }}%</p>
</article>
</a>
{% endfor %}
{% endblock content %}
class Quiz(models.Model):
title = models.CharField(max_length=100) #or TextField
#slug = models.SlugField(max_length=200, default=1) #url
video_link = models.CharField(max_length=100, default="https://www.youtube.com/watch?v=p60rN9JEapg")
question_amount = models.IntegerField()
author = models.ForeignKey(User, default=1, on_delete=models.CASCADE, related_name='quiz_author',)
date_created = models.DateTimeField(default=timezone.now)
class Meta:
verbose_name_plural = "Quizzes"
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('quiz-detail', kwargs={'pk': self.pk})
class Score(models.Model):
quiz = models.ForeignKey(Quiz, default=1, on_delete=models.CASCADE)
user = models.ForeignKey(User, default=1, on_delete=models.CASCADE)
correct_answers = models.IntegerField()
incorrect_answers = models.IntegerField()
def __str__(self): #returns as a/b
score = str(self.correct_answers) + '/' + str(self.get_total_answers())
return score
def add_correct_answers(self, amount):
self.correct_answers = self.correct_answers + amount
self.save()
def add_incorrect_answers(self, amount):
self.incorrect_answers = self.incorrect_answers + amount
self.save()
def get_total_answers(self):
total = self.correct_answers + self.incorrect_answers
return total
def get_percentage(self):
percentage = round(self.correct_answers / self.get_total_answers() * 100)
return percentage
So as you have a foreign Key relationship between Quiz and Score, you can have multiple scores for a single quiz, therefore you should use the backward relationship from the quiz model like this:
{% extends "quiz_app/base.html" %}
{% block content %}
New Quiz
{% for quiz in quizzes %}
<a id="quiz-anchor" href="{% url 'quiz-detail' quiz.id %}">
<article class="quiz-thumbnail-large">
<h2>{{ quiz.title }}</h2>
<h3>{{ quiz.question_amount }} Questions</h3>
{% for score in quiz.score_set.all %}
<p>Score: {{ score.get_percentage }}%</p>
{% endfor %}
</article>
</a>
{% endfor %}
{% endblock content %}
Edit
This is a quick fix:
{% extends "quiz_app/base.html" %}
{% block content %}
New Quiz
{% for quiz in quizzes %}
<a id="quiz-anchor" href="{% url 'quiz-detail' quiz.id %}">
<article class="quiz-thumbnail-large">
<h2>{{ quiz.title }}</h2>
<h3>{{ quiz.question_amount }} Questions</h3>
{% for score in quiz.score_set.all %}
{% if score.user == request.user %}
<p>Score: {{ score.get_percentage }}%</p>
{% endif %}
{% endfor %}
</article>
</a>
{% endfor %}
{% endblock content %}
But it's not a good idea, because you will retrieve all the score for all the users first, and then filter them; It's better to use a template tag here.

How to show sub-sub category of sub-category in Django?

I have the following models:
class TutorialCategory(models.Model):
category_title = models.CharField(max_length=150)
category_summary = models.CharField(max_length=150)
category_slug = models.SlugField(default=1, blank=True)
class TutorialSeries(models.Model):
series_title = models.CharField(max_length=200)
series_maincategory = models.ForeignKey(
TutorialCategory, default=1, on_delete=models.SET_DEFAULT)
series_summary = models.CharField(max_length=200)
class Tutorial(models.Model):
tutorial_title = models.CharField(max_length=150)
tutorial_content = models.TextField()
tutorial_published = models.DateTimeField(
"date Published", default=datetime.now())
tutorial_series = models.ForeignKey(
TutorialSeries, default=1, on_delete=models.SET_DEFAULT)
tutorial_slug = models.SlugField(default=1, blank=True)
As shown above TutorialCategory is main category, TutorialSeries is sub category and Tutorial is sub-sub-category. I created a simple view that shows sub categories of main categories, but don't know how to show the sub-sub categories of sub category.
Please check out views.py and urls.py if you can improve its quality and if there is an easy and better way of doing it. Anyway, this is view:
def single_slug(request, single_slug):
matching_series = TutorialSeries.objects.filter(
series_maincategory__category_slug=single_slug)
series_urls = {}
for i in matching_series.all():
part_one = Tutorial.objects.filter(
tutorial_series__series_title=i.series_title).earliest("tutorial_published")
series_urls[i] = part_one.tutorial_slug
return render(request, 'tutorial/sub-category.html', context={
"tutorial_series": matching_series,
'part_ones': series_urls
})
urls here:
urlpatterns = [
path('', views.home_page, name='home'),
path('tutorial/<int:id>/', views.tutorial_detail, name='tutorial_detail'),
path('<single_slug>/', views.single_slug, name='single_slug'),
]
the template that shows sub-category of main category:
{% for tut, partone in part_ones.items %}
<div class="card">
<div class="card-body">
<h5 class="card-title">{{ tut.series_title }}</h5>
<p>{{ tut.series_summary }}</p>
Read more
</div>
</div>
{% endfor %}
Please help me how to do it and if you know any better way of doing it please let me know and help me. Thank you so much in advance.
edit: #ruddra
I changed views.py to this passing matching_series
def single_slug(request, single_slug):
matching_series = TutorialSeries.objects.filter(
series_maincategory__category_slug=single_slug)
series_urls = {}
for i in matching_series.all():
part_one = Tutorial.objects.filter(
tutorial_series__series_title=i.series_title).earliest("tutorial_published")
series_urls[i] = part_one.tutorial_slug
return render(request, 'tutorial/sub-category.html', context={
"matching_series": matching_series,
'part_ones': series_urls
})
and replaced the previous template with yours. template here:
{% for tutorial in matching_series %}
{% for sub_cat in tutorial.tutorialseries_set.all %}
{{ sub.series_title }}
{% for sub_sub_cat in sub.tutorial_set.all %}
{{ sub_sub_cat.tutorial_title }}
{% endfor %}
{% endfor %}
{% endfor %}
You can try like this:
{% for sub_cat in matching_series %}
{% for sub_sub_cat in sub_cat.tutorial_set.all %}
{{ sub_sub_cat.tutorial_title }}
{% endfor %}
{% endfor %}
Here I am assuming matching_series is being passed through context from view in single_slug. Then I am using backward relation between different models to fetch the data.
Explanation: Assuming there is object named tutorial_category which is instance of TutorialCategory. As there is ForeignKey from TutorialSeries to TutorialCategory, I can use tutorial_category.tutorialseries_set.all() or .filter() etc to fetch the tutorial series from tutorial_category object( As I am rendering it in template, I removed parenthesis after all). Similarly I fetch Tutorial from TutorialSeries.

Categories