Reduce the time consumed by api in Django Rest Framework - django

These are the models that I created i.e. Video, Tag, Category, Exercise and Package_Exercise respectively. and i want to fetch data based on the object in package exercise and fetch all the data from the Exercise i.e. video url, tag and category of each exercise. I wrote the code but its taking too much time how do I reduce the time taken by the code? What should be the best approach to handle these kind of situations? What would be the best approach based on the time complexity.
class Video(models.Model):
video = models.FileField(upload_to='videos_uploaded',null=False,validators=[FileExtensionValidator(allowed_extensions=['MOV','avi','mp4','webm','mkv'])])
name = models.CharField(max_length=100)
thumbnail = models.ImageField(upload_to="video_thumbnails",null=False)
description = models.TextField(max_length=200)
created_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE, related_name='videos_created_by')
updated_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE, related_name='videos_updated_by')
def __str__(self):
return self.name
class Tag(models.Model):
name=models.CharField(max_length=100)
def __str__(self):
return self.name
class Category(models.Model):
title=models.CharField(max_length=200)
created_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE,
related_name='catagoery_created_by')
updated_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE,
related_name='catagoery_exercise_updated_by')
def __str__(self):
return self.title
class Exercise(models.Model):
name=models.CharField(max_length=100,null=False)
description=models.TextField(max_length=300,null=False)
video=models.ForeignKey(Video,on_delete=models.CASCADE,null=False)
category=models.ForeignKey(Category,on_delete=models.CASCADE,null=False)
tag=models.ManyToManyField(Tag,null=False)
created_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE,
related_name='exercise_created_by', null=False)
updated_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE,
related_name='exercise_updated_by', null=False)
def __str__(self):
return self.name
class Package_Exercise(models.Model):
package = models.ForeignKey(Package,on_delete=models.CASCADE,related_name='package')
exercise = models.ForeignKey(Exercise,on_delete=models.CASCADE)
repetition = models.IntegerField()
number_of_sets = models.IntegerField()
rest_time = models.IntegerField()
created_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE,
related_name='packages_exercise_created_by')
updated_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE,
related_name='packages_exercise_updated_by')
Here is the serializer takes 2.3s for ~30 objects of data in the models.
class PackageSerializer(serializers.ModelSerializer):
exercises = serializers.SerializerMethodField()
class Meta:
model=Package
fields= ['id','package_name','description','amount','is_public','public_doctor','thumbnail','exercises']
def get_exercises(self, obj):
pkg_exercies = Package_Exercise.objects.filter(package = obj.id)
sam = []
for each in pkg_exercies:
sam.append(
{
"name":each.exercise.name,
"url":each.exercise.video.video.url,
"description":each.exercise.description,
"category":each.exercise.category.title,
"tag":each.exercise.tag.name
}
)
return sam
What are the ways to tackle these kind of situations in both POST and GET APIs

Make a new serializer for the package_excercise model and use it in PackageSerializer's method like this:
def get_exercises(self, obj):
pkg_exercies = Package_Exercise.objects.filter(package = obj.id)
serializer = ExcerciseSerializer(data=pkg_exercies, many=True)
serializer.is_valid()
return serializer.data
In this way, you will be using the best way possible for fetching desired data moreover you will not have to repeat the same code in the future.

Related

cannot display classes of courses

