Python Django models execute a join query - python

I am developing an application with Django framework and I'm new to it
I need to create a query that simply joins 2 tables( type and subType ) and then later on use the result in the views the models file looks like this:
class Type(models.Model):
name = models.CharField(max_length=60)
description = models.CharField(max_length=200)
class SubType(models.Model):
name = models.CharField(max_length=60)
description = models.CharField(max_length = 200)
Type = models.ForeignKey(Type)
And in home.html file I have : (I dropped out the bootstrap code to make it more readable )
<ul>
<li ><a href="/home" >Home Page</a></li>
{% for type in all_types %}
<li >
{{ type.name }}
<ul >
--The Inner Loop--
</ul>
</li>
{% endfor %}
</ul>
I need to create an list of types and then inside each type I need to create another list which contains the subTypes of each type
I have no idea how do I have to create the query inside the views.py
def index(request):
list_all_types = #Here I have to create a join query via django models
t = loader.get_template('home.html');
c = Context({
'all_types' : list_all_types,
});
return HttpResponse(t.render(c));
So please let me know how do I have to make the query and replace the correct code with the comment part in views.py and what changes do I have to add to make to the home.html to make it enabled show all the subTypes instead of --inner loop in home.html
Thanks in advance

You don't need to do anything in the view other than get the types:
types = Type.objects.all()
In the template, you just iterate over type.subtype_set.all:
<ul>
{% for subtype in type.subtype_set.all %}
<li>{{ subtype.name }}</li>
{% endfor %}
</ul>
Note that this is well covered by the tutorial. (As is the use of the render shortcut rather than loading and rendering the template separately.)
(Actually, what I said at first was not quite true: for the sake of efficiency, you can add prefetch_related() to the Type query.)

Related

How does "template.Library()" and "get_related_name" work in django?

I'm working on a basic social media django project with the help of an udemy course. The following are the models i created:
group : models.py
register = template.Library()
class Group(models.Model):
name = models.CharField(max_length=255,unique=True)
slug = models.SlugField(allow_unicode=True,unique=True)
description = models.TextField(blank=True,default='')
description_html = models.TextField(editable=False,default='',blank=True)
members = models.ManyToManyField(User,through="GroupMember")
class GroupMember(models.Model):
group = models.ForeignKey(Group,related_name='memberships',on_delete=models.CASCADE)
user = models.ForeignKey(User,related_name='user_groups',on_delete=models.CASCADE)
post : models.py
class Post(models.Model):
user = models.ForeignKey(User,related_name='posts',on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now=True)
message = models.TextField()
message_html = models.TextField(editable=False)
group = models.ForeignKey(Group,related_name='posts',null=True,blank=True)
And the part that does not make any sense to me is the following:
post_list.html
{% for member_group in get_user_groups %}
<a href="{% url 'groups:single' slug=member_group.group.slug %}">{{ member_group.group.name
}}</a></li>
{% endfor %}
{% for other_group in get_other_groups %}
{{ other_group.name }}</li>
{% endfor %}
What does "get_user_groups","get_other_groups" and "register = template.Library()" mean here and how are they related? Also what are they trying to achieve here? I'm clueless guys, help me out.
That's an example of custom template tags. There is probably a custom_tags.py file where you created the custom template tags within a folder called template_tags that shows the work being done to create the content of those tags.
get_user_groups isn't pulling from views.py or directly referencing your models.py. Instead, it's referencing queries stored in custom_tags.py
Find a detailed breakdown here:
https://medium.com/#hiteshgarg14/creating-custom-template-tags-in-django-application-7bd1dcfeb144
This can be useful if you want to display content from a query on a variety of different views without having to redundantly insert that query into multiple functions within views.py. In this case, it looks like it will be used to insert group membership information within a variety of views by using custom tags.

querying foreignkey nested for loop django

