I want use Django ORM. I build SQL query:
select itinerary.id, count(users.home_location_id) from itinerary_itinerary as itinerary left join (select to_applicationuser_id as id, users.home_location_id from custom_auth_applicationuser_friends as friends join custom_auth_applicationuser as users on friends.to_applicationuser_id = users.id where from_applicationuser_id = 28)
as users on itinerary.location_id = users.home_location_id
WHERE user_id = 28
GROUP BY itinerary.id, users.home_location_id
Could anybody tell me how make left join with table from subquery?
28 is current user_id.
I use something like:
Itinerary.object.filter(user_id=28).extra(
tables=['(select to_applicationuser_id as id, users.home_location_id from custom_auth_applicationuser_friends as friends join custom_auth_applicationuser as users on friends.to_applicationuser_id = users.id where from_applicationuser_id = 28) as users'],
where=['itinerary.location_id = users.home_location_id']
)
But I got error
ProgrammingError relation "(select to_applicationuser_id as id,
users.home_location_id fro" does not exist
UPD
Models (it is just simple scheme):
class ApplicationUser(models.Model):
name = models.CharField(max_length=255)
home_location = models.ForeignKey(Location)
friends = models.ManyToManyFieled('self')
class Location(models.Model):
loc_name = models.CharFiled(max_length=255)
class Itinerary(models.Model):
user = models.ForeignKey(ApplicationUser)
location = models.ForeignKey(Location)
When you add tables with extra, they get added to the from list, which does not accept an sql statement.
I don't think you need to use extra at all here, you can get a similar query with the ORM without the need to join on a select statement. The following code, using filtering and annotations, will give the same results as much as I was able to understand your query:
ApplicationUser.objects.filter(
Q(itinerary__location_id = F('friends__home_location_id')) |
Q(friends__home_location__isnull=True),
id=28,
).values_list(
'itinerary__id', 'friends__home_location_id'
).annotate(location_count = Count('friends__home_location_id')
).values_list('itinerary__id', 'location_count')
Related
Here are my models
class Student:
user = ForeignKey(User)
department = IntegerField()
semester = IntegerField()
...
class Attendance:
student = ForeignKey(Student)
subject = ForeignKey(Subject)
month = IntegerField()
year = IntergerField()
present = IntegerField()
total = IntegerField()
students = Student.objects.filter(semester=semester)
How can I perform a right join between Student and Attendance models, so that I can get a
queryset with all of the students and attendances` if exists for a student, else null?
The documentation mentions left joins but not right joins.
change left join for table subject
queryset.query.alias_map['subject'].join_type = "RIGHT OUTER JOIN"
You can use such query:
queryset = Student.objects.all().select_related('attendance_set')
student = queryset[0]
# all attendances for the student
attendances = student.attendance_set.all()
With select_related you JOIN'ing Attendance table. Django does not have explicit join ORM method, but it does JOIN internally when you call select_related. Resulting queryset will contain all Student's with joined attendances, and when you will call attencande_set.all() on each student - no additional queries will be performed.
Check the docs for _set feature.
If you want to query only those students who has at least one attendance, you can use such query:
from django.models import Count
(Student.objects.all()
.select_related('attendance_set')
.annotate(n_attendances=Count('attendance_set'))
.filter(n_attendances__gt=0))
I need to use raw sql in my django project. I'm using count command and then I associated it with as command like "the_count" but i got an error. The error like this, the_count does not exist.
And my my code here,
# First Model
class AModel(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_lenth=100)
# Second Model
class BModel(models.Model):
a_model = models.ForeignKey(AModel, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
query = 'SELECT "app_AModel"."id",
(SELECT COUNT(*) FROM "app_BModel" INNER JOIN ON ("app_BModel"."user_id" = "app_AModel"."user_id") WHERE ("app_BModel"."a_model_id" = "app_AModel"."id")) AS "the_count"
FROM "app_AModel"
WHERE ("the_count" = 0)'
BModel.objects.raw(query)
Thank you for yours helps...
From postgreSQL documentation
An output column's name can be used to refer to the column's value in
ORDER BY and GROUP BY clauses, but not in the WHERE or HAVING clauses;
there you must write out the expression instead.
Also you probably want to use GROUP BY and HAVING on my_app table instead so something in a line of following:
SELECT a_model_id, COUNT(*) from app_BModel GROUP BY a_model_id HAVING count(*) > 0
All I want is to write the following SQL query in Python Django syntax. I researched a lot but could not get the result I want. Could you please help me.
SELECT * FROM thread
LEFT JOIN user
ON (thread.user1_id = user.id OR thread.user2_id = user.id)
WHERE user.id = 9
My model:
class Thread(models.Model):
last_message = models.TextField(max_length=100)
user1_id = models.IntegerField()
user2_id = models.IntegerField()
The exact query cannot be created using the Django ORM without resorting to some raw SQL. The problem is the OR in the join condition.
But, since your not selecting any rows from the user table, you can create a different query with the same results.
Start by defining your models using ForeignKeys.
from django.db import models
from django.contrib.auth.models import User
class Thread(models.Model):
last_message = models.TextField(max_length=100)
user1 = models.ForeignKey(User)
user2 = models.ForeignKey(User)
class Meta:
db_table = 'thread' # otherwise it will be: appname_thread
Then you can preform the query.
from django.db.models import Q
threads = Thread.objects.filter(Q(user1__id=9) | Q(user2__id=9))
The resulting SQL will be something like this:
SELECT * FROM thread
LEFT JOIN user AS user1
ON (thread.user1_id = user1.id)
LEFT JOIN user AS user2
ON (thread.user2_id = user2.id)
WHERE (user1.id = 9 OR user2.id = 9)
You can improve this by avoiding the join altogether.
# note the single underscore!
threads = Thread.objects.filter(Q(user1_id=9) | Q(user2_id=9))
Generating the following SQL.
SELECT * FROM thread
WHERE (user1_id = 9 OR user2_id = 9)
If you need to also obtain the user instances in the same query, in which case you really need the join, you have two options.
Either use the first query that includes joins and afterwards select the correct user based in the id in Python.
for thread in threads:
if thread.user1.id == 9:
user = thread.user1
else:
user = thread.user2
Or use raw SQL to get the exact query you want. In this case, you can use the models without the ForeignKeys as you defined them.
threads = Thread.objects.raw('''
SELECT *, user.id AS user_id, user.name as user_name FROM thread
LEFT JOIN user
ON (thread.user1_id = user.id OR thread.user2_id = user.id)
WHERE user.id = 9''')
for thread in threads:
# threads use the ORM
thread.id
# user fields are extra attributes
thread.user_id
thread.user_name
there are two tables:
class TBLUserProfile(models.Model):
userid = models.IntegerField(primary_key=True)
relmusicuid = models.IntegerField()
fansnum = models.IntegerField()
class TSinger(models.Model):
fsinger_id = models.IntegerField()
ftbl_user_profile = models.ForeignKey(TBLUserProfile, db_column='Fsinger_id')
I want to get Tsinger info and then order by TBLUserProfile.fansnum, I know how to write sql query: select * from t_singer INNER JOIN tbl_user_profile ON (tbl_user_profile.relmusicuid=t_singer.Fsinger_id) order by tbl_user_profile.fansnum, but I don't want to use model raw function. relmusicuid is not primary key otherwise I can use ForeignKey to let it work. How can I use django model to achieve this?
You can do like this :
Tsinger.objects.all().order_by('ftbl_user_profile__fansnum')
For information about Django JOIN :
https://docs.djangoproject.com/en/1.8/topics/db/examples/many_to_one/
I want to be able to query through multiple many to many relationships in SQLAlchemy.
I have Users, which are associated to Groups, which are associated to Roles. All associations are many-to-many. I want to get the list of Roles that are associated with the User through the Groups.
Here are my striped down models:
class User(Model):
id = Column(Integer)
groups = relationship('Group', secondary=user_group)
class Group(Model):
id = Column(Integer)
roles = relationship('Role', secondary=role_group)
class Role(Model):
id = Column(Integer)
I have a rough idea of what SQL would be used:
select distinct role.* from role, role_group
where role.id = role_group.role_id
and role_group.group_id in
(select "group".id from "group", user_group
WHERE user_group.user_id = 1
and "group".id = user_group."group.id")
But I am having a hard time figuring out how to translate that into SQLAlchemy...and I am not sure even if the SQL here is the best way to do this or not.
Try this
s = Session()
s.query(Role).join(User.groups).join(Group.roles).filter(User.id==1).all()
it will generate following sql query
SELECT role.id AS role_id
FROM user
JOIN user_group AS user_group_1 ON user.id = user_group_1.user_id
JOIN "group" ON "group".id = user_group_1.group_id
JOIN role_group AS role_group_1 ON "group".id = role_group_1.group_id
JOIN role ON role.id = role_group_1.role_id
WHERE user.id = 1;
however sqlalchemy will only return distinct roles (if you will query Role.id then sqlalchemy will return what sql query actually returns).
I did find a solution to my own question that would generate close to the SQL I was looking for. However, I believe zaquest's answer is much better and will be using that instead. This is just for posterity's sake.
Here is the query I came up with:
s = Session()
s.query(Role).join(Role.groups).filter(
Group.id.in_(s.query(Group.id).join(User.groups)
.filter(User.id == self.id)))
This would generate the following SQL
SELECT role.id AS role_id
FROM role JOIN role_group AS role_group_1 ON role.id = role_group_1.role_id
JOIN "group" ON "group".id = role_group_1.group_id
WHERE "group".id IN
(SELECT "group".id AS group_id
FROM "user" JOIN user_group AS user_group_1 ON "user".id = user_group_1.user_id
JOIN "group" ON "group".id = user_group_1."group.id"
WHERE "user".id = :id_1)
This is similar to the SQL I was looking for. The key that I forgot about was that I can use another query as part of the in operator in SQLAlchemy.