I am trying to create an educational website using django, so I have two models class and course which have a one-to-many foreignkey relationship between them i.e. one course can have several class but one class can only have one course. But this creates a problem for me. That is, in my course_detail_view I have assigned the model course. So I cannot render classes in my html file. Can anyone help me solve this ?
My models.py:
class Course(models.Model):
title = models.CharField(max_length=100)
image = models.ImageField(upload_to='class/instructor_pics', null=True)
instructor = models.CharField(max_length=100)
instructor_image = models.ImageField(upload_to='class/instructor_pics', null=True)
students = models.ManyToManyField(User, related_name='courses_joined', blank=True)
slug = models.SlugField(max_length=200, unique=True)
description = models.TextField(max_length=300, null=True)
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created']
def __str__(self):
return self.title
class Class(models.Model):
title = models.CharField(max_length=100)
video = models.FileField(upload_to='class/class_videos',null=True,
validators=[FileExtensionValidator(allowed_extensions=['MOV','avi','mp4','webm','mkv'])])
course = models.ForeignKey(Course, on_delete=models.CASCADE, null=True, related_name='classes')
def __str__(self):
return self.title
My views.py:
class CourseDetailView(LoginRequiredMixin, DetailView):
model = Course
template_name = 'class/course.html'
Thanks in advance!

Django Rest Framework how to serialize a many to many relational Model?

I am doing a project in Django Rest Framework. Now I am trying to serialize many to many relations, but I don't know how this works. Here is my models' code:
Model for files
def user_directory_path(instance, filename):
return 'user_{0}/{1}'.format(instance.user.id, filename)
class Document(models.Model):
name = models.CharField(max_length=250, blank=True, null=True)
document = models.FileField(upload_to=user_directory_path)
def __str__(self):
return self.name
Model for Expenses and loans
class Expenses(models.Model):
name = models.CharField(max_length=250, blank=True, null=True)
amount = models.DecimalField(default=0.0, decimal_places=2, max_digits=10)
date = models.DateField(auto_now=True)
additional_files = models.ManyToManyField(Document, blank=True, related_name="expenses") # Upload multiple files
def __str__(self):
return self.name
class Loans(models.Model):
name = models.CharField(max_length=250, blank=True, null=True)
amount = models.DecimalField(default=0.0, decimal_places=2, max_digits=10)
loan_from = models.CharField(max_length=250, blank=True, null=True)
date = models.DateField(auto_now=True)
additional_files = models.ManyToManyField(Document, blank=True, related_name="loans") # Upload multiple files
def __str__(self):
return self.name
My question:
Just want to know how to serialize these additional_files in the Expenses and Loans.
It will be much better if give resources and explanations of how that works.
For List endpoint you could make something like that:
serializers.py
class ListDocumentSerializer(serializers.Serializer):
# Document fields
class ListLoansSerializer(serializers.Serializer):
name = serializers.CharField()
additional_files = ListDocumentSerializer(many=True)
# other loans model fields
views.py
class ListLoansApi(APIView):
permission_classes = []
def get(self, request):
loans = Loans.objects.prefetch_related('additional_files') # prefetch_related for ORM optimization with M2M
loans_data = ListDoctorSerializer(loans, many=True).data
return Response(loans_data)

Insert records into two tables using single view in Django rest framework

I have three models as follows.
class Quiz(models.Model):
name = models.CharField(max_length=50)
desc = models.CharField(max_length=500)
number_of_questions = models.IntegerField(default=1)
time = models.IntegerField(help_text="Duration of the quiz in seconds", default="1")
def __str__(self):
return self.name
def get_questions(self):
return self.question_set.all()
class Question(models.Model):
ques = models.CharField(max_length=200)
quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE)
def __str__(self):
return self.ques
class Answer(models.Model):
content = models.CharField(max_length=200)
correct = models.BooleanField(default=False)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
def __str__(self):
return f"question: {self.question.ques }, answer: {self.content}, correct: {self.correct}"
I have to create api for create question. for this I have to use model Question and Answer same time e.g.
its admin page but I want to create same api which accept above parameters and store it into database.
how to write view.py for this api ?

Django design model - when a data of status field changes, remaining models status change with it

