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 %}
Related
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()
This is my models.py
class report(models.Model):
Citizennumber = models.IntegerField()
Subject = models.CharField(max_length=100)
Patientfile = models.FileField(upload_to="Report")
Description= models.CharField(max_length=200)
Hospitalname= models.CharField(max_length=50, default="blank")
uploaddate = models.DateField(default=datetime.date.today)
How do I loop through this models in django templates so that if 'report.Hospitalname' has same value in multiple objects and I only want to print it once in templates?
First you should order the queryset by Hospitalname.
reports = Report.objects.order_by('Hospitalname')
Then you can use the template tag {% ifchanged %} to print the Hospitalname when it changes through iterations:
{% for report in reports %}
{% ifchanged report.Hospitalname %}
<h1>{{ report.Hospitalname }}</h1>
{% endifchanged %}
...
{% endfor %}
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.
I try to create a book database in Django. I have to do one more thing. So i have a model with CHOICES:
#model Book
class Book(models.Model):
#book types and placed
BIOGRAPHY = 1
FANTASY = 2
HISTORICAL = 3
HORROR = 4
CLASSIC = 5
YOUTH_LITHERATURE = 6
NON_FICTION = 7
MODERN_LITERATURE = 8
POETRY = 9
ADVENTURE = 10
ESSAYS = 11
ROMANCE = 12
SATIRE = 13
THRILLER = 14
DRAMA = 15
NONE = 0
B00K_CHOICES = (
(BIOGRAPHY,'Biography'),
(FANTASY, 'Fantasy/Sci-Fi'),
(HISTORICAL, 'Historical'),
(HORROR, 'Horror'),
(CLASSIC, 'Classic'),
(YOUTH_LITHERATURE, 'Youth Litherature'),
(NON_FICTION, 'Non-Fiction'),
(MODERN_LITERATURE, 'Modern Literature'),
(POETRY, 'Poetry'),
(ADVENTURE, 'Adventure'),
(ESSAYS, 'Essays'),
(ROMANCE, 'Romance'),
(SATIRE, 'Satire'),
(THRILLER, 'Thriller'),
(DRAMA, 'Drama'),
(NONE, 'No Information'),
)
book_image = models.ImageField(upload_to='book_image', blank=True, null=True)
book_name = models.CharField(max_length=255, unique=True)
book_author = models.ForeignKey(Author, on_delete=models.CASCADE)
book_types = models.IntegerField(choices=B00K_CHOICES, default= NONE)
book_description = models.TextField(null=True, blank=True)
book_pages = models.PositiveIntegerField(null=True, blank=True)
book_published = models.DateField(null=True, blank=True)
book_ratings = GenericRelation(Rating, related_query_name='book', default=NONE)
def __str__(self):
return '{}'.format(self.book_name)
And i create a simple view with display this choices:
def book_types_list(request):
book = Book.objects.all()
context = {'book': book, 'book_types': Book.B00K_CHOICES}
return render(request, 'plibrary_core/book_types_list.html', context)
I create also a html template with list of this choices:
{% extends 'base.html' %}
{% load static %}
{% block custom %}
<link rel='stylesheet' type="text/css" href="{% static 'css/background_color_styles.css' %}">
{% endblock %}
{% block title %}
<title>Book Types List | Private Library</title>
{% endblock %}
{% block content %}
<div class="container">
<div class="col">
<div id="background-color-content">
<h3>Book Types</h3>
<hr>
{% for book_type in book_types %}
<ul>
<h6>{{ book_type }}</h6>
</ul>
{% endfor %}
</div>
</div>
</div>
{% endblock %}
And in this moment, i need to have something like this - User click on the book type (for example Horror) and then he see another template with all books with only this types. I try to do something like this but it doesn't work. I don't know how to fix it. Somebody know what i need to do?;X
Firt use ul apropiatelly, with each item in a li tag, and in the correct place:
<ul> <!-- ul is outside the loop -->
{% loop %}
<li> ...</li>
{% endloop %}
</ul>
Then in your view you don't need to call the object Book.objects.all() unless you want to show all your books. It looks like you are just displaying the book choices.
def book_types_list(request):
book = Book.objects.all() # why do you need this in your view?
context = {'book': book, 'book_types': Book.B00K_CHOICES}
return render(request, 'foo/books.html', context)
Then in your template you just need to:
<ul>
{% for book_type in book_types %}
<li>
<!-- you have to handle the logic of the url here -->
{{ book_type.1 }}
</li>
{% endfor %}
</ul>
urls.py
url(r'^my_url/(?P<book_type_id>\d+)/$', my_view, name='my_url'),
with this element you get to render a select element on screen, and it will use the choices you are providing in choices, use that instead of the for loop of book types
{{ book.booktypes }}
In Django I need to filter the data and display the result like. for example
Company3(20)
Company1(12)
Company2(3)
Here "Company1,Company2,Company3" are Company Names and inside the brackets "20,12,3" are no. of jobs posted by the particular company.
models.py
class User(models.Model):
first_name= forms.CharField(max_length=30,widget=forms.TextInput())
last_name = forms.CharField(max_length=30,widget=forms.TextInput())
username = forms.CharField(max_length=30,widget=forms.TextInput())
email = forms.EmailField(widget=forms.TextInput())
password = forms.CharField(widget=forms.PasswordInput())
companyname = forms.CharField(max_length=30,widget=forms.TextInput())
class jobs(models.Model):
emp = models.ForeignKey(User, unique=False)
title = models.CharField(max_length=30)
referencecode = models.CharField(max_length=30)
jobsummary = models.TextField()
jobdetails = models.TextField()
key_skills = models.CharField(max_length=30)
I tried to give views.py is like
def search_result(request):
details=User.objects.filter(jobs__isnull=False).select_related()
return render_to_response('searchresult.html', {'details': details})
templates
<ul>
{% for d1 in details %}
<li>{{ d1.companyname }}({{ d1.count }})</li>
{% endfor %}
</ul>
Give some ideas to display the results as like above
perhaps a more efficient would look like
details = User.objects.filter(jobs__isnull=False).annotate(job_count=Count('jobs'))\
.order_by('job_count')
and then in the template
<ul>
{% for d1 in details %}
<li>{{ d1.companyname }}({{ d1.job_count }})</li>
{% endfor %}
</ul>
You should use d1.jobs_set.count instead, to get the count of jobs.
So update your template to:
<ul>
{% for d1 in details %}
<li>{{ d1.companyname }}({{ d1.jobs_set.count }})</li>
{% endfor %}
</ul>
You really should have a Company model; which would have made this a simple task with the help of the aggregation api; but for your case you'll need to do it in your view:
from collections import defaultdict
from django.shortcuts import render
def search_result(request):
company_count = defaultdict(int)
for obj in User.objects.filter(jobs__isnull=False).select_related():
company_count[obj.companyname] += 1
return render(request, 'searchresult.html', {'details': company_count})
Your template would become:
{% for company_name in details %}
{{ company_name }}({{ details.company_name }})
{% endfor %}