Django Query data optimization - python-3.x

Recently, I watched Django and discovered the teaching videos of select_related and prefetch_related.
So I installed debug_toolbar and took a look at my website
I searched the database too many times on one page.
I must convert it to json and send it back to the front end
Can I still optimize?
Is this the only way to go?
Below is my model .
models.py
def get_upload_path(instance, filename):
return f'register/{instance.owner.job_number}/{filename}'
def image_upload_path(instance, filename):
date = datetime.datetime.strptime(instance.date, '%Y-%m-%d %H:%M:%S')
return f'image/{date.year}/{date.month}/{date.day}/{filename}'
class UserProfile(models.Model):
name = models.CharField(max_length=64)
department = models.CharField(max_length=32)
job_number = models.CharField(max_length=32, unique=True)
card_number = models.CharField(max_length=32, unique=True)
location = models.CharField(max_length=32)
date = models.DateTimeField()
class UserRegister(models.Model):
owner = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
date = models.DateTimeField()
feature = ArrayField(models.FloatField(null=True, blank=True), null=True, blank=True, size=512)
image = models.ImageField(upload_to=get_upload_path)
class Meta:
db_table = 'UserRegister'
class UserImage(models.Model):
owner = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
heat = models.CharField(max_length=8, blank=True, null=True)
date = models.DateTimeField()
image = models.ImageField(upload_to=image_upload_path)
punch_in = models.CharField(max_length=8, blank=True, null=True)
class Meta:
db_table = 'UserImage'
views.py
def get_db_data(db, page, limit, model):
data = []
paginator = Paginator(db, limit)
try:
page_object = paginator.page(page)
all_page = paginator.num_pages
for db_data in page_object:
images = []
for image in db_data.userregister_set.all():
try:
url = f'/static/uploads{image.image.url}'
except ValueError:
url = '/static/imgs/assets/none.jpg'
images.append({'id': image.id, 'url': url})
_ = {
'id': db_data.id,
'name': db_data.name,
'department': db_data.department,
'job_number': db_data.job_number,
'card_number': db_data.card_number,
'location': db_data.location,
'date': db_data.date.strftime('%Y-%m-%d %H:%M:%S'),
'images': images,
}
data.append(_)
result = {
'data': data,
'all_page': all_page,
'page': int(page)
}
return result
except EmptyPage as error:
# 該頁數沒資料。
return {'msg': 'Error'}
class Test(Views):
def get(self, request):
name = request.GET.get('name')
department = request.GET.get('department')
job_number = request.GET.get('job_number')
card_number = request.GET.get('card_number')
location = request.GET.get('location')
start_date = request.GET.get('start_date')
end_date = request.GET.get('end_date')
order = request.GET.get('order', default='DESC')
page = request.GET.get('page', default=1)
limit = request.GET.get('limit', default=25)
user_profile = UserProfile.objects.all().select_related()
if name:
user_profile = user_profile.filter(name=name)
if department:
user_profile = user_profile.filter(department=department_table.department)
if job_number:
user_profile = user_profile.filter(job_number=job_number)
if card_number:
user_profile = user_profile.filter(card_number=card_number)
if location:
user_profile = user_profile.filter(location=locations_table.location)
if start_date and end_date:
user_profile = user_profile.filter(date__range=[start_date, end_date])
if order == 'DESC':
data = get_db_data(db=user_profile.order_by('-date'), page=page, limit=limit, model='api')
else:
data = get_db_data(db=user_profile.order_by('date'), page=page, limit=limit, model='api')
response = JsonResponse(data)
# return response # This is the response I want to return, but now I need to use `debug_toolbar`, so I return an empty page to facilitate my reading `debug_toolbar`.
return render(request, 'User/test1.html')
return JsonResponse(data) is what I want to return, but now I need to use debug_toolbar, so I return to an empty page to facilitate reading debug_toolbar.

Use select_related() or prefetch_related().
Put the associated parameters into.
can speed up the ORM.

Related

EcomUser() got an unexpected keyword argument 'mobile_number'

