Is there a way I could add an attribute to all query objects using annotate? I basically just need to get a value from an m2m relationship of the object and save it as an attribute of the object.
Something like this:
query.annotate(value_to_be_added=("value_from_m2m"))
Basically I have two different queries of the same model, one query A needs to have a "value" changed or added for all of its objects (and that value comes from the m2m relationship). Query B doesn't need to have those values changed.
How would I do this?
I solved it. What needs to be used is just a simple filter F().
from django.db.models import F
query.annotate(value_to_be_added=F("value_from_m2m"))
https://docs.djangoproject.com/en/3.0/ref/models/expressions/#f-expressions
Related
I have two classes declared as follows:
from mongoengine import Document, fields, DynamicDocument
class Booking(DynamicDocument):
booking_id=fields.StringField(required=True)
pickup_timestamp=fields.DateTimeField()
class Assignment(Document):
created_timestamp=fields.DateTimeField(default=datetime.datetime.utcnow)
pickup_time=fields.DateTimeField()
bookings=fields.ListField(fields.ReferenceField(Booking))
My application allows a user to club Bookings together under an Assignment object, by selecting the Booking objects from a list on the UI.
When creating the assignment object I automatically set the pickup time to the least value from the Booking pickup_timestamp like so -
assignment.pickup_time = min([booking.pickup_timestamp for booking in assignment.bookings])
However I also need to set other attributes on the assignment object based on other fields in the earliest Booking object.
My question - Is there a way to sort a ListField containing ReferenceFields by a field on the referenced objects?
I did find this answer, however it does not talk about ReferenceFields in the ListField. Tried setting the field type to SortedListField as well, but I wasn't able to figure out how to specify which key to sort on.
Solved with -
assignment.bookings=sorted(assignment.bookings, key=lambda k: k.pickup_timestamp)
Which is pretty much the same as this answer. I didn't know that the MongoEngine ListField behaves exactly like a dictionary in this regard!
If there is a more efficient/better way to do this, would be very keen to know!
I have to use SQLalchemy Core expression to fetch objects because ORM can't do "update and returning". (the update in ORM doesn't has returning)
from sqlalchemy import update
class User(ORMBase):
...
# pure sql expression, the object returned is not ORM object.
# the object is a RowProxy.
object = update(User) \
.values({'name': 'Wayne'}) \
.where(User.id == subquery.as_scalar()) \
.returning() \
.fetchone()
When
db_session.add(object)
it report UnmappedInstanceError: Class 'sqlalchemy.engine.result.RowProxy' is not mapped.
How do I put that RowProxy object from sql expression into identity map of ORM
?
I'm not sure there is a straight-forward way to do what you're describing, which is essentially to build an ORM object that maps directly to an database entry but without performing the query through the ORM.
My intuition is that the naive approach (just build init the ORM object with the values in the database) would just create another row with the same values (or fail to because of uniqueness constraints).
The more standard way to do what you are asking would be to query the row through the ORM first and then update the database from that ORM object.
user = User.query.filter(User.user_attribute == 'foo').one()
user.some_value = 'bar'
session.add(user)
session.commit()
I'm not sure if you have some constraint on your end that prevents you from using that pattern though. The documentation works through similar examples
Simple case:
Possible quick solution: construct the object from kwargs of your RowProxy, since those are object-like.
Given:
rowproxy = update(User) \
.values({'name': 'Wayne'}) \
.where(User.id == subquery.as_scalar()) \
.returning() \
.fetchone()
We might be able to do:
user = User(**dict(rowproxy.items()))
rowproxy.items() returns tuples of key-value pairs; dict(...) converts the tuples into actual key-value pairs; and User(...) takes kwargs for the model attribute names.
More difficult case:
But what if you have a model where one of the attribute names isn't quite the same as the SQL table column name? E.g. something like:
class User(ORMBase):
# etc...
user_id = Column(name='id', etc)
When we try to unpack our rowproxy into the User class, we'll likely get an error along the lines of: TypeError: 'id' is an invalid keyword argument for User (because it's expecting user_id instead).
Now it gets dirty: we should have lying around a mapper for how to get from the table attributes to the model attributes and vice versa:
kw_map = {a.key: a.class_attribute.name for a in User.__mapper__.attrs}
Here, a.key is the model attribute (and kwarg), and a.class_attribute.name is the table attribute. This gives us something like:
{
"user_id": "id"
}
Well, we want to actually provide the values we got back from our rowproxy, which besides allowing object-like access also allows dict-like access:
kwargs = {a.key: rowproxy[a.class_attribute.name] for a in User.__mapper__.attrs}
And now we can do:
user = User(**kwargs)
Errata:
you may want to session.commit() right after calling update().returning() to prevent long delays from your changes vs. when they get permanently stored in the database. No need to session.add(user) later - you already updated() and just need to commit() that transaction
object is a keyword in Python, so try not to stomp on it; you could get some very bizarre behavior doing that; that's why I renamed to rowproxy.
I don't know how to ask this but is very simple
I have an entity called "State" and another entity called "City".
I'm doing a query to get specific cities with a given parameter:
cities = City.objects.filter(code__exact=12345).values("id","name","state")
And then I serialize the list ( or dict? = in order to get them via JSON:
for c in cities:
result.append(c)
return HttpResponse(json.dumps(result))
The problem is I'm getting only the state ID but I need another attributes from this object, how I can initialize the state object inside the city or at least get specific attributes from state object.
The result from a values() call is a ValueQuerySet, which is special in a few ways. One of them is:
A ValuesQuerySet is useful when you know you’re only going to need
values from a small number of the available fields and you won’t need
the functionality of a model instance object. It’s more efficient to
select only the fields you need to use.
The part in bold is important. It means that the result of the queryset will not have the instances of the models, you have to tell it exactly what you need to be fetched.
So, if you know the fields of the state model you want in your result, you can add them in your values clause. If you just put state, it will give you the state id, which is the default identity field.
cities = City.objects.filter(code__exact=12345).values("id",
"name",
"state__name",
"state__id")
If you are doing this just to convert the results to json, use the built-in serializers:
from django.core import serializers
result = serializers.serialize('json',
City.objects.filter(code__exact=12345),
fields=('id', 'name', 'state__name', 'state__id'))
I have a Django QuerySet, and I want to get a Q object out of it. (i.e. that holds the exact same query as that queryset.)
Is that possible? And if so, how?
No, but you could create the Q object first, and use that; alternatively, create your query as a dict, and pass that to your filter method and the Q object.
This is not exactly what you were asking for, but you can extract the sql from a query set by accessing the query member. For example:
x = somequeryset.query
Then you could use that on a new queryset object to reconstruct the original queryset. This may work better in saving stuff like "values" that are defined for a query set. The defined x is easy to store. I've used this in the past to save user constructed queries/searches that then are run daily with the results emailed to the user.
Relevant also if you wanted the Q object so you you can reconstruct a complex query by ORing another Q object to it, is that, provided two QuerySets are on the same model, you can OR the QuerySets directly for that same effect. It's worth trying that and examining the SQL before and after.
For example:
qs1 = model.objects.filter(...)
print("qs1: {}".format(qs1.query)
qs2 = model.objects.filter(...)
print("qs2: {}".format(qs1.query)
qs = q1 | q2
print("qs: {}".format(qs.query)
I certainly found your question because I wanted the Q object from the query for this very reason, and discovered on the Django Users Group:
https://groups.google.com/d/msg/django-users/2BuFFMDL0VI/dIih2WRKAgAJ
that QuerySets can be combined in much the same way as Q objects can.
That may or may not be helpful to you, depending on the reason you want that Q object of course.
I'd like to query a model for instances where the generic relation field is not empty (that is, in the example below I'm looking for instances where document.count() > 0):
class Report(models.Model):
document = generic.GenericRelation(Document)
Something like:
Report.objects.filter(date__gte=twomonths).exclude(document__isnull=True)
Unfortunately this doesn't work - the query returns objects that have no "document" (ie. it returns objects where document.count() is 0).
Is there a way to query for instances where the generic relationship is empty?
I believe there still may be some contradictions in your question. Note: "I'm looking for instances where document.count() == 0" and then later, "Unfortunately this doesn't work - the query returns objects that have no 'document' (ie. it returns objects where document.count() is 0)".
If you want Reports that have no documents, you can use:
Report.objects.filter(document__isnull=True)
Or
Report.objects.exclude(document__isnull=False)
If you want Reports that have at least one document, you can use:
Report.objects.filter(document__isnull=False)
Or
Report.objects.exclude(document__isnull=True)