How to get data equivalent to sql query using django orm:
SELECT *
FROM "financeDocuments_documenttemplateline"
LEFT JOIN "financeDocuments_documentinstanceline" ON "financeDocuments_documentinstanceline".template_line_id = "financeDocuments_documenttemplateline".id AND "financeDocuments_documentinstanceline".document_instance_id = 1
WHERE "financeDocuments_documenttemplateline".document_type_id = 1
I use:
document_lines = DocumentTemplateLine.objects.filter(document_type__id = document_instance.document_type.id).select_related('documentinstanceline').values('documentinstanceline__value')
But it generates:
SELECT "financeDocuments_documentinstanceline"."value" FROM "financeDocuments_documenttemplateline" LEFT OUTER JOIN "financeDocuments_documentinstanceline" ON ("financeDocuments_documenttemplateline"."id" = "financeDocuments_documentinstanceline"."template_line_id") WHERE "financeDocuments_documenttemplateline"."document_type_id" = 1
Models are like this one:
class DocumentInstance(models.Model):
company = models.ForeignKey(Company)
period = models.ForeignKey(Period, verbose_name=u'период')
document_type = models.ForeignKey(DocumentType, verbose_name=u'вид документа' )
created = models.DateTimeField('created', auto_now_add=True)
author = models.ForeignKey(User)
class Meta:
unique_together= (('company', 'period', 'document_type'),)
class DocumentInstanceLine(models.Model):
document_instance = models.ForeignKey(DocumentInstance, related_name='lines')
template_line = models.ForeignKey(DocumentTemplateLine)
value = models.FloatField(default=0.00)
comment = models.TextField(blank=True)
class Meta:
unique_together= (('document_instance', 'template_line'),)
How to change code for django orm to add second condition like in my first sql query?
Related
I am trying to join multiple table using django ORM .i have tried several different way but no luck.
from django.db import models
from compositefk.fields import CompositeForeignKey, CompositeOneToOneField
class Company(models.Model):
code = models.DecimalField(db_column='Code', max_digits=38, decimal_places=0)
srccode = models.SmallIntegerField(db_column='SrcCode')
est = models.DateTimeField(db_column='Est')
rownum = models.BigIntegerField(db_column='RowNum')
class Meta:
manage = False
unique_together = (('code', 'srccode'),)
db_table = 'Company'
class Floor(models.Model):
code = models.DecimalField(db_column='Code', max_digits=38, decimal_places=0)
srccode = models.SmallIntegerField(db_column='SrcCode')
depcode = models.DecimalField(db_column='DepCode', max_digits=38, decimal_places=0)
depsrccode = models.SmallIntegerField(db_column='Depsrccode')
floorname = models.CharField(db_column='FloorName')
rownum = models.BigIntegerField(db_column='RowNum')
company = CompositeForeignKey(Company,on_delete=models.CASCADE,to_fields={'code':'code','srccode': 'srccode'})
department= CompositeOneToOneField(Department,on_delete=models.CASCADE,to_fields={'depcode':'depcode','depsrccode': 'depsrccode'})
class Meta:
manage = False
unique_together = (('depcode', 'depsrccode','floorname'),)
db_table = 'floor'
class SubCompany(models.Model):
code = models.DecimalField(db_column='Code', max_digits=38, decimal_places=0)
srccode = models.SmallIntegerField(db_column='SrcCode')
subname = models.CharField(db_column='SubName')
rownum = models.BigIntegerField(db_column='RowNum')
location = models.CharField(db_column='Location')
department = models.CharField(db_column='Department')
company = CompositeForeignKey(Company,on_delete=models.CASCADE,to_fields={'code':'code','srccode': 'srccode'})
class Meta:
manage = False
unique_together = (('code', 'srccode','subname','rownum'),)
db_table = 'SubCompany'
basically i am trying to get data as per below row sql
SELECT Location, Department, Subname, t.* from [Floor] t join [SubCompany] s on t.code = s.code and t.srccode = s.srccode;"
what is the equilant Django Orm of above SQL query.?
is there any alternative solution apart from raw sql in django.?
Thanks
I'm trying to do an aggregate operation between two tables using Django, my models are:
class Cusinetype(models.Model):
hometype_en = models.TextField()
active = models.BooleanField()
hometype_es = models.TextField(blank=True, null=True)
class Meta:
managed = False
db_table = 'cusinetype'
class Foodpreferences(models.Model):
id_client = models.ForeignKey(Client, models.DO_NOTHING, db_column='id_client')
id_cusinetype = models.ForeignKey(Cusinetype, models.DO_NOTHING, db_column='id_cusinetype')
created_at = models.DateTimeField()
class Meta:
managed = False
db_table = 'foodpreferences'
The query that I'm trying to build is:
SELECT
ct.id,
ct.hometype_en,
ct.hometype_es
,
((SELECT COUNT(*)
FROM foodpreferences fp
WHERE fp.id_cusinetype = ct.id AND fp.id_client = 3 ) > 0 ) selected
FROM
Cusinetype ct
I'm trying to generate a model, to store the information of those tables in a single one query, but anything works.
Someone has an idea about how to do it?
serializers.py
class PreferencesSerializer(serializers.ModelSerializer):
selected = serializers.IntegerField()
class Meta:
model = Cusinetype
fields = ('id', 'trucktype_en', 'trucktype_es', 'selected')
views.py
qs = Cusinetype.objects.filter().filter(active = True)
qs = qs.annotate(
selected=Sum(Case(
When(foodpreferences__id_client=3, then=1),
output_field=IntegerField()
))
)
serializers = PreferencesSerializer(qs, many = True)
return Response({ "result": serializers.data })
I have the following models:
class Contest(models.Model):
id_contest = models.AutoField(primary_key=True)
name = models.CharField(max_length=50, blank=False)
class Registration(models.Model):
id_registration = models.AutoField(primary_key=True)
team = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.DO_NOTHING,
related_name='registrations',
related_query_name='registration')
contest = models.ForeignKey(
Contest,
on_delete=models.DO_NOTHING,
related_name='registrations',
related_query_name='registration')
created_at = models.DateTimeField(null=True)
confirmed_at = models.DateTimeField(null=True)
class Submission(models.Model):
id_submission = models.AutoField(primary_key=True)
team = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.DO_NOTHING,
related_name='submissions',
related_query_name='submission')
contest = models.ForeignKey(
Contest,
on_delete=models.DO_NOTHING,
related_name='submissions',
related_query_name='submission')
submitted_at = models.DateTimeField(null=True)
is_valid = models.NullBooleanField()
public_score = models.FloatField(null=True)
And I'm working on a leaderboard query (PostgreSQL) like:
select
r.team_id,
max(t.username) as team_name,
count(s.team_id) as num_submissions,
min(s.public_score) as score,
max(s.submitted_at) as last_submission,
max(r.confirmed_at) as confirmation
from api_registration r
left join auth_user t on (r.team_id = t.id)
left join api_submission s on (r.contest_id = s.contest_id and s.team_id = t.id and s.is_valid = TRUE)
where r.contest_id = 1
group by r.team_id
order by score ASC, last_submission DESC;
Which returns the results I want.
However, when translating into Django QuerySet operations, the closest I've
come is:
leaderboard = Registration.objects \
.filter(contest=contest, contest__submission__is_valid=True) \
.annotate(team_name=Max('team__username'),
num_submissions=Count('team__submission'),
score=Min('contest__submission__public_score'),
last_submission=Max('contest__submission__submitted_at'),
confirmation=Max('confirmed_at')) \
.order_by('score', '-last_submission')
which generates the query:
SELECT
"api_registration"."id_registration",
"api_registration"."team_id",
"api_registration"."contest_id",
"api_registration"."created_at",
"api_registration"."confirmed_at",
MAX("api_registration"."confirmed_at") AS "confirmation",
MAX("api_submission"."submitted_at") AS "last_submission",
MAX("auth_user"."username") AS "team_name",
MAX("api_submission"."public_score") AS "score",
COUNT(T5."id_submission") AS "num_submissions"
FROM "api_registration" INNER JOIN "api_contest" ON ("api_registration"."contest_id" = "api_contest"."id_contest")
INNER JOIN "api_submission" ON ("api_contest"."id_contest" = "api_submission"."contest_id")
INNER JOIN "auth_user" ON ("api_registration"."team_id" = "auth_user"."id")
LEFT OUTER JOIN "api_submission" T5 ON ("auth_user"."id" = T5."team_id")
WHERE ("api_registration"."contest_id" = 1
AND "api_submission"."is_valid" = True)
GROUP BY "api_registration"."id_registration"
ORDER BY "score" ASC, "last_submission" DESC;
And doesn't properly compute the correct number of submissions per team.
Any help on how to define the Django QuerySet operations to obtain correct results?
Try change this:num_submissions=Count('team__submission'), for num_submissions=Count('team_id'),.
This is to group according to the team_id of the table registration.
In Django views, I want to fetch all details(Workeraccount.location,Workeravail.date, Workerprofile.*) for any particular wid=1.
SQL Query:
select * from Workeraccount,Workeravail,Workerprofile where Workerprofile.wid=1 and Workerprofile.wid=Workeravail.wid and Workeraccount.wid=Workerprofile.wid;
The corresponding models are as follows:
class Workeraccount(models.Model):
wid = models.ForeignKey('Workerprofile', db_column='wid', unique=True)
location = models.ForeignKey(Location, db_column='location')
class Meta:
managed = False
db_table = 'workerAccount'
class Workeravail(models.Model):
wid = models.ForeignKey('Workerprofile', db_column='wid')
date = models.DateField()
class Meta:
managed = False
db_table = 'workerAvail'
class Workerprofile(models.Model):
wid = models.SmallIntegerField(primary_key=True)
fname = models.CharField(max_length=30)
mname = models.CharField(max_length=30, blank=True, null=True)
lname = models.CharField(max_length=30)
gender = models.CharField(max_length=1)
age = models.IntegerField()
class Meta:
managed = False
db_table = 'workerProfile'`
You can do this:
workprofile = Workerprofile.objects.filter(id=1).first()
all_worker_avails = workprofile.workeravail_set.all()
all_workeraccounts = workprofile.workeraccount_set.all()
As Workeraccount and Workeravail are related through Workerprofile, you can get one queryset easily - you will need two separate ones.
You can also do the following:
all_worker_avails = Workeravail.objects.filter(wid=workprofile)
...
Here is how you can do it with only one database call:
workprofile = Workerprofile.objects.get(pk=1)
.select_related('workeravail_set', 'workerprofile_set')
This will fetch all the data for you at once, which can then be used with:
workprofile.workerprofile_set.location #Gets the Workeraccount.location
workprofile.workeravail_set.date #Gets the Workeravail.date
workprofile.fname #Example of Workerprofile.*
As an aside, if you want a shorter way to reference the foreign objects than the "*_set" method, you can set a related_name like
class Workeraccount(models.Model):
wid = models.ForeignKey('Workerprofile', db_column='wid', unique=True, related_name='waccount')
...
And then replace workeraccount_set with waccount
I need to filter a queryset by comparing dates on related objects, but the filter its ignored.
My resumed model is:
class Requerimiento(models.Model):
nombre = models.CharField(max_length=30)
fecha_publicacion = models.DateField(default=datetime.now)
fecha_aprobacion = models.DateField(default=datetime.now, blank=True)
aprobacion = models.BooleanField()
autor = models.ForeignKey(User, null=True, blank=True)
def __unicode__(self):
return self.nombre
class Contexto(models.Model):
nombre = models.CharField(max_length=30)
requerimientos = models.ManyToManyField(Requerimiento,
related_name = 'contextos')
def __unicode__(self):
return self.nombre
class Proyecto(models.Model):
nombre = models.CharField(max_length=30)
cod_proyecto = models.CharField(max_length=10)
contextos = models.ManyToManyField('Contexto', related_name = 'proyectos')
fecha_publicacion = models.DateField(default=datetime.now)
autor = models.ForeignKey(User, null=True, blank=True)
And the queryset is:
queryset=Proyecto.objects.filter(pk=proyecto_id)\
.prefetch_related('contextos')\
.prefetch_related('contextos__requerimientos')\
.filter(contextos__requerimientos__fecha_aprobacion__lte=F('fecha_publicacion'))
What i'm doing wrong?
EDIT
Looking with debug-toolbar i see the following with proyect id 2 selected in the following code
requerimientos = ProyectoFilter(request.GET,
queryset=Proyecto.objects.filter(pk=proyecto_id)
.distinct()
.prefetch_related('contextos')
.prefetch_related('contextos__requerimientos')
.filter(contextos__requerimientos__fecha_aprobacion__lte=F('fecha_publicacion')))
First query:
SELECT ••• FROM "sgrs_proyecto" INNER JOIN "sgrs_proyecto_contextos"
ON ( "sgrs_proyecto"."id" = "sgrs_proyecto_contextos"."proyecto_id" )
INNER JOIN "sgrs_contexto" ON ( "sgrs_proyecto_contextos"."contexto_id" =
"sgrs_contexto"."id" ) INNER JOIN "sgrs_contexto_requerimientos"
ON ( "sgrs_contexto"."id" = "sgrs_contexto_requerimientos"."contexto_id" )
INNER JOIN "sgrs_requerimiento" ON ( "sgrs_contexto_requerimientos"."requerimiento_id" = "sgrs_requerimiento"."id" )
WHERE ("sgrs_proyecto"."id" = 2 AND "sgrs_requerimiento"."fecha_aprobacion"
<= "sgrs_proyecto"."fecha_publicacion")
Second query:
SELECT ••• FROM "sgrs_contexto" INNER JOIN "sgrs_proyecto_contextos"
ON ( "sgrs_contexto"."id" = "sgrs_proyecto_contextos"."contexto_id" )
WHERE "sgrs_proyecto_contextos"."proyecto_id" IN (2)
ORDER BY "sgrs_contexto"."indice_riesgo" DESC
Third query:
SELECT ••• FROM "sgrs_requerimiento" INNER JOIN "sgrs_contexto_requerimientos"
ON ( "sgrs_requerimiento"."id" = "sgrs_contexto_requerimientos"."requerimiento_id" )
WHERE "sgrs_contexto_requerimientos"."contexto_id" IN (3, 7, 6, 4, 2, 5, 1)
The date filter is in the first query and should be in the third, is this correct?
How can i get the correct filter position?
Thanks
First of all the usage of prefetch_related is not correct. See first note in https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related. Second, you might want to use distinct() with queries with filters on m2m relation.
The query you have posted should give you all Proyecto objects that have at least one related Requerimiento with fecha_aprobacion less or equal than its' own fecha_aprobacion. What do you expect from the query and what do you get?
OK, finally got it.
I took out the filter from the queryset and make this comparison in the template.
Just added the following:
...
{% for requerimiento in contexto.requerimientos.all %}
{% if requerimiento.fecha_aprobacion <= proyecto.fecha_publicacion %}
...
Hope this helps others.