I'm trying to create a user and link it with the user profile. But here is the problem.
This is my profile model
class EcomUser(BaseModelMixin):
profile = models.OneToOneField(
settings.AUTH_USER_MODEL, unique=True, blank=True, null=True,
on_delete=models.CASCADE)
username = models.CharField(max_length=100, blank=True)
email = models.CharField(max_length=100, blank=True, null=True)
name = models.CharField(max_length=100, blank=True)
referral_code = models.CharField(max_length=10, blank=True)
signinId = models.CharField(max_length=20, blank=True)
GOOGLE = 'GOOGLE'
APPLE = 'APPLE'
MOBILE_NUMBER = 'mobile_number'
LOGIN_TYPES = (
(GOOGLE, 'GOOGLE'),
(APPLE, 'APPLE'),
(MOBILE_NUMBER, 'mobile_number')
)
loginType = models.CharField(max_length=15, choices=LOGIN_TYPES, default=MOBILE_NUMBER)
class Meta:
db_table = "ecom_user"
My user model:
class User(AbstractBaseUser, BaseModelMixin):
email = models.EmailField(
verbose_name='email_address',
max_length=255,
blank=True,
null=True
)
username = models.CharField(max_length=128, null=True,unique=True)
fullName = models.CharField(max_length=256, blank=True)
mobile_number = models.CharField(max_length=15, blank=True,unique=True)
is_superuser = models.BooleanField(default=False)
class Meta:
db_table = "users"
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = [] # Email & Password are required by default.
def get_full_name(self):
# The user is identified by their email address
return self.fullName
def __str__(self): # __unicode__ on Python 2
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
objects = UserManager()
and serializer.py
class UserRegisterSerializer(serializers.Serializer):
"""Normal serializer which accepts mobile number"""
mobile_number = serializers.CharField(max_length=10, min_length=10, required=True)
referral_code = serializers.CharField(max_length=10, min_length=10, required=True)
email = serializers.EmailField(max_length=255)
def validate_referral_code(self, referral_code):
if not re.match(r"^[\w]{10}$", referral_code):
raise serializers.ValidationError("Wrong Referral Code")
return referral_code
def validate_mobile_number(self, mobile_number):
if not re.match(r"^[\d]{10}$", mobile_number):
raise serializers.ValidationError("Please pass proper mobile number")
return mobile_number
class EcomUserSerializer(serializers.ModelSerializer):
profile_id = serializers.IntegerField(required=True)
mobile_number = serializers.CharField(max_length=10, min_length=10, required=True)
referral_code = serializers.CharField(max_length=10, min_length=10, required=True)
class Meta:
model = EcomUser
fields= ('profile_id','referral_code', 'mobile_number', 'loginType', 'signinId')
def create(self, data):
instance = EcomUser.objects.create(**data)
return instance
views.py
#api_view(['POST'])
def registration(request):
try:
local_reponse = {
"status": False,
"message": "",
"code": status.HTTP_400_BAD_REQUEST,
"data": []
}
data = request.data
print('1')
mobile_number = data.get('mobile_number', None)
referralCode = data.get('referralCode', '')
LoginType = data.get('LoginType')
signinId = data.get('signinId', '')
email = data.get('email', '')
print(f'{LoginType} --- {EcomUser.MOBILE_NUMBER}')
if LoginType == "mobile_number":
print('2')
exist_user = User.objects.filter(mobile_number=mobile_number).count()
if exist_user:
print('3')
local_reponse["message"] = msg.ALREADY_EXIST
return Response(local_reponse)
try:
print('not found')
registerd_user = User.objects.get(mobile_number=mobile_number)
print(f'{registerd_user} -- check')
if registerd_user:
print('register')
ecom = EcomUser.objects.get(profile_id=registerd_user.id)
if ecom:
local_reponse["message"] = msg.ALREADY_EXIST
except User.DoesNotExist:
print('4')
user = User.objects.create_ecom_user(mobile_number=mobile_number)
user.save()
print('is user create?')
if user:
print('yes')
info = {}
info['profile_id'] = user.id
info['referral_code'] = referralCode
info['mobile_number'] = mobile_number
info['LoginType'] = LoginType
info['signinId'] = signinId
ecom_serializer = EcomUserSerializer(data=info)
if not ecom_serializer.is_valid():
print('5')
local_reponse["message"] = ecom_serializer.error_messages
local_reponse["status"] = False,
return Response(local_reponse)
print(f'linked profile 1 ----' )
ecomuser_data = ecom_serializer.save()
print(f'linked profile 2 ---- ' )
ecomuser_id = ecomuser_data.id
print('linked profile 3' )
ecomuser = EcomUser.objects.get(id=ecomuser_id)
print('linked profile 4' )
ecom_serializer = EcomUserSerializer(ecomuser)
print('linked profile 5' )
context = ecom_serializer.data
print('linked profile 6' )
local_reponse = {
"status": True,
"message": msg.CREATED,
"code": status.HTTP_201_CREATED,
"data": context
}
print('linked profile 7' )
return Response(local_reponse)
except Exception as e:
print('7')
local_reponse["message"] = str(e)
return Response(local_reponse)
When I try to run API on postman. It showed "EcomUser() got an unexpected keyword argument 'mobile_number'" and the output in the terminal show below:
1
mobile_number --- mobile_number
2
not found
4
is user create?
yes
linked profile 1 ----
7
The user is created but can not link to the profile, any one can help?
There's no mobile_number field in your EcomUser model. Thus when you call
ecomuser_data = ecom_serializer.save()
after adding
info['mobile_number'] = mobile_number
if fails, leaving you with the user and no profile. I guess is_valid() is only checking the fields it wants, not detecting the surplus, but the extra field causes the save to fail with the error shown. You've already added the field when creating the user, so you don't need it in the profile, so removing that second line should make things work.

