Traslate this queryset? - django

My query is made in MYSQL I would like to know how to translate it to the ORM django tnhanks you
SELECT *,(SELECT count(*)
FROM tesisnueva.donador_desactivar ds
where ds.motivo=1 and
ds.donador_id= dd.id and
date_add(ds.fecha_desactivar, INTERVAL 90 DAY)<now()) as cantidad
FROM tesisnueva.donador_donador dd
where dd.genero='F';
MY MODELS
class Donador(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
hospital = models.ForeignKey(Hospital, null=True, blank=True, on_delete=models.SET_NULL)
fecha_nacimiento = models.DateField(validators=[check_date])
direccion = models.CharField(max_length=50,null=False,blank=False)
genero = models.CharField( max_length=1 , choices = GENERO, default='M')
grupo_sanguineo = models.CharField(max_length=10,choices=GRUPO_SANGRE, default='A')
factor_RH = models.CharField(max_length=2, choices=FACTOR_SANGRE, default='+')
telefono = models.CharField(max_length=12)
activo = models.BooleanField(default=0)
groups = models.ForeignKey(Group, null=True, blank=True, on_delete=models.CASCADE)
class Desactivar(models.Model):
donador = models.ForeignKey(Donador,on_delete=models.CASCADE)
motivo= models.IntegerField()
fecha_desactivar=models.DateField()

You can make use of .annotate(…) [Django-doc] and use a filter=… parameter [Django-doc] to filter the related model accordingly:
from datetime import timedelta
from django.db.models import Q
from django.utils.timezone import now
Donador.objects.filter(genero='F').annotate(
cantidad=Count(
'desactivar',
filter=Q(motivo=1, fecha_desactivar=now()-timedelta(days=90))
)
)
The Donador objects that arise from this queryset have an extra attribute .cantidad that contains the number of related desactivar objects that satisfy the given filter.

Related

Should i create one model for multiple apps in a clothing project?

It's my first time creating a project with Django. and it's an e-commerce store for clothing. my confusion now is, most of the items are similar, like women's wears, men's wears, children's wears.Creating different models in different apps means i have to repeat a lot of code because most of the fields will be same and some operations would be more complicated to achieve like global search, etc.
So should i create a single database for all of the items and filter out what i need in different sections like menswear page, women's wear page, etc ?
#For men's model
from django.db import models
from django.urls import reverse
# Create your models here.
CLOTH_CATEGORY_OPTIONS = (
("top", "Top"),
("bottom", "Bottom"),
("complete", "Complete"),
)
CLOTH_GENDER_OPTIONS = (
("male", "Male"),
("female", "Female"),
("unisex", "Unisex"),
)
class Wear(models.Model):
cloth_name = models.CharField(max_length=50, unique=True)
cloth_image = models.CharField(max_length=300)
cloth_category = models.CharField(
max_length=8, choices=CLOTH_CATEGORY_OPTIONS, default='top')
cloth_gender = models.CharField(
max_length=8, choices=CLOTH_GENDER_OPTIONS, default='male')
cloth_price = models.FloatField()
cloth_description = models.TextField()
slug = models.SlugField(default='', editable=False,
max_length=200, null=False)
#For women's model
from django.urls import reverse
# Create your models here.
CLOTH_CATEGORY_OPTIONS = (
("top", "Top"),
("bottom", "Bottom"),
("complete", "Complete"),
)
CLOTH_GENDER_OPTIONS = (
("male", "Male"),
("female", "Female"),
("unisex", "Unisex"),
)
class WomensWear(models.Model):
cloth_name = models.CharField(max_length=50, unique=True)
cloth_image = models.CharField(max_length=300)
cloth_category = models.CharField(
max_length=8, choices=CLOTH_CATEGORY_OPTIONS, default='top')
cloth_gender = models.CharField(
max_length=8, choices=CLOTH_GENDER_OPTIONS, default='male')
cloth_price = models.FloatField()
cloth_description = models.TextField()
slug = models.SlugField(default='', editable=False,
max_length=200, null=False)
As you can see, this is repetitive, so i want to create a global database so i can import it in each app and filter out for men, women, children etc.
You didn't need to repeat all this code for each gender..
Make one model with a field Gender and specify all the genders.
You can filter the clothes in the views with:
Wear.objects.all().filter(Gender=**Male or Women**)
That will filter your products with the gender you give.
Creating 2 models will work for you. A Cloth Model and a Gender Model
One cloth can be of a male or female or both so will work with one to many
class Cloth(models.Model):
gender = models.ForiegnKey(Gender)
....
You will be filtering using:
Cloth.objects.filter(gender__type="male")

Need help translating raw sql query to ORM Django

Django Models that used in projects:
class LeadStatus(models.Model):
status_id = models.PositiveIntegerField(verbose_name='ID статуса', unique=True)
name = models.CharField(max_length=100, verbose_name='Имя', null=True, default='Неизвестный')
class Lead(models.Model):
lead_id = models.PositiveIntegerField(verbose_name="ID сделки", null=True, unique=True)
created_date_time = models.DateTimeField(verbose_name="Время и дата создания сделки", null=True)
price = models.IntegerField(verbose_name='Бюджет сделки')
current_status = models.ForeignKey(LeadStatus, on_delete=models.SET_NULL, verbose_name='Текущий статус', null=True)
class LeadsNote(models.Model):
note_id = models.CharField(verbose_name="ID примечания", null=True, unique=True, max_length=64)
lead = models.ForeignKey(Lead, on_delete=models.CASCADE)
old_status = models.ForeignKey(LeadStatus, related_name='old_status', null=True, blank=True,
on_delete=models.CASCADE)
new_status = models.ForeignKey(LeadStatus, null=True, related_name='new_status', blank=True,
on_delete=models.CASCADE)
crossing_status_date_time = models.DateTimeField(verbose_name="Время и дата пересечения статуса", null=True)
I am trying to execute the following SQL query using Django ORM tools. He does what i need
SELECT leads.id,
notes.crossing_status_date_time,
old_status.name as old_status,
new_status.name as new_status,
(CASE WHEN leads.id in (
select leads.id
from core_leads
where old_status.status_id not in (13829322, 14286379) and new_status.status_id in (13829322, 14286379))
THEN true ELSE false END) as _is_profit
FROM core_leadsnote AS notes
LEFT JOIN core_lead AS leads ON notes.lead_id=leads.id
LEFT JOIN core_leadstatus AS old_status ON notes.old_status_id=old_status.id
LEFT JOIN core_leadstatus AS new_status ON notes.new_status_id=new_status.id
Using Django subqueries I came up with the following ORM query.
But it doesn't work as well as raw sql
from django.db.models import OuterRef, Q, Subquery, Case, When, BooleanField
from .models import LeadsNote, Lead, CompanyConfig, AmoCompany
company = AmoCompany.objects.first()
status_config = CompanyConfig.objects.get(company=company)
accepted_statuses = [status.status_id for status in status_config.accept_statuses.all()]
subquery = (Lead
.objects.select_related('current_status', 'company')
.filter(leadsnote=OuterRef('pk'))
.filter(~Q(leadsnote__old_status__status_id__in=accepted_statuses) &
Q(leadsnote__new_status__status_id__in=accepted_statuses)))
query = (LeadsNote
.objects
.annotate(
_is_profit=Case(
When(lead__id__in=Subquery(subquery.values('id')), then=True),
default=False, output_field=BooleanField())))
Need any help finding the right solution

Django Sum in Annotate

Good afternoon,
I am really struggling with getting a sum using Annotate in DJango.
I am using User object and the following models:
class Depts(models.Model):
dept_name = models.CharField(max_length=55)
dept_description = models.CharField(max_length=255)
isBranch = models.BooleanField(default=False)
def __str__(self):
return "{}".format(self.dept_name)
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='profile')
title = models.CharField(max_length=75)
dept = models.ForeignKey(Depts, on_delete=models.CASCADE, related_name="dept", null=True)
class ActivityLog(models.Model):
activity_datetime = models.DateTimeField(default=timezone.now)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, related_name='activity_user')
activity_category = models.ForeignKey(ActivityCategory, on_delete=models.CASCADE, null=True, related_name='activity_cat')
activity_description = models.CharField(max_length=100, default="Misc Activity")
class ActivityCategory(models.Model):
activity_name = models.CharField(max_length=40)
activity_description = models.CharField(max_length=150)
pts = models.IntegerField()
def __str__(self):
return '%s' % (self.activity_name)
What I need to do is get a group of departments with aggregating the sum of the pts earned by all the users activitylogs.
So a user is part of department, they do activities, each activity is of a type activity_category and has associated points. How can I query using the ORM to get a sum of points for everyone in each department?
Thank you, I cannot seem to wrap my mind around it.
You annotate the departments with the sum:
from django.db.models import Sum
Depts.objects.annotate(
total_pts=Sum('dept__user__activity_user__activity_category__pts')
)
Note: The related_name=… parameter [Django-doc]
is the name of the relation in reverse, so from the Depts model to the UserProfile
model in this case. Therefore it (often) makes not much sense to name it the
same as the forward relation. You thus might want to consider renaming the dept relation to userprofiles.
After setting the related_name='userprofiles', the query is:
from django.db.models import Sum
Depts.objects.annotate(
total_pts=Sum('userprofiles__user__activity_user__activity_category__pts')
)