Its my first time trying django as my first programming project.
I have a hierarchy structure of Company -> Business -> Outlets using foreign key.
I would like to know is there anyway to structured it in a way where the Company status is saved as inactive status, the remaining business, outlets models that will be triggered as inactive status.
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Common_Info(models.Model):
"""(Common description)"""
name = models.CharField(blank=True, max_length=100)
slug = models.SlugField(unique=True, max_length=120)
address_1 = models.CharField(max_length=50, null=True)
address_2 = models.CharField(max_length=50, null=True)
address_3 = models.CharField(max_length=50, null=True)
post_code = models.CharField(max_length=6, null=False)
registration_no. = models.CharField(max_length=15,null=False)
gst_no. = models.CharField(max_length=15,null=True)
telphone_no. = models.CharField(max_legth=15, null=False)
fax_no. = models.CharField(max_legth=15, null=True)
email_address = models.EmailField(max_length=254,null=False)
"""(Status choice)"""
Active_Status = 1
Inactive_Status = 0
STATUS_CHOICES = (
(Active_Status, 'Active'),
(Inactive_Status, 'Inactive'),
)
status = models.IntegerField(choices=STATUS_CHOICES, default=Active_Status)
create_date = models.DateTimeField(auto_now_add=True)
create_user = models.ForeignKey(settings.AUTH_USER_MODEL)
modified_date = models.DateTimeField(auto_now_add=True)
modified_user = models.ForeignKey(settings.AUTH_USER_MODEL)
class Meta:
abstract = True
class Company(Common_Info):
"""(Company additional description)"""
gst_no. = models.CharField(max_length=15,null=True)
class Meta:
verbose_name ='Company'
verbose_name_plural = "Companies"
def __unicode__(self):
return u"Company"
class Business(Common_Info):
"""(Business description)"""
parent=models.ForeignKey(Company, on_delete=models.CASCADE)
gst_no. = models.CharField(max_length=15,null=True)
class Meta:
verbose_name ='Business'
verbose_name_plural = "Businesses"
def __unicode__(self):
return u"Business"
class Outlet(Common_Info):
outlet_code = models.CharField(max_length=3, unique=True)
business_name = models.ForeignKey(Business, on_delete=models.CASCADE)
def __unicode__(self):
return u"Outlet"
Is there something similar to cascade on delete or other more elegant way of extending such a function across other apps in the project.
I don't think there is any direct support in ORM. But you can override the save() method to update the related the outlets and business. You can use related objects to fetch business and outlets. Here is an example:
class Company(Common_Info):
"""(Company additional description)"""
gst_no. = models.CharField(max_length=15,null=True)
class Meta:
verbose_name ='Company'
verbose_name_plural = "Companies"
def __unicode__(self):
return u"Company"
def save(self, *args, **kwargs):
super(Company, self).save(*args, **kwargs)
if self.status == 0:
self.business_set.update(status=self.status)
self.outlet_set.update(status=self.status)

Django Model design for a basic inventory application