Deny to access to id of user in Foreignkey model

--WHY I CANT TO ACCESS TO ID OF USER AND PRODUCT WITH user__id and product__id?
i have error: (The view store.views.submit_review didn't return an HttpResponse object. It returned None instead).
<pre><code>
i define some code for rating post for any user user
--#views
def submit_review(request, product_id):
url = request.META.get('HTTP_REFERER')
if request.method == 'POST':
try:
reviews = ReviewRating.objects.get(user__id=request.user.id,Product__id=product_id) #my problem is here
form = Reviewform(request.POST, instance=reviews)
form.save()
messages.success(request, 'Thank you!your review has been updated.')
return redirect(url)
except ReviewRating.DoesNotExist:
form = Reviewform(request.POST)
if form.is_valid():
data = ReviewRating()
data.subject = form.cleaned_data['subject']
data.review = form.cleaned_data['review']
data.rating = form.cleaned_data['rating']
data.ip = request.META.get['REMOTE_ADDR']
data.product_id = product_id
data.user_id = request.user.id
data.save()
messages.success(request, 'Thank you! Your review has been submitted')
return redirect(url)
</code></pre>
this section i define model.I checked this part it work correctly
define model for views in my app
#models
class ReviewRating(models.Model):
Product = models.ForeignKey(product, on_delete=models.CASCADE)
user = models.ForeignKey(Account, on_delete=models.CASCADE)
subject = models.CharField(max_length=100, blank=True)
review = models.TextField(max_length=500, blank=True)
rating = models.FloatField()
ip = models.CharField(max_length=20, blank=True)
status = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.subject
this part i define url
#urls
define path for html and views
urlpatterns = [
path('submit_review/int:product_id/',views.submit_review,name='submit_review')
]
your model is not clear. It would be better if you could atleast share your full model.py file
if you provide the objective of your service with models.py, serializers.py, views.py I think I will be able to help more specifically
till now, one issue i've found in the the url section is that you need to add < > on int:product_id.
it should be,
urlpatterns = [
path('submit_review/<int:product_id>/',views.submit_review,name='submit_review')
]

redefinition of group name 'slug' as group 2; was group 1 at position 50

I am using Django Rest-framework and creating an endpoints for a application which has multiple Teams.
Each "Teams" have multiple "Channels". for simplicity I divide my application in two different apps.
TeamsAPI
ChannelsAPI
I want to display the Channels as HyperLinkedField in Team List.
channels:[
127.0.0.1:8000/api/teams/<team_slug>/channels/<channel_slug>/)
]
Team List Serializer
class TeamListSerializer(serializers.ModelSerializer):
channels = serializers.HyperlinkedRelatedField(many=True,
read_only=True,
view_name='channel-detail',
lookup_field='slug')
.
.
.(other feilds)
class Meta:
model = Team
fields = (
'channels',
.
.
.(other fields)
)
Teams URL
urlpatterns = [
path('<slug:slug>/channels/', include('channelsapi.api.urls')),
.
.
.(other urls)]
Channel URL
urlpatterns = [
path('<slug:slug>/', ChannelDetailAPIView.as_view(), name='channel-detail'),
.
.
.(other urls)]
Channel Model
class Channel(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=200, blank=True)
team = models.ForeignKey(Team,
related_name='channels',
on_delete=models.CASCADE)
slug = models.SlugField(unique=True)
pinned = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
Channel Detail Serializer
class ChannelDetailSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(read_only=True,
view_name='channel-detail',
lookup_field='slug')
team = serializers.HyperlinkedRelatedField(read_only=True,
view_name='team-detail',
lookup_field='slug')
class Meta:
model = Channel
fields = (
'url',
'slug',
'name',
'description',
'team',
'pinned',
'created_at',
'updated_at'
)
read_only_fields = ('created_at', 'updated_at')
lookup_field = 'slug'
I solved this problem by overriding the "HyperLinkedRelatedField".
Here is the code:
class ChannelHyperlink(serializers.HyperlinkedRelatedField):
view_name = 'channel-detail'
queryset = Channel.objects.all()
def get_url(self, obj, view_name, request, format):
url_kwargs = {
'slug': obj.team.slug,
'pk': obj.pk
}
return reverse(view_name, kwargs=url_kwargs, request=request, format=format)
def get_object(self, view_name, view_args, view_kwargs):
lookup_kwargs = {
'team__slug': view_kwargs['slug'],
'pk': view_kwargs['pk']
}
return self.get_queryset().get(**lookup_kwargs)
Now just simply call your custom serializer:
channels = ChannelHyperlink(many=True)