Django raw query giving same result on all models

I have 3 models Product, Photo, and ProductLikeDilike. I am performing left outer join on all the 3 models. First I am joining Product with Photo and then the resultant table(temp) I am joining with ProductLikeDilike. Below is the raw sql.
Note: olx is the name of django app.
data = Product.objects.raw('select * from (select
olx_product.id,olx_product.name,olx_photo.file,olx_photo.cover_photo_flag
from olx_product left outer join olx_photo on
(olx_product.id=olx_photo.reference_id_id) where
olx_photo.cover_photo_flag="yes" or olx_photo.cover_photo_flag is null) as
temp left outer join olx_productlikedislike on
(temp.id=olx_productlikedislike.product_id_id and
olx_productlikedislike.product_liked_by_id_id=2)')
for x in data:
print(x.name)
What I want to understand that when I use any of the above 3 models to run the raw sql why I am getting the same result i.e.
When I do
data = Product.objects.raw('select *.....')
for x in data:
print(x.name)
or
data = Photo.objects.raw('select *......')
for x in data:
print(x.name)
or
data = ProductLikeDislike.raw('select *.....')
for x in data:
print(x.name)
I am getting the same result. Why?
Please help me to understand this.
Below is the models.py file
from django.db import models
from django.urls import reverse
from django.dispatch import receiver
from django.contrib.auth.models import User
class Product(models.Model):
category = models.ForeignKey(Category ,on_delete=models.CASCADE)
name = models.CharField(max_length = 200, db_index = True)
slug = models.SlugField(max_length = 200, db_index = True)
description = models.TextField(blank = True)
price = models.DecimalField(max_digits = 10, decimal_places = 2 )#Not used FloatField to avoid rounding issues
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
contact= models.BigIntegerField(default=None,blank=True, null=True)
created_by = models.CharField(max_length = 200, default=None,blank=True, null=True)
uploaded_by_id = models.IntegerField(default=0)
status = models.IntegerField(default=0) # 0-->Active,1-->Inactive
mark_as_sold = models.IntegerField(default=0) # 0-->not sold,1-->sold
def get_absolute_url(self):
return reverse('olx:edit_product', kwargs={'pk': self.pk})
class Meta:
ordering = ('-created',)
index_together = (('id','slug'),)# we want to query product by id and slug using together index to improve performance
def __str__(self):
return self.name
class Photo(models.Model):
reference_id = models.ForeignKey(Product, null=True,on_delete=models.CASCADE)
photo_type = models.CharField(max_length = 70, db_index = True)
file = models.FileField(upload_to='photos/',default='NoImage.jpg')
cover_photo_flag = models.CharField(default=0,max_length = 5, db_index = True)
uploaded_at = models.DateTimeField(auto_now_add=True)
uploaded_by_id = models.IntegerField(default=0)
status = models.IntegerField(default=0) # 0-->Active,1-->Inactive
class Meta:
ordering = ('-uploaded_at',)
class ProductLikeDislike(models.Model):
product_id = models.ForeignKey(Product,models.SET_DEFAULT,default=0)
product_liked_by_id = models.ForeignKey(User,models.SET_DEFAULT,default=0)
status = models.BooleanField(default=False)
And Please also show me how to write it in pure Django way if possible?
I am getting the same result. Why? Please help me to understand this.
Because .raw(..) [Django-doc] just takes a raw query and executes it. The model from which the raw is performed is irrelevant.
We can generate a query that looks like:
from django.db.models import Q
Product.objects.filter(
Q(photo__photo_flag__isnull=True) | Q(photo__photo_flag='yes'),
Q(likedislike__product_liked_by_id_id=2)
)
So here we accept all Products for which a related Photo object has a flag that is NULL (this also happens in case the JOIN does not yield any flags), or the photo_flag is 'yes'). Furthermore there should be a Likedislike object where the liked_by_id_id is 2.
Note that usually a ForeignKey [Django-doc] has no _id suffix, or id_ prefix. It is also a bit "odd" that you set a default=0 for this, especially since most databases only assign strictly positive values as primary keys, and it makes no sense to inherently prefer 0 over another object anyway.
Something like this:
user_i_care_about = User.objects.get(username='user2')
productlikedislike_set = models.Prefetch('productlikedislike_set',
ProductLikeDislike.objects.select_related('product_liked_by') \
.filter(product_liked_by=user_i_care_about) \
.order_by('id'))
photo_set = models.Prefetch('photo_set', Photo.objects.all()) # this is here incase you need to a select_related()
products = Product.objects.prefetch_related(photo_set, productlikedislike_set) \
.filter(models.Q(photo__cover_photo_flag='yes') | models.Q(photo__isnull=True)) \
.filter(productlikedislike__product_liked_by=user_i_care_about)
Then you can use:
for product in products:
for pic in product.photo_set.all():
print(x.file.name)
# every product here WILL be liked by the user
if your models look something like this:
class Product(models.Model):
# category = models.ForeignKey(Category, on_delete=models.CASCADE) # TODO: uncomment, didnt want to model this out
name = models.CharField(max_length=200, db_index=True)
slug = models.SlugField(max_length=200, db_index=True)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2) # Not used FloatField to avoid rounding issues # this is correct, no need to explain this, anyonw that works with django, gets this.
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
contact = models.BigIntegerField(default=None,blank=True, null=True)
created_by = models.CharField(max_length=200, default=None, blank=True, null=True)
uploaded_by_id = models.IntegerField(default=0) # TODO: use ForeignKey(User) here!!!
status = models.IntegerField(default=0) # 0-->Active,1-->Inactive # TODO: learn to use `choices`
mark_as_sold = models.IntegerField(default=0) # 0-->not sold,1-->sold # TODO: there is something called `BooleanField` use it!
class Meta:
ordering = ('-created',)
index_together = (('id', 'slug'),) # we want to query product by id and slug using together index to improve performance
def get_absolute_url(self):
return reverse('olx:edit_product', kwargs={'pk': self.pk})
def __str__(self):
return self.name
class Photo(models.Model):
product = models.ForeignKey(Product, null=True,on_delete=models.CASCADE, db_column='reference_id')
photo_type = models.CharField(max_length=70, db_index=True)
file = models.FileField(upload_to='photos/', default='NoImage.jpg')
cover_photo_flag = models.CharField(default=0, max_length=5, db_index=True) # TODO: learn to use `choices`, and you use "yes" / "no" -- and the default is 0 -- FIX THIS!!
uploaded_at = models.DateTimeField(auto_now_add=True)
uploaded_by_id = models.IntegerField(default=0) # TODO: use ForeignKey(User) here!!!
status = models.IntegerField(default=0) # 0-->Active,1-->Inactive # TODO: learn to use `choices` -- perhaps just call this "is_active" and make it a bool
class Meta:
ordering = ('-uploaded_at',)
class ProductLikeDislike(models.Model):
product = models.ForeignKey(Product, models.SET_DEFAULT, default=0) # TODO: default=0?? this is pretty bad. models.ForeignKey(Product, models.SET_NULL, null=True) is much better
product_liked_by = models.ForeignKey(User, models.SET_DEFAULT, default=0, db_column='product_liked_by_id') # TODO: default=0?? this is pretty bad. models.ForeignKey(ForeignKey, models.SET_NULL, null=True) is much better
status = models.BooleanField(default=False) # TODO: rename, bad name. try something like "liked" / "disliked" OR go with IntegerField(choices=((0, 'Liked'), (1, 'Disliked')) if you have more than 2 values.
A full example WITH tests can be seen here: https://gist.github.com/kingbuzzman/05ed095d8f48c3904e217e56235af54a