I am new to Django (and databases for that matter) and trying to create a simple inventory application to help learn. I've been through the tutorials and am going through some books, but I am stuck at what i think is simple, just not sure where to look or how to ask.
With an inventory application, you have your equipment which then has a manufacturer, which the equipment has a model number that only that manufacturer has. Lets say Dell Optiplex 3040. I am also using the admin console right now as well. So i would like to be able to relate equipment to a manufacturer and then also relate the equipment to the model number. It almost seems as I am needing to use the many to many field and the through field to accomplish what I am trying to do but I dont think that is the right way to do it (shown in the link below). https://docs.djangoproject.com/en/1.9/topics/db/models/#many-to-many-relationships
Below is the code I have so far. Thank you.
from django.db import models
# Create your models here.
class Department(models.Model):
department = models.CharField(max_length=50)
def __str__(self):
return self.department
class Manufacturer(models.Model):
manufacturer = models.CharField(max_length=50)
def __str__(self):
return self.manufacturer
class EquipmentModel(models.Model):
equipmentModel = models.CharField(max_length=50)
def __str__(self):
return self.equipmentModel
class Employees(models.Model):
employee_name_first = models.CharField(max_length=25)
employee_name_last = models.CharField(max_length=25)
employee_username = models.CharField(max_length=20)
phone = models.IntegerField()
assigned_equipment = models.ForeignKey('Device', default='undefined')
department = models.ForeignKey('Department', on_delete=models.CASCADE, default='undefined')
job_title = models.ManyToManyField('Job_Positions', default='undefined')
def __str__(self):
return self.employee_username
class Device(models.Model):
ip = models.GenericIPAddressField(protocol='IPv4',unpack_ipv4=False,null=True, blank=True)#might be good to seperate IP in its own class because a device can have multiple IP's
department = models.ForeignKey('Department', on_delete=models.CASCADE)
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
serial_number = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now=False, auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True, auto_now_add=False)
comments = models.TextField(blank=True)
def __str__(self):
return self.serial_number
class Job_Positions(models.Model):
position_title = models.CharField(max_length=50)
position_description = models.TextField(blank=True)
def __str__(self):
return position_title
***Edit to add the updated code and the admin.py code in response question I had to answer.
#admin.py
from django.contrib import admin
# Register your models here.
from .models import Device,Department,Manufacturer,Employees, Job_Positions, EquipmentModel
class DeviceModelAdmin(admin.ModelAdmin):
list_display = ["ip", "department","model","serial_number","date_updated"]
list_filter = ["department","model","ip"]
search_fields = ["ip"]
class Meta:
model = Device
class EmployeesModelAdmin(admin.ModelAdmin):
list_display = ["employee_name_first", "employee_name_last", "employee_username", "phone"]
list_filter = ["department"]
class Meta:
model = Employees
admin.site.register(Device, DeviceModelAdmin)
admin.site.register(Department)
admin.site.register(Manufacturer)
admin.site.register(EquipmentModel)
admin.site.register(Employees, EmployeesModelAdmin)
admin.site.register(Job_Positions)
updated models.py
from django.db import models
# Create your models here.
class Department(models.Model):
department = models.CharField(max_length=50)
def __str__(self):
return self.department
class Manufacturer(models.Model):
manufacturer = models.CharField(max_length=50)
def __str__(self):
return self.manufacturer
class EquipmentModel(models.Model):
model_number = models.CharField(max_length=50)
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
def __str__(self):
return self.model_number
class Employees(models.Model):
employee_name_first = models.CharField(max_length=25)
employee_name_last = models.CharField(max_length=25)
employee_username = models.CharField(max_length=20)
phone = models.IntegerField()
assigned_equipment = models.ForeignKey('Device', default='undefined')
department = models.ForeignKey('Department', on_delete=models.CASCADE, default='undefined')
job_title = models.ManyToManyField('Job_Positions', default='undefined')
def __str__(self):
return self.employee_username
class Device(models.Model):
ip = models.GenericIPAddressField(protocol='IPv4',unpack_ipv4=False,null=True, blank=True)#might be good to seperate IP in its own class because a device can have multiple IP's
department = models.ForeignKey('Department', on_delete=models.CASCADE)
model = models.ForeignKey('EquipmentModel', on_delete=models.CASCADE,null=True)
serial_number = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now=False, auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True, auto_now_add=False)
comments = models.TextField(blank=True)
def __str__(self):
return self.serial_number
class Job_Positions(models.Model):
position_title = models.CharField(max_length=50)
position_description = models.TextField(blank=True)
def __str__(self):
return position_title
A many-to-many relationship is not what you want here, because any piece of equipment (I assume) can only have one manufacturer.
You do need an intermediate model which stores the model information, and you already have one in your EquipmentModel. I would suggest modifying it as follows:
class EquipmentModel(models.Model):
# This stores information about a particular model of device
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
model_number = models.CharField(max_length=50)
And then instead of having a foreign key to the manufacturer in Device, replace it with a foreign key to the equipment model:
class Device(models.Model):
# ...
model = models.ForeignKey('EquipmentModel', on_delete=models.CASCADE)