Retrieve all related objects (reverse foreign keys) efficiently with django - mysql

I have the following models:
Car:
name = models.CharField(max_length=50)
model = models.CharField(max_length=80)
Driver:
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name='drivers')
Now I want to retrieve all of cars including related model driver data
cars = Car.objects.prefetch_related('drivers').all()
Now in my template I just want to print each car and the first driver information
{% for car in cars %}
<tr>
<td>car.name</td>
<td>car.model</td>
<td>car.drivers.first.name</td>
<td>car.drivers.first.address</td>
</tr>
{% endfor %}
However, this results in 2k+ queries for around 500 cards in my db and it takes a while to load. Am I doing something wrong, is there anyway to make this more efficient?

Related

Two models with one-to-many into single JSON dict

I have two models for 'PO Header' and 'PO Item' data like this:
class po(models.Model):
po_number = models.CharField(max_length=16, null=True)
buy_org = models.CharField(max_length=20, null=True)
supplier = models.CharField(max_length=16, null=True)
class poitm(models.Model):
po = models.ForeignKey(po, on_delete=models.CASCADE, related_name='poitm')
po_li = models.CharField(max_length=6, null=True)
matnr = models.CharField(max_length=16, null=True)
quantity = models.DecimalField(decimal_places=6, max_digits=16, null=True)
I try to create a view that returns a json object like this:
[{'po_number':'45000123','buy_org':'Org1','supplier':'Org2','itemlist':[{'po_li':'010','matnr':'123456','quantity':'12'},{'po_li':'020','matnr':'123457','quantity':'8'}]},{'po_number':'45000124','buy_org':'Org1','supplier':'Org2','itemlist':[{'po_li':'010','matnr':'123235','quantity':'15'},{'po_li':'020','matnr':'123499','quantity':'24'}]}
]
In principle a list of purchase orders with each purchase order containing a list of purchase order items.
I managed to create queryset containing the data like I need it but for performance reasons when using datatables.net with dom data I need to return the data in json format instead of looping through the queryset in the html template.
def purchaseorders(request):
polist=purchaseOrder.objects.all()
itemlist=poItem.objects.all()
for poentry in polist:
poentry.itemlist=itemlist.filter(po_id=poentry.id)
return render(request, 'purchaseorders.html', {"poitems":polist})
This seems to create a queryset with each object of a queryset. This then gives me a problem when I try to serialize it to json. Only the fields from the outer queryset are in the json result.
In the end the purpose is to generate an html page with a datatables.net table. Currently I am achieving this by looping through the inner and the outer queryset in the html page using django tags:
var data =[ {% for po in poitems %}
{ "ponumber": '{{ po.po_number}}', "buy_org": "{{ po.buy_org }}", "supplier": "{{ po.supplier }}","itemlist": [
{% for itemlist in po.itemlist %}
{ "poli": '{{ itemlist.po_li }}', "matnr": '{{ itemlist.matnr}}', "quantity": '{{itemlist.quantity}}'},
{% endfor %}
]},
{% endfor %} ]
This is a serious performance issue when I deal with a few thousand purchase orders. According to Datatables.net the correct way is to go with ajax and providing the data in json format.
I looked and tried for two solid days, turning in circles now, please help.

Django: Read image path field from MySQL

im curently making a mini product eshop for my studies. So I have the image path of products in MySQL database like LOAD_FILE(C:\\product.jpg) and I want to access the image from my Django project.
I have 2 questions. 1st, what Model Field should I use to read the image from the database's image path. And 2nd one how to read this image?
class Product(models.Model):
name = models.CharField(max_length=200, null=True)
price = models.DecimalField(max_digits=7,decimal_places=2)
image = models.ImageField(null=True, blank=True)
def __str__(self):
return self.name
#property
def imageURL(self):
try:
url = self.image.url
except:
url = ''
return url
The Models.ImageField is perfect for this. You don't need to it like this. Simply get your image in the template using {{ Product.image.url }} inside an img tag. Use If condition in templates such as {% if Product.image.url is not null %} <Show the picture> {% else %}<show some default image or show some text> {% endif %}

How to get the sum of a model field value from all the posts a user created in django base template?

