I'm using SqlAlchemy to store some objects with a DateTime field:
my_date = Field(DateTime())
I'd like to run a query to retrieve the most recent few objects (Entities with the my_date field that are the most recent).
I've tried the following:
entities = MyEntity.query.order_by(MyEntity.time).limit(3).all()
entities = MyEntity.query.order_by(-MyEntity.time).limit(3).all()
But these queries return the same objects in the same order. The SqlAlchemy documentation notes the use of the '-' to reverse the order, but I'm surely missing something here.
Can anyone help?
You can do it like this:
entities = MyEntity.query.order_by(desc(MyEntity.time)).limit(3).all()
You might need to:
from sqlalchemy import desc
Here's some documentation.
Another option is this:
stmt = select([users_table]).order_by(users_table.c.name.desc())
entities = MyEntity.query.order_by(MyEntity.my_date.desc()).limit(3).all()
should work.
You can use like this
from sqlalchemy import desc
db.session.query(MyEntity).order_by(desc(MyEntity.time))
Related
I wish to update a Django model field of objects in a queryset. To be specific, I want to add a prefix on one of the fields i.e. if an object has a name like 'Wilson', I want to prefix it with 'OLD', then it will become 'OLDWilson'.
I can think of the following using loops:
my_objs = MyObjects.objects.filter(name='some_name') # This has over 40000 records
for obj in my_objs:
obj.name = 'OLD{0}'.format(obj.name)
obj.save()
I was hoping of a more elegant way to take advantage of the UPDATE method as specified here: Django Mass Update
Something like the following:
MyObjects.objects.filter(name='some_name').update(name='OLD+name_here')
Any pointers on how I can achieve this?
Try something like this :
from django.db.models import F
Myobj = MyObjects.objects.filter(name='some_name')
Myobj.update(name='OLD'+ F('name'))
I know this question is almost 5 years old. But, with hopes that this helps the answer be more visible - here goes.
Use Concat from django.db.models.functions like so:
from django.db.models.functions import Concat
from django.db.models import Value
MyObjects.objects.filter(name='some_name').update(name=Concat(Value'OLD', 'name'))
That last line returns the number of rows affected by the update.
This actually works in the latest version of Django as of May 2022
from django.db.models import Value
from django.db.models.functions import Concat
query = MyObjects.objects.filter(name='some_name')
query.update(name=Concat(Value("OLD"), "name"))
I need to build a complex query and I prefer to use raw postgres. But the query returns a sqlalchemy.engine.result.ResultProxy object and when I iterate through that each of those objects is a sqlalchemy.engine.result.RowProxy object
search_term = "%{0}%".format(d)
items = db.engine.execute("SELECT inventory.id,inventory.location,inventory.amount,inventory.units, plant_material.variety FROM inventory LEFT JOIN plant_material ON inventory.plant_material_id = plant_material.id WHERE plant_material.variety ILIKE %s", (search_term))
This standard query returns my model object that I define in Marshmallow, <class 'app.models.Inventory'>:
Inventory.query.filter(Inventory.common_name.like(search_term)).limit(10)
How can I return the models.Inventory object and use raw sql?
If you are curious about my model definitions check out this gist
https://docs.sqlalchemy.org/en/14/orm/queryguide.html#selecting-orm-entities-and-attributes
from sqlalchemy.sql import text, select
db.session.execute(select(ModelClass).from_statement(text("SELECT ..."))).scalars().all()
You can use something like this:
query = db.engine.execute("SELECT inventory.id...")
for row in query:
print(row['id'])
...
Given a table
class Order(db.Model):
created_at = db.Column(db.DateTime)
days = db.Column(db.Integer)
I need to compose a query with FROM statement like this: Order.created_at + Order.days < datetime.now(). The simplest way doesn't work, since the result of addition integer to datetime is double :) This conclusion I've made after practical experiment with MySQL.
After searching a little I've found out correct SQL statement for MySQL which solves described issue:
SELECT *
FROM orders o
WHERE o.created_at + INTERVAL o.days DAY < '2014-06-10 14:22:00';
And what I'd like to ask is how to code the query above for sqlalchemy filter?
I've found one article how to use Intervals here on stackoverflow, but DATEADD is missing in MySQL and I have no ideas where I need to bind an Interval.
Sorry for my poor English, I hope I could explain my problem correct :)
UPD: Maybe the right thing to define days as Interval, but currently it's not an option.
MySQL has a function called TIMESTAMPADD which seems to do what you want. Here's how to use it in a query.
session.query(Order).filter(func.timestampadd(text('DAY'), Order.days, Order.created_at) < datetime(2014, 6, 10, 14, 22))
from sqlalchemy import select, func
query = (session.query(Orders).filter(
func.DATEADD('day', Orders.days, Orders.created_at) == '2014-06-10 14:22:00'))
Old question, but for anyone using PSQL / SQlAlchemy 1.0.10+ you can use the below:
from sqlalchemy.sql import cast
db = SQLAlchemy() # Instantiated
Order.query.filter(
Order.created_at > cast('1 DAY', db.Interval) * Order.day
).all()
I have this query:
mps = (
session.query(mps) .filter_by(idc = int(c.idc))
.filter_by(idmp = int(m.idmp))
.group_by(func.day(mps.tschecked))
).all()
My problem is, that I don't know how to extract (with sqlalchemy) the max/min/avg value from a table...
I find this: Database-Independent MAX() Function in SQLAlchemy
But I don't know where to use this func.max/min/avg...
Can someone tell me how to do this? Can you give me an example?
The following functions are available with from sqlalchemy import func:
func.min
func.max
func.avg
Documentation is available here.
You can use them i.e. in the query() method.
Example:
session.query(self.stats.c.ID, func.max(self.stats.c.STA_DATE))
(just like you use aggregate functions in plain SQL)
Or just use an order_by() and select the first or last element. . .
I have a model similar to the following:
class Review(models.Model):
venue = models.ForeignKey(Venue, db_index=True)
review = models.TextField()
datetime_created = models.DateTimeField(default=datetime.now)
I'd like to query the database to get the total number of reviews for a venue grouped by day. The MySQL query would be:
SELECT DATE(datetime_created), count(id)
FROM REVIEW
WHERE venue_id = 2
GROUP BY DATE(datetime_created);
What is the best way to accomplish this in Django? I could just use
Review.objects.filter(venue__pk=2)
and parse the results in the view, but that doesn't seem right to me.
This should work (using the same MySQL specific function you used):
Review.objects.filter(venue__pk=2)
.extra({'date_created' : "date(datetime_created)"})
.values('date_created')
.annotate(created_count=Count('id'))
Now that Extra() is being depreciated a more appropriate answer would use Trunc such as this accepted answer
Now the OP's question would be answered as follows
from django.db.models.functions import TruncDay
Review.objects.all()
.annotate(date=TruncDay('datetime_created'))
.values("date")
.annotate(created_count=Count('id'))
.order_by("-date")
Just for completeness, since extra() is aimed for deprecation, one could use this approach:
from django.db.models.expressions import DateTime
Review.objects.all().\
annotate(month=DateTime("timestamp", "month", pytz.timezone("Etc/UTC"))).\
values("month").\
annotate(created_count=Count('id')).\
order_by("-month")
It worked for me in django 1.8, both in sqlite and MySql databases.
If you were storing a date field, you could use this:
from django.db.models import Count
Review.objects.filter(venue__pk = 2)
.values('date').annotate(event_count = Count('id'))
Because you're storing datetime, it's a little more complicated, but this should offer a good starting point. Check out the aggregation docs here.
Also you can define custom function:
from django.db.models.expressions import Func
# create custom sql function
class ExtractDateFunction(Func):
function = "DATE" # thats the name of function, the way it mapped to sql
# pass this function to annotate
Review.objects.filter(venue__pk=2)
.annotate(date_created=ExtractDateFunction("datetime_created"))
.values('date_created')
.annotate(created_count=Count('id'))
Just make sure that your DB engine supports DATE function