How to POST Model with Many to Many through in Django REST

I have a model with a many to many connection. I would like to make this model available in Django REST. By default such a model is read only, but I would also like to write. Furthermore, it would be great to get the information of the through connection integrated into the GET as a nested model.
...
class KeyDateCase(models.Model):
...
diagnoses_all_icd_10 = models.ManyToManyField(
'ICD10', through='CaseICD10Connection')
...
class CaseICD10Connection(models.Model):
case = models.ForeignKey('KeyDateCase', on_delete=models.CASCADE)
icd_10 = models.ForeignKey('ICD10', on_delete=models.CASCADE)
is_primary = models.BooleanField(default = False)
certainty = models.CharField(
max_length=1,
choices=CERTAINTY_CHOICES,
default='G',
)
class ICD10(models.Model):
primary_key_number = models.CharField(max_length=10, primary_key=True)
star_key_number = models.CharField(max_length=10, blank=True, null=True)
additional_key_number = models.CharField(
max_length=10, blank=True, null=True)
preferred_short_description = models.CharField(max_length=128, )
...
class KeyDateCaseViewSet(viewsets.ModelViewSet):
???
class KeyDateCaseSerializer(serializers.ModelSerializer):
???
How can I achieve this? What should my view and serializer look like?
Normally I workaround by indirect way by POST to through table and implement nested-create(). Please provide me more information if my answer is inaccurate.
models.py
from django.db import models
class ICD10(models.Model):
primary_key_number = models.CharField(max_length=10, primary_key=True)
star_key_number = models.CharField(max_length=10, blank=True, null=True)
additional_key_number = models.CharField(max_length=10, blank=True, null=True)
preferred_short_description = models.CharField(max_length=128, )
def __str__(self):
return f'{self.primary_key_number} {self.star_key_number}'
class CaseICD10Connection(models.Model):
case = models.ForeignKey('KeyDateCase', related_name='connections', related_query_name='key_date_cases', on_delete=models.CASCADE)
icd_10 = models.ForeignKey('ICD10', related_name='connections', related_query_name='icd_10s', on_delete=models.CASCADE)
is_primary = models.BooleanField(default=False)
certainty = models.CharField(max_length=1, default='G', )
class KeyDateCase(models.Model):
name = models.CharField(max_length=20)
diagnose_all_icd_10 = models.ManyToManyField(ICD10, related_name='icd10s', related_query_name='icd10s',
through=CaseICD10Connection)
serializers.py
from rest_framework import serializers
from keydatecases.models import KeyDateCase, ICD10, CaseICD10Connection
class KeyDateCaseSerializer(serializers.ModelSerializer):
class Meta:
model = KeyDateCase
fields = [
'id',
'name',
'diagnose_all_icd_10',
]
read_only_fields = ['id', 'diagnose_all_icd_10']
class ICD10Serializer(serializers.ModelSerializer):
class Meta:
model = ICD10
fields = [
'primary_key_number',
'star_key_number',
'additional_key_number',
'preferred_short_description',
]
class CaseICD10ConnectionSerializer(serializers.ModelSerializer):
case = KeyDateCaseSerializer()
icd_10 = ICD10Serializer()
class Meta:
model = CaseICD10Connection
fields = [
'case',
'icd_10',
'is_primary',
'certainty',
]
def create(self, validated_data) -> CaseICD10Connection:
# import ipdb;
# ipdb.set_trace()
# create key_date_case
key_date_case = KeyDateCase.objects.create(**validated_data.get('case'))
# create icd10
icd10 = ICD10.objects.create(**validated_data.get('icd_10'))
# create connection
conn = CaseICD10Connection.objects.create(
case=key_date_case, icd_10=icd10, is_primary=validated_data.get('is_primary'),
certainty=validated_data.get('certainty')
)
return conn
viewsets.py
from rest_framework import viewsets
from keydatecases.api.serializers import CaseICD10ConnectionSerializer
from keydatecases.models import CaseICD10Connection
class CaseICD10ConnectionViewSet(viewsets.ModelViewSet):
permission_classes = ()
queryset = CaseICD10Connection.objects.all()
serializer_class = CaseICD10ConnectionSerializer
My Repository:
I share my repository with many questions. Please do not mind it.
https://github.com/elcolie/tryDj2
In regards to creating or updating nested objects, the documentation actually has a great example. I would provide you a better one if I could. If there is anything confusing in the example, happy to explain it here.
If you follow this approach, your GET requests will expand the nested objects automatically for you.