My current project is to generate a spending report from the following tables. The complete report is to show a user's spending $ breakdown by Franchise's retail category, such as
User 1
retail_category 1: $20
retail_category 2: $30
retail_category 3: $35
User 2
retail_category 1: $10
retail_category 2: $15
retail_category 3: $5
Here are the tables:
class User(models.Model):
id_user = models.AutoField(primary_key = True)
class Franchises(models.Model):
id_franchise = models.AutoField(primary_key=True)
retail_category = models.IntegerField(default=99) # values are 1 to 13
class Stores(models.Model):
id_store = models.AutoField(primary_key=True)
franchise = models.ForeignKey(Franchises, db_column='id_franchise')
class Receipts(models.Model):
id_receipt = models.AutoField(primary_key=True)
store = models.ForeignKey(Stores, db_column='id_store')
user = models.ForeignKey(User, db_column='id_user')
grand_total = models.DecimalField(max_digits=19, decimal_places=4)
I'd appreciate any raw mysql or django model query. Thanks,
Hopefully I'm translating your django schema spec to raw mysql correctly:
SELECT user, retail_category, SUM(grand_total)
FROM Receipts
INNER JOIN Stores ON Receipts.store = Stores.id_store
INNER JOIN Franchises ON Stores.franchise = Franchises.id_franchise
GROUP BY user, retail_category;
Related
So this is my model:
class InAndOut(models.Model):
quantity = models.FloatField()
date= models.DateField(null=True)
type = models.CharField(max_length=12)
id_product = models.ForeignKey(Products, on_delete=models.CASCADE)
I want to query distinct values based on id_product and for each one the difference quantity based on type field("in" or "out"):
So a real example would look like:
quantity = 1500
type = In
id_product = Gas
quantity = 300
type = Out
id_product = Gas
query - Gas 1200
please use this code.
qs =InAndOut.objects.filter(id_product='Gas')
diff_value=(qs.filter(types='In').annotate(Sum('quantity')).values()[0]['quantity__sum'] - qs.filter(types='Out').annotate(Sum('quantity')).values()[0]['quantity__sum'])
This code working for me.
Using the example below, i'm trying to make a single query that will get my list of offices, and pull the next upcoming visit from the child table.
class Office(db.Model):
id = db.Column(db.Integer, primary_key=True)
office_name = db.Column(db.String(100))
visits = db.relationship('Visit', backref='office', lazy='select', order_by='desc(Visit.visit_date)')
class Visit(db.Model):
id = db.Column(db.Integer, primary_key=True)
visit_date = db.Column(db.Date)
office_id = db.Column(db.Integer, db.ForeignKey('office.id'))
I've been able to create a query in raw SQL that will return what i need:
SELECT * FROM office
LEFT OUTER JOIN ( SELECT office_id, visit_date FROM visit WHERE visit_date >= date('now')
GROUP BY office_id )
AS next_vis ON id = next_vis.office_id
But i haven't been able to convert the above in SQLAlchemy.
Closest i've got to is this:
next_vis = db.session.query(Visit.office_id, Visit.visit_date).filter(
Visit.visit_date >= datetime.utcnow().date()).order_by(
Visit.visit_date.asc()).group_by(Visit.office_id).subquery()
offices = db.session.query(Office, next_vis.c.visit_date).outerjoin(
next_vis, Office.id == next_vis.c.office_id).order_by(
Office.office_name.asc())
But the only problem is it returns a tuple of (office, date) but ideally i want it returned as a single object. Is that not possible?
Thanks!
If anyone is interested i went about this a slightly different way.
I switched from a join query to adding a column property in my Office model:
class Office(db.Model):
id = db.Column(db.Integer, primary_key=True)
office_name = db.Column(db.String(100))
visits = db.relationship('Visit', backref='office', lazy='select',
order_by='desc(Visit.visit_date)')
next_vis = column_property(
select([Visit.visit_date]).where(
and_(Visit.office_id == id, Visit.visit_date >= db.func.current_date())).order_by(
Visit.visit_date.asc()).correlate_except(Visit))
Now when i do Office.query.all() i can do:
for i in Office.query.all():
print(i.next_vis)
If i've overlooked anything please let me know!
Thanks,
I have a Django 1.9 project implementing small chat app. All messages from a certain recipient are grouped into dialogs, so the models are defined as follows:
class Dialog(models.Model):
# Some fields
class Message(models.Model):
dialog = models.ForeignKey(Dialog, ...)
text = models.TextField()
is_read = models.BooleanField(default = False)
My goal is to render a template with a table that renders dialogs. And for each dialog in the table, I need to see
the number of unread messages and
the text of the last message.
To illustrate, consider mock-data below:
Input:
id dialog_id message is_read
1 1 Hello, sir false
2 1 My name is true
3 1 Jack true
4 2 This site false
5 2 is perfect false
6 2 Cheers false
Desired output:
dialog_id last_message_in_dialog unread_messages_count
1 Jack 1
2 Cheers 3
In pure mysql, I would write a query like this:
select
a.dialog_id,
text as last_message_in_dialog,
(select count(*) from message
where dialog_id = a.dialog_id and is_read = false) as unread_messages_count
from message a
where id in (select max(id) from message group by dialog_id)
In Django terms, I have the code below:
max_id_qs = Message.objects.\
values('dialog__id').\
annotate(max_id = Max('id'),).values('max_id')
qs = Message.objects.filter(id__in = max_id_qs).\
values('dialog__id', 'text')
This code serves well to fetch the last message in each dialog. However, the problem is that I can't figure out how to implement the subquery (select count(*) from message where dialog_id = a.dialog_id and is_read = false) in Django. Maybe my total approach with max_id_qsis wrong, and there's more elegant and clear way to implement the query in Django ORM?
I've spent an entire day trying to solve this issue. help me please !
This will work :-
allDistinctIdWithNotReadMsg =
Message.objects.filter(is_read=False).values('id').annotate(the_count=Count('is_read',distinct('id')))
for ids in allDistinctIdWithNotReadMsg:
lastMsg = Message.objects.filter(dialog_id=ids['id']).order_by("-id")[0]
for msg in lastMsg:
print ids['id'] ,msg.message,ids['the_count']
The situation is i have a database full of test results split into different test sets. Each test has a name, result , start time , start date , ... , what currently happens is over the week test sets can be run multiple times , giving multiple test results under a test set
Currently when i want to get the latest result of each test under a test set i am querying for the distinct test names, and then for each distinct name i am querying for that name and ordering by startDate and startTime to get the latest. This is a pain because when i have a test set with over 100 different tests it degrades substantially.
What im trying to do is to perform what i want in one call of django.objects...
Here is the mysql to effectively represent what i want to achieve:
select testName,result,MAX(startDate),MAX(startTime),othertestinfo from testset where testset_id = 'UniqueID' group by testName;
Im having a hard time trying to figure this out in django , if its even possible.
Any help would be much appreciated.
Thanks
Update 23/1/12
Models for what i am using.
class testCase(models.Model):
id = models.AutoField(primary_key=True)
testName = models.CharField(max_length=50)
result = models.CharField(max_length=50)
precision = models.CharField(max_length=10)
fileLocation = models.CharField(max_length=150)
testset_id = models.ForeignKey(testset)
machine = models.CharField(max_length=15)
startDate = models.DateField()
startTime = models.TimeField()
class testset(models.Model):
testsetID = models.CharField(max_length=100, primary_key=True)
testsetName = models.CharField(max_length=40)
platformName = models.CharField(max_length=15)
osName = models.CharField(max_length=15)
executionName = models.CharField(max_length=40)
version = models.CharField(max_length=10)
software = models.CharField(max_length=20)
runType = models.CharField(max_length=20)
You can give a try to the following:
t = testset.objects.values('testName').annotate(Max('startDate'),Max('startTime'))
This would give you a list of the objects' values-dictionaries containing key-value pairs of testName, startDate, startTime for the required condition.
You would get the condition fulfilled in this but you can try experimenting with this to get all the columns.
I have a table posts and it stores 3 types of post, Topic, Reply and Comment. Each one has its parent id.
# Single table inheritance
class Post(Base):
__tablename__ = 'posts'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('posts.id'))
discriminator = Column(String(1))
content = Column(UnicodeText)
added_at = Column(DateTime)
__mapper_args__ = {'polymorphic_on': discriminator}
class Topic(Post):
replies = relation("Reply")
__mapper_args__ = {'polymorphic_identity': 't'}
class Reply(Post):
comments = relation("Comment")
__mapper_args__ = {'polymorphic_identity': 'r'}
class Comment(Post):
__mapper_args__ = {'polymorphic_identity': 'c'}
And I'm using eagerload_all() to get all the replies and comments belong to one topic:
session.query(Topic).options(eagerload_all('replies.comments')).get(topic_id)
My question is, if I want to get only replies and those replies' comments in certain time period, for example, this week, or this month. How should I use filter to achieve this?
Thank you
The use of eagerload_all will only query for the children of an object Topic immediately rather on first request to the Replies and/or Comments, but since you load the Topic object into the session, all its related children will be loaded as well. This gives you the first option:
Option-1: Filter in the python code instead of database:
Basically create a method on the Topic object similar to
class Topic(Post):
...
def filter_replies(self, from_date, to_date):
return [r for r in self.replies
if r.added_at >= from_date
and r.added_at <= to_date]
Then you can do similar code on Replies to filter Comments or any combination of those. You get the idea.
Option-2: Filter on the database level:
In order to achieve this you need not load the Topic object, but filter directly on the Reply/Comment. Following query returns all Reply for a given Topic with a date filter:
topic_id = 1
from_date = date(2010, 9, 5)
to_date = date(2010, 9, 15)
q = session.query(Reply)
q = q.filter(Reply.parent_id == topic_id)
q = q.filter(Reply.added_at >= from_date)
q = q.filter(Reply.added_at <= to_date)
for r in q.all():
print "Reply: ", r
The version for the Comment is just a little bit more involved as you require an alias in order to overcome the SQL statement generation issue as all your objects are mapped to the same table name:
topic_id = 1
from_date = date(2010, 9, 5)
to_date = date(2010, 9, 15)
ralias = aliased(Reply)
q = session.query(Comment)
q = q.join((ralias, Comment.parent_id == ralias.id))
q = q.filter(ralias.parent_id == topic_id)
q = q.filter(Comment.added_at >= from_date)
q = q.filter(Comment.added_at <= to_date)
for c in q:
print "Comment: ", c
Obviously you can create a function that would combine both peaces into a more comprehensive query.
In order to achieve this week or this month type of queries you can either convert these filter into a date range as shown above or use the expression.func functionality of SA.