How can I do this in SQLAlchemy? - python

I have an SQLAlchemy model, say Entity and this has a column, is_published. If I query this, say by id, I only want to return this if is_published is set to True. I think I can achieve using a filter. But in case there is a relationship and I am able to and require to access it like another_model_obj.entity and I only want this to give the corresponding entity object if the is_published for that instance is set to True. How should I do this? One solution would be wrap this around using an if block each time I use this. But I use this too many times and if I use it again, I will have to remember this detail. Is there any way I can automate this in SQLAlchemy, or is there any other better solution to this problem as a whole? Thank you

It reads as if you would need a join:
session().query(AnotherModel).join(Entity).filter(Entity.is_published)

This question was asked many times here and still doesn't have a good answer. Here are possible solutions suggested by the author of SQLAlchemy. A more elaborate query class to exclude unpublished objects is provided in iktomi library. It works with SQLAlchemy 0.8.* branch only for now but should be ported to 0.9.* soon. See test cases for limitations (tests that fail are marked with #unittest.skip()) and usage examples.

Related

Why Django doesn't have an on_update=models.CASCADE option?

My question comes from a situation where I want to emulate the ON UPDATE CASCADE in SQL (when I update an id and I have a Foreignkey, it is going to be automatically updated) in Django, but I realized that (apparently) doesn't exist a native way to do it.
I have visited this old question where he is trying to do the same.
My question is: Why Django doesn't have a native option? Is that a bad practice? If so, why? Does that bring problems to my software or structure?
Is there a simple way to do this?
Thanks in advance!
It is a bad practice to think about updating key fields. Note that this field is used for index generation and other computationally expensive operations. This is why the key fields must contain a unique and unrepeatable value that identifies the record. It does not necessarily have to have a direct meaning with the content of the register, it can be an autonumeric value. If you need to update it, you may need to put the value in another field of the table to be able to do it without affecting the relationships.
It is for this reason that you will not find in Django the operation you are looking for.

How do I find only objects that have a related object in Django ORM? [duplicate]

This is bound to be a duplicate question but I can't find any others. I'm trying to get a list of photos that have complaints. I can't simply get complaints and deal with the related photos - I need a queryset of photos.
This should work but doesn't seem right:
Photo.objects.filter(complaint__id__gte=0)
This doesn't seem like the most efficient way:
Photo.objects.annotate(Count('complaint')).exclude(complaint__count=0)
Is there a better way?
how about ...
Photo.objects.filter(complaint__isnull=False)
from https://docs.djangoproject.com/en/dev/topics/db/queries/
I'm not sure which variant is the best, but that works as well.
Photo.objects.exclude(complaint=None)
Generated SQL query here is not the same as in case with .filter(complaint__isnull=False), but sense is identical.
Depending on the complexity of the relationship and filter logic you might need this (or this can turn out to be more readable):
complaints = Complaint.objects.filter(
# some complex filter here
Q(...) & Q(...) | Q(...)
)
Photo.objects.annotate(
has_complaints=Exists(complaints)
).filter(has_complaints=True)

sqlalchemy automatically extend query or update or insert upon table definition

in my app I have a mixin that defines 2 fields like start_date and end_date. I've added this mixin to all table declarations which require these fields.
I've also defined a function that returns filters (conditions) to test a timestamp (e.g. now) to be >= start_date and < end_date. Currently I'm manually adding these filters whenever I need to query a table with these fields.
However sometimes me or my colleagues forget to add the filters, and I wonder whether it is possible to automatically extend any query on such a table. Like e.g. an additional function in the mixin that is invoked by SQLalchemy whenever it "compiles" the statement. I'm using 'compile' only as an example here, actually I don't know when or how to best do that.
Any idea how to achieve this?
In case it works for SELECT, does it also work for INSERT and UPDATE?
thanks a lot for your help
Juergen
Take a look at this example. You can change the criteria expressed in the private method to refer to your start and end dates.
Note that this query will be less efficient because it overrides the get method to bypass the identity map.
I'm not sure what the enable_assertions false call does; I'd recommend understanding that before proceeding.
I tried extending Query but had a hard time. Eventually (and unfortunately) I moved back to my previous approach of little helper functions returning filters and applying them to queries.
I still wish I would find an approach that automatically adds certain filters if a table (Base) has certain columns.
Juergen

Django JSONField isnull lookup

As far as I know you can't use __isnull lookups on django native JSONField. On the Internet I found this inactive issue.
As possible workaround we can of course use these hacks:
model.objects.filter(field__contains={'key': None}), which isn't so flexible since you might need to query multiple keys or whatever.
model.objects.exclude(field__key=True).exclude(field__key=False), which is hacky and works only for boolean data.
I hope there is a better way ((c) Raymond Hettinger) of doing this. Any advises will be appreciated. For now, I will go with the first approach
According to this (see the last, closing comment) the following should work model.objects.filter(field__key=None) (But obviously you should use the Django version with the fix).
The django docs
warn that
Since any string could be a key in a JSON object, any lookup other
than those listed below will be interpreted as a key lookup. No errors
are raised. Be extra careful for typing mistakes, and always check
your queries work as you intend.
and here they are

Can django lazy-load fields in a model?

One of my django models has a large TextField which I often don't need to use. Is there a way to tell django to "lazy-load" this field? i.e. not to bother pulling it from the database unless I explicitly ask for it. I'm wasting a lot of memory and bandwidth pulling this TextField into python every time I refer to these objects.
The alternative would be to create a new table for the contents of this field, but I'd rather avoid that complexity if I can.
The functionality happens when you make the query, using the defer() statement, instead of in the model definition. Check it out here in the docs:
http://docs.djangoproject.com/en/dev/ref/models/querysets/#defer
Now, actually, your alternative solution of refactoring and pulling the data into another table is a really good solution. Some people would say that the need to lazy load fields means there is a design flaw, and the data should have been modeled differently.
Either way works, though!
There are two options for lazy-loading in Django: https://docs.djangoproject.com/en/1.6/ref/models/querysets/#django.db.models.query.QuerySet.only
defer(*fields)
Avoid loading those fields that require expensive processing to convert them to Python objects.
Entry.objects.defer("text")
only(*fields)
Only load the fields that you actually need
Person.objects.only("name")
Personally, I think only is better than defer since the code is not only easier to understand, but also more maintainable in the long run.
For something like this you can just override the default manager. Usually, it's not advised but for a defer() it makes sense:
class CustomManager(models.Manager):
def get_queryset(self):
return super(CustomManager, self).get_queryset().defer('YOUR_TEXTFIELD_FIELDNAME')
class DjangoModel(models.Model):
objects = CustomerManager()

Categories