Difference on field based on other field value? - mysql

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.

Related

SQL Alchemy and datetime

I have sqlite base with a table Rating.
ID|Time|Clicks|
1|2020-04-02 20:20| 250
2|2020-04-03 18:20| 50
3|2020-04-04 22:50| 100
My class looks like this:
class Rating(base):
__tablename__ = 'Rating'
id = Column('ID', Integer, primary_key = True)
clicks = Column('Clicks', Integer)
time = Column('Time', Date)
I wanna show Clicks for a specific date.
date_i_need = datetime.date(2020, 4, 2)
q = test = session.query(Rating).filter_by(time = date_i_need).first()
I tried to change a type from Date to Datetime and Timestamp, but it always returns None.
Any guess?
You can specify datetime.date in statement. I think the problem is with syntax. Use ==:
Please try this:
date_i_need = datetime.date(2020, 4, 2)
q_test = session.query(Rating).filter(Rating.time == date_i_need).first()

Trouble with sqlalchemy join query - get the next date from child

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,

Generate a spending report from the following tables

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;

Django , Query to get certain values with a distinct name and the latest date and time

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.

How to set filter to get children in certain time period by eagerload_all() at SqlAlchemy

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.