My Django model for video upload saying “ValueError”

I am trying to write a small blog where I can be uploading my videos for public download but am getting a server error message when I try click on any video for details. Below is the error that I'm getting when Debug is set to True
ValueError at /video/lagos-anthem/
Sample larger than population or is negative
Request Method: GET
Request URL: https://www.majestylink.com/video/lagos-anthem/
Django Version: 3.1.2
Exception Type: ValueError
Exception Value:
Sample larger than population or is negative
Exception Location: /home/majestyempire/.virtualenvs/majestyenv/lib/python3.7/random.py, line 321, in sample
Python Executable: /usr/local/bin/uwsgi
Python Version: 3.7.5
Python Path:
['/var/www',
'.',
'',
'/var/www',
'/home/majestyempire/.virtualenvs/majestyenv/lib/python37.zip',
'/home/majestyempire/.virtualenvs/majestyenv/lib/python3.7',
'/home/majestyempire/.virtualenvs/majestyenv/lib/python3.7/lib-dynload',
'/usr/lib/python3.7',
'/home/majestyempire/.virtualenvs/majestyenv/lib/python3.7/site-packages',
'/home/majestyempire/musicblog/myblog']
Server time: Sat, 28 Nov 2020 13:49:35 +0100
Below is my models.py
class Video(models.Model):
CATEGORY_CHOICES = (
('Music', 'Music'),
('Movies', 'Movies'),
)
artist = models.CharField(max_length=200, unique=True)
category = models.CharField(max_length=30, choices=CATEGORY_CHOICES, default='Music')
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(default='', blank=True, unique=True)
thumbnail = models.ImageField(blank=False)
video_file = models.FileField(default='')
uploaded_date = models.DateTimeField(default=timezone.now)
objects = PostManager()
class Meta:
ordering = ['-uploaded_date']
def save(self):
self.uploaded_date = timezone.now()
self.slug = slugify(self.title)
super(Video, self).save()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('video:detail', kwargs={'slug': self.slug})
This is the post_detail view
def post_detail(request, slug):
random_posts = random.sample(list(Video.objects.all()), 2)
vid = get_object_or_404(Video, slug=slug)
comments = Comment.objects.filter(post=vid)
is_liked = False
context = {
'Video': Video,
'vid': vid,
'random_posts': random_posts,
}
return render(request, 'video/video_detail.html', context)
def post_detail(request, slug):
a = Video.objects.all().count()
if a > 2:
random_posts = random.sample(list(Video.objects.all()), 2)
else:
random_posts = random.choices(list(Video.objects.all()))
vid = get_object_or_404(Video, slug=slug)
comments = Comment.objects.filter(post=vid)
is_liked = False
context = {
'Video': Video,
'vid': vid,
'random_posts': random_posts,
}
return render(request, 'video/video_detail.html', context)

AssertionError in unit testing

while I was writing tests I got that error
assert response.status_code == status.HTTP_201_CREATED
E AssertionError: assert 415 == 201
E -415
E +201
models.py
class Product(TimeStamp):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
color = models.ManyToManyField(ColorOfProduct)
available = models.BooleanField(default=True)
image = models.ImageField(upload_to='products/%Y/%m/%d', null=True, blank=True)
slug = models.SlugField(max_length=100, unique=True, blank=True)
def __str__(self):
return f'{self.category} - {self.name}'
tests.py looks like this
class ProductTest(APITestCase):
def post_product(self, category, name, brand_name, color, available):
url = reverse(ProductView.name)
print(url)
data = {
'category': category,
'name': name,
'brand_name': brand_name,
'color': color,
'available': available,
}
response = self.client.post(url, data, format='json')
return response
def test_post_and_get_product(self):
new_category_name = 'Hewlet Packard'
new_product_name = 'HP Zenbook'
new_brand_name = 'HP'
new_color = 'black'
new_available = True
response = self.post_product(
new_category_name,
new_product_name,
new_brand_name,
new_color,
new_available,
)
assert response.status_code == status.HTTP_201_CREATED
assert Product.objects.count() == 1
assert Product.objects.get().name == new_product_name
I am indicating media type but when I check it throws error "Unsupported media type"
how can I solve this issue?
The reason might be django's default test format is application/octet-stream. You need to use json.dumps() before calling your test method. In your post_product method, just change:
response = self.client.post(url, data, format='json')
to
import json
response = self.client.post(url, json.dumps(data), content_type='application/json')

Resources