I have a auth_user model, and a posts model. the posts model has fields like: id, author_id and likes. All I need print likes values related to each user in the base template. like:
{{ user.posts.likes }}
or
{{ user.user_id.posts.likes }}
This is my posts model:
class Post(models.Model):
title = models.CharField(max_length=150)
author = models.ForeignKey(User, on_delete=models.CASCADE)
likes = models.PositiveIntegerField(default=0, blank=True)
class Meta:
db_table = "posts"
def total_likes(self):
return self.likes
however it does not work, while {{ user.profile.image.url }} (profile is another model which has user_id) works perfectly.
I am importing base templates to other templates like {% extends "app/base.html" %} so I don't see any place in backend to pass the likes values
I believe the problem is that you're confusing a single Post for multiple posts and as a result there isn't an object to access. A user only has one profile, but as your code indicates they can have multiple posts as the author ForeignKey would indicate.
{{ user.post_set }} <- is a manager
{{ user.post_set.all }} <- is a queryset
{{ user.post_set.all.0 }} <- is the first item of the queryset
{{ user.post_set.all.0.likes }} <- should be the # of likes of the user's first post
Edit 1
The updated question could be restated as "how can I get the total number of likes a user has received via their posts"
There might be a way to accomplish that in the templates, but I think it's going to be difficult. I would put that number together in the view code. The key word that you're looking for is "aggregation"
https://docs.djangoproject.com/en/3.1/topics/db/aggregation/
from django.db.models import Sum
...
# inside your view
total_likes = user.post_set.all().aggregate(Sum('likes'))
Edit 2
Absolutely right #melvyn
Edit 3
In order to apply this to all pages without modifying the views you're going to have to write a context processor.
https://docs.djangoproject.com/en/3.1/ref/templates/api/#writing-your-own-context-processors
file: likes_context.py
from django.db.models import Sum
def likes_context_processor(request):
if request.user.is_authenticated:
posts = request.user.post_set.all()
total_likes = posts.aggregate(Sum('likes'))
else:
total_likes = 0
return {"total_likes": total_likes }
You'll need to locate that file appropriately and then add it to your context processors config in your settings.py
This might be helpful as well: creating my own context processor in django

Django where autoblocks data is stored?

I am working on online shop project. I have product model and it has description field, but it's empty. Description data is stored somehow with django-cms and autoblocks. I can edit that description in browser with django-cms. In the template this {% autoblock product.slug %} line is description.
In views.py, i pass product as context, but it's slug field has nothing to do with description, when i try {{ product.slug }}.
Also googled about Autoblocks, but only what managed to find out it's this model:
class Autoblock(models.Model):
composite_id = models.CharField(max_length=150)
content = PlaceholderField('content')
site = models.ForeignKey(Site)
def __unicode__(self):
return self.composite_id
All of these fields has nothing to do with description.
So my question is, how can i access that description in code?

Django form performance

I asked this in Code Review but it was rejected with a cause of "broken code." That is why I'm asking it here. This site is probably more appropriate for this question than the Code Review one.
In my app, a user can modify a course that they created. One field is a "teacher" field and the user can select a different person to be the teacher. This ForeignKey creates 138 duplicated queries and I can't figure out how to make it more efficient.
Model:
class CourseCatalog(models.Model):
course_name = models.CharField(verbose_name="Course name", max_length=50)
course_desc = models.TextField(verbose_name="Course Description")
teacher = models.ForeignKey(Teacher, blank=True, null=True,
verbose_name='Course Owner', on_delete=models.PROTECT)
...
View:
class EditCourseCatalog(UpdateView):
model = CourseCatalog
fields = ['course_name','course_desc', 'teacher']
template_name = 'school/course_catalog/new_edit_form.html'
Template:
...
<h3>Course Form</h3>
{{ user.teacher }}
<form action="" method="post">{% csrf_token %}
{{form|crispy}}
...
Here is the query from debug that is duplicated 138 times. The only difference between the queries is the school_familymember.id = 220.
SELECT `school_familymember`.`id`, `school_familymember`.`password`,
school_familymember.last_login, school_familymember.is_superuser,
school_familymember.username, school_familymember.first_name,
school_familymember.last_name, school_familymember.email.school_familymember.is_staff, school_familymember.is_active, school_familymember.date_joined, school_familymember.family_id, school_familymember.middle_name, school_familymember.family_member_role_id, school_familymember.address1, school_familymember.address2, school_familymember.city, school_familymember.state, school_familymember.zip_code, school_familymember.notes, school_familymember.gender, school_familymember.phone_number, school_familymember.cell_phone_number FROM school_familymember WHERE school_familymember.id = 220
The Teacher model is also a foreign key to the FamilyMember table and this is where I think I'm having the issue. I'm wondering if there is a way to make one single query to collect the family names and ids and then use that for the drop down list in the form. Can I do this with the built in form managers or do I have to scrap that and create the queries in the view and pass them to the form?
class Teacher(models.Model):
family_member = models.OneToOneField(FamilyMember, verbose_name='name')
notes = models.TextField(blank=True)
Create a custom model form, and in the __init__ method change the teachers queryset to use select_related to be more efficient.
class CourseCatalogForm(forms.ModelForm):
class Meta:
fields = ['course_name','course_desc', 'teacher']
def __init__(self, *args, **kwargs):
super(CourseCatalogForm, self).__init__(*args, **kwargs)
self.fields['teacher'].queryset = self.fields['teacher'].queryset.select_related('family_member')
Then use your new model form class in your view instead of specifying fields.
class EditCourseCatalog(UpdateView):
model = CourseCatalog
template_name = 'school/course_catalog/new_edit_form.html'
form_class = CourseCatalogForm