I am trying to return a list of categories for a business, and for each category I would like to list all the items related to the category.
I was returning all of my items, not by category, but I have decided I want them sorted by category. This is what I have tried (among other attempts as well) I simply am having trouble getting the items into there categories. This is my latest attempt
In my models.py I have
Business(models.Model):
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
logo = models.CharField(max_length=300)
ItemCategory(models.Model):
name = models.CharField(max_length=50)
Item(models.Model):
name = models.CharField(max_length=100)
business = models.ForeignKey(Business)
category = models.ForeignKey(ItemCategory)
short_description = models.CharField(max_length=250)
in my views.py
def business_profile(request, business_id):
items = Item.objects.filter(business_id = business_id).select_related('itemcategory')
return render(request, 'business_profile.html', {"items": items})
in my template I am trying
{% for itemcategory in items.itemcategory_set.all %}
{{ itemcategory.name }}
{% for item in itemcategory %}
{{ item.name }} <br>
{{ item.short_description }}
{% endfor %}
{% endfor %}
From my research into other questions and reading the documents, i felt this would be right.. However from my results I can not get the correct output in my template.
Would this be the correct practice? Or should I try getting the categories first with
categories = ItemCategory.objects.filter(business = business_id)
and then possibly add a select_related('item') to process all the items for the category?
When I refer to data in the template but my model has 2 words (ItemCategory) - for instance when I move backward for a foreign key or use the model in select_related('') - would I use item_category or do you simply use itemcategory with no underscore?
UPDATE: I answered below in comment with explanation.
To list the items by category, I used #yusuf.oguntola's idea and initially got the business with .get(), then I created a queryset to get all the items. My function in views.py included
business = Business.objects.get(id = business_id)
items = business.item_set.all().order_by('category')
note: the business_id was passed in url pattern
However, the key change was in my template. I found this awesome built in functionality for templates in the django documents here
I implemented it in template like so...
{% regroup items by category as category_list %}
<ul>
{% for category in category_list %}
<li>{{ category.grouper }}
<ul>
{% for item in category.list %}
<li>{{ item.name }}<br> {{ item.short_description }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
One of the most important parts is you have to have order_by() and put the parameter of the field you are ordering by - in my case, category. If this is not included, it will simply put the items listed in chronological order and will repeat your field instance.
items = Item.objects.filter(business_id = business_id) is wrong.
You should rather say:
items = Item.objects.filter(business__id = business_id) #Notice the double underscore.
You may also rather get the business and simply say:
business.item_set.all() #This would retrieve all Item for the business.
select_related() expects a fieldname as a paramter. So use a field name that exists on the Item model. Like:
select_related('category')
Where's the meal? May be you can proceed from there though.

Django: 'Could not parse' error when creating an HTML list of names of objects from a database

I'm trying to create a website for students and professors which includes a database of courses. Each course is a model Kurs which includes among other fields the following ones, which are the professor running the course and the name of the course:
prowadzacy = models.ForeignKey(User)
nazwa = models.CharField(max_length=200)
In the shell, I can easily find all courses ran by a given professor:
>>> Kurs.objects.filter(prowadzacy__username='stefantestowy')
<QuerySet [<Kurs: Estetyka 7>]>
So in the above I learn that the professor with the username 'stefantestowy' runs one course, 'Estetyka 7'.
After a professor logs in (I'm using the built-in Django login mechanism) he or she is redirected to usersite.html, which should display information about the professor, including the list of names of the courses he or she is running. But if I want to crudely use the syntax which works in the shell to produce an HTML list, I encounter a 'cannot parse' error. Namely, my usersite.html contains the following:
Your login is {{request.user.username}} </br>
Your name is {{request.user.first_name}} {{request.user.last_name}} </br>
(...)
Here is a list of your courses: </br>
<ul>
{% for kurs in Kurs.objects.filter(prowadzacy__username=request.user.username) %}
<li>{{ kurs.nazwa }}</li>
{% endfor %}
</ul>
which leads to the following error:
Could not parse the remainder: '(prowadzacy__username=request.user.username)' from 'Kurs.objects.filter(prowadzacy__username=request.user.username)'
Just to be sure, I changed
prowadzacy__username=request.user.username
to
prowadzacy__username='stefantestowy'
that is, the name successfully used in the shell, but the 'could not parse' error persists. What am I doing wrong?
Additional detail, if it could be of any help: settings.py contains
LOGIN_REDIRECT_URL = '/polls/usersite'
urls.py's urlpatterns contains
url(r'^usersite/$', views.userviewbasic, name='usersite'),
and the relevant view in views.py is just the minimal
def userviewbasic(request):
return render(request, 'polls/usersite.html')
Thanks in advance!
{% for kurs in Kurs.objects.filter(prowadzacy__username=request.user.username) %}
<li>{{ kurs.nazwa }}</li>
{% endfor %}
This won't work in a template.
You will need to pass the filtered list to the template like so.
def userviewbasic(request):
kurs = Kurs.objects.filter(prowadzacy__username=request.user.username)
return render(request, 'polls/usersite.html', {"kurs": kurs})
And iterate over the parameter kurs in the template.
{% for kur in kurs %}
<li>{{ kur.nazwa }}</li>
{% endfor %}
You can read more about the template language in Django here: https://docs.djangoproject.com/en/1.10/ref/templates/api/#rendering-a-context

django template access to models

I am having an issue with templating system in Django, I am doing a Movie list app just to learn more about Django and I have already declared my models like following:
class Pelicula (models.Model):
nombre = models.CharField(max_length = 30)
genero = models.CharField(max_length = 20)
año = models.IntegerField()
def __str__(self):
return self.nombre
Then I have declared my view like following
def index(request):
pelicula = Pelicula.objects.all()
return render_to_response("index.html", dict(pelicula = pelicula, usuario = request.user))
So as far as i know, I am not having any trouble here
Then the problem starts on my template
<!DOCTYPE html>
<html>
<head>
<title>Mis peliculas favoritas</title>
</head>
<body>
<h1>Mis peliculas favoritas</h1>
<ol>
{% for pelicula in pelicula.object_list %}
<li>{{ pelicula.nombre }}</li>
{% endfor %}
</ol>
agregar pelicula nueva
</body>
</html>
So as you see, I am using a for loop to get all the objects in my db, I have 3, but when i run the server, the title shows up and the other link bellow named "agregar" shows up except for the movies, I am wondering if the problem is something between the "pelicula" name instead of using Pelicula as i used on declaring my model, anyway I have also changed that to Pelicula.object_list and it didn't worked anyway
I believe I am having a trouble understanding how to use the information i have through Django template tags
Thanks in advance and please forgive my grammar as I am not a native english speaker
In the view code you have pelicula = Pelicula.objects.all() which creates a list of all the abjects from the database. You then send this to the template with the same name, which means all you have to do in the template is iterate over them. Try changing the template to this:
<h1>Mis peliculas favoritas</h1>
{% if pelicula %}
<ol>
{% for item in pelicula %}
<li>{{ item.nombre }}</li>
{% endfor %}
</ol>
{% else %}
didn't find any...
{% endif %}
Part of the confusion seems to come from the fact that the template code and the view code is separate. The template doesn't know anything about the view code. The context dictionary just sets the names that can be used in the template and in the template the only names that you have available to use are the ones that you passed to it via the dictionary. The names in the view and template here are the same in this case because you set them to be the same. They aren't the same variables though, they just have the same name. In the template pelicula is already a list of objects so you don't need to do anything extra to use it in the template loop.

Making query from template

I am using jinja2 as the templating engine for django app. I wanted to make query in the template. I tried doing this:
{% for f in fs %}
{% Following.objects.filter(follows=f).count() %}
{% endfor %}
I'm passing 'fs' in variables while rendering the templates which a list.
But, its wrong. I can't do the 'query_set' call because of the way my models are defined. Here is a snippet:
class Following(models.Model):
user = models.ForeignKey(User)
follows = models.ForeignKey(F)
class F(models.Model):
name = models.CharField(max_length=50)
So, is there a possible way to do this?
If you are using jinja2 rather than the normal Django template language, what you have should work: you don't say why it doesn't.
But nevertheless, there's no need to define a separate method. You can use the automatic reverse relationship accessor:
{{ f.following_set.count() }}
You can't call methods that take parameter from django template. To overcome this, you can define method in your F model to get the required count.
For example:
class F(models.Model):
name = models.CharField(max_length=50)
def get_follow_count(self):
Following.objects.filter(follows=self).count()
Then in template you can do
{% for f in fs %}
{{ f.get_follow_count }}
{% endfor %}

Categories