Django: Query where GenericRelation is null - python

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)

Related

Adding attribute to all query objects using annotate?

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

Sort a ListField containing ReferenceField (Mongoengine)

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!

connect SQLAlchemy ORM with the objects from sql core expression?

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.

Sqlalchemy FIlter based on subtype

I am using a join-based inheritance - I have User(parent) and CorporateUser(child) models. The polymorphic_identity of User is "user" and the one of the CorporateUser is "corporate_user".
I have a query like this
User.query.filter(User.name.like("%"+search_text+"%"))
Is it possible to "chain" to this query something that will only return objects of type CorporateUser?
Currently I just add another User.query.filter(User.name.like("%"+search_text+"%")).filter(User.type == 'corporate_user')
but this doesn't seem very elegant.
I am aware I can just do CorporateUser.query.filter(User.name.like("%"+search_text+"%"))
but the point is that I am given the filters of the initial query.
Thanks.
The .with_entities() can help you. It will not exactly return the CorporateUser, but only the fields you defined.
query = User.query.filter(User.name.like("%"+search_text+"%")) \
.filter(User.type == 'corporate_user') \
.with_entities(User.corporate_user)
Each item in your query result will be a tuple with the entities defined.
Of course, your model need the User.corporate_user back reference. Based on your question, I'm not sure if you have it.

Django debug error

I have the following in my model:
class info(models.Model):
add = models.CharField(max_length=255)
name = models.CharField(max_length=255)
An in the views when i say
info_l = info.objects.filter(id=1)
logging.debug(info_l.name)
i get an error saying name doesnt exist at debug statement.
'QuerySet' object has no attribute 'name'
1.How can this be resolved.
2.Also how to query for only one field instead of selecting all like select name from info.
1. Selecting Single Items
It looks like you're trying to get a single object. Using filter will return a QuerySet object (as is happening in your code), which behaves more like a list (and, as you've noticed, lacks the name attribute).
You have two options here. First, you can just grab the first element:
info_l = info.objects.filter(id=1)[0]
You could also use the objects.get method instead, which will return a single object (and raise an exception if it doesn't exist):
info_l = info.objects.get(id=1)
Django has some pretty good documentation on QuerySets, and it may be worth taking a look at it:
Docs on using filters
QuerySet reference
2. Retrieving Specific Fields
Django provides the defer and only methods, which will let you choose specific fields from the database, rather than fetching everything at once. These don't actually prevent the fields from being read; rather, it loads them lazily. defer is an "opt-in" mode, which lets you specify what fields should be lazily loaded. only is "out-out" -- you call it, and only the fields you pass will by eagerly loaded.
So in your example, you'd want to do something like this:
info_l = info.objects.filter(id=1).only('name')[0]
Though with a model as simple as the example you give, I wouldn't worry much at all about limiting fields.

Categories

Resources