Use and, or conditions while using Case,When - django

Anyone know in the following query how can I use AND condition?
q = Food.objects.all().annotate(open=Case(When(days__day=today,then='blahblah'),When(start_time__lte=now and end_time__gte=now,then='blabla')))
On the second when I want to check if the now value is between start and end time but it seems like the 'and' keyword is not working there

Use Q objects so:
from django.db.models import F, Q, When
q = Food.objects.annotate(open=Case(
When(days__day=today, then='blahblah'),
When(Q(start_time__lte=now) & Q(end_time__gte=now), then='blabla'),
)
Use & to AND two Q objects and | to OR them.

Related

Incrementing specific parameter in all objects in the QuerySet

I am trying to increment the same parameter in all objects in the query set.
What I am doing right now:
q = SomeModel.objects.all()
for object in q:
object.my_parameter += 1
object.save()
I have wondered if it could be achieved in a simpler way, e.g. using update() function. To put it simply I would like to do something like this:
SomeModel.objects.all().update(my_parameter += 1)
I just can't believe that there is no shortcut for what I want to do.
Edit:
Resolved! Thank you!
You can do this by F() expressions
from django.db.models import F
SomeModel.objects.all().update(my_parameter=F('my_parameter') + 1)
Further reading https://docs.djangoproject.com/en/2.0/ref/models/expressions/#f-expressions
Certainly you could do it in a single bulk update. Check this out: Updating multiple objects at once.
I prefer to use the F expression too:
from django.db.models import F
SomeModel.objects.all().update(my_parameter =F('my_parameter') + 1)

Filter objects or (if 0 found) get all objects in Django with one DB hit

Is there a way in Django to achieve the following in one DB hit (Debug Toolbar shows 2 queries)?
q = SomeModel.objects.filter(name=name).order_by(some_field)
if q.count() == 0:
q = SomeModel.objects.all().order_by(some_field)
I want to check if there are objects with a given name. If yes, then return them. If not, return all objects. All done in one query.
I've checked Subquery, Q, conditional expressions but still don't see how to fit it into one query.
Ok, much as I resisted (I still think it's premature optimization), curiosity got the better of me. This is not pretty but does the trick:
from django.db.models import Q, Exists
name_qset = SomeObject.objects.filter(name=name)
q_func = Q(name_exists=True, name=name) | Q(name_exists=False)
q = SomeModel.objects.annotate(
name_exists=Exists(name_qset)
).filter(q_func).order_by(some_field)
Tried it out and definitely only one query. Interesting to see if it is actually appreciably faster for large datasets...
You best bet is to use .exists(), otherwise your code is fine
q = SomeModel.objects.filter(name=name).order_by(some_field)
if not q.exists():
q = SomeModel.objects.all().order_by(some_field)

Queryset inside fk attribute

I need do a advanced query,
My classes
class P:
class R:
p = fk(P)
class S:
R = fk(R)
I need some like this, from R class:
S.objects.filter(r.p = self.p)
In other words, all S where P is equal to a given P
I am not Pro with QuerySets
Thanks
Assuming you have a instance of the p class in self.p then the queryset
S.objects.filter(r__p=self.p) would work. Next time put a bit more effort into your question though or people won't want to put effort into an answer.

Combine Q objects in Django and limit one of them

I want to combine these 2 queries in 1 to get the Music object with name xyz and also get top 3 objects from genre 10, ordered by artist:
1. Music.objects.filter(name='xyz', genre=10)
2. Music.objects.filter(genre=10).order_by('artist')[:3]
I can use Q objects like this but I don't know how to order & filter the 3rd Q object below:
Music.objects.filter( (Q(name='xyz') & Q(genre=10)) | Q(genre=10) )
Maybe try like this?
Music.objects.filter( (Q(name='xyz') & Q(genre=10)) | Q(genre=10) ).order_by('artist')[:3]
No way to do it, use two queries but change second to avoid duplicates:
exact = Music.objects.filter(name='xyz', genre=10)
additional = Music.objects.filter(genre=10).exclude(name='xyz').order_by('artist')[:3]
do_something_with = list(exact) + list(additional)

Iterate through a list and use values in complex queries Django ORM

Am having a request in the following design :- example.com/?param1=blah&param1=blah1....param1=blahn. Notice that I want to have param1 with several parameters. Now to capture the values of the parameter param1, I do the following
searchQery = request.GET.getlist('param1')
where I get a list with values for param1. I want to use a complex query
for item searchQuery:
val = MyModel.objects.filter(Q(item__startswith=searchQuery[0])| Q(item__startswith=searchQuery[1])| Q(item__startswith=searchQuery[2])) all the way to searchQuery[n]
In short I want to iterate through the values of the list, dynamically and am currently lost there.
from operator import or_
val = MyModel.objects.filter(reduce(or_,(Q(item__startswith=x) for x in searchQuery)))
Use reduce to combine a generated sequence of Q expressions.