I wonder if this query can be modified to return User objects instead of just merchant_id (User).
(User.objects.get(id=merchant['merchant_id']) for merchant in self.user.visits.values('merchant_id').distinct())
You are creating 1 DB query for each User (which is a Merchant?) lookup. Need to brush up on my django ORM but I would do something like:
User.objects.filter(id__in=[ merchant['merchant_id'] for merchant in self.user.visits.values('merchant_id').distinct() ])
How does this sound?
merchants_visited = self.user.visits.merchants.all().distinct()
return User.objects.filter(visits__merchants__in=merchants_visited, profile=self)
Related
I am triying to query my product model like this:
I have Product model that is related to an user
My user can have a related Store, and its store can be unactive or no-visible
So, my products can be sold by an user that has a store or an user that not has a store; what I want to do is to make query adding these extra parameters when "has_store" condition beign True like this.
store_query = ({"seller__user_store__is_active": True,
"seller__user_store__is_visible": True}
if F("seller__user_store__isnull=False") else {})
And then add that query to my filtering sentence:
Product.objects.filter(Q(is_new=True) & Q(is_active=True), **store_query)
My product model also has is_new, and is_active and other parameters.
So, expected behaviour is something like add Q(seller__user_store__is_visible=True) and Q(seller__user_store__is_active=True) if product seller has a related store
I hope have been clear, thanks you a lot
I think you make things too complicated. The stored_query is just equivalent to:
Q(seller__user_store=None) | Q(seller__user_store__is_active=True, seller__user_store__is_visible=True)
Indeed, in case the seller__user_store=None, it does not have to look to the conditions of the seller, otherwise it will. We can thus implement this as:
Product.objects.filter(
Q(seller__user_store=None) | Q(seller__user_store__is_active=True, seller__user_store__is_visible=True),
is_new=True, is_active=True
)
I was wondering if it is possible to filter a queryset result with a queryset object attribute.
Example:
clients = Client.objects.filter(name__contains=search)
This should return several objects
result = Invoice.objects.filter(client_id=clients.id)
Now I want all the data inside Invoice that corresponds to the clients.id found.
What is the most optimized way to do it? Since Django is a powerful framework, I was wondering if it has a good and fast way to do it without me having to add the primary result to a list and do a for loop.
You can do this by filtering directly Invoices using lookups
result = Invoice.objects.filter(client__name__contains=search)
Alternatively, you can find all clients, extract ids, and filter invoices by those id.
clients = Client.objects.filter(**your_crazy_search).values_list('id', flat=True).all()
result = Invoices.objects.filter(client_id__in=clients_id)
You don't even need to extract ID from clients, that will work just fine:
clients = Client.objects.filter(name__contains=search)
result = Invoices.objects.filter(client__in=clients)
It will result in SQL query:
SELECT * FROM invoices WHERE result.client_id IN (SELECT `id` FROM `client` WHERE ...)
I am trying this:
count = UserCheck.objects.filter(user=puser, fixture__competition__name__icontains='gold',
fixture__date__gte='2013-02-11',
fixture__date__lte='2013-05-24', year=2013).extra(
where=["WEEKOFYEAR(fixture__date) = %s" %week]).exclude(result=0).count()
The problem is the extra() part where I can't filter using WEEKOFYEAR(fixture__date). How can I do this. Is this possible?
PS: I am using MySQL (and django 1.4)
When using the extra QuerySet modifier, you are not using Django's ORM anymore. You are using "pure" SQL, so basically related models can't be accessed with the __ notation and in your case fixture__date is not a valid column name. However, one must keep in mind that tables are named in a specific way in Django. So you can use:
count = UserCheck.objects.filter(user=puser, fixture__competition__name__icontains='gold',
fixture__date__gte='2013-02-11',
fixture__date__lte='2013-05-24', year=2013).extra(
where=["WEEKOFYEAR(app_fixture.date) = %s" %week]).exclude(result=0).count()
where app refers to the app that holds the Fixture model.
In short, for each model in an app, Django makes the table <app>_<model>, and you can use that with the extra clause when you want to refer to that model.
Lets say I have 2 django models like this:
class Spam(models.Model):
somefield = models.CharField()
class Eggs(models.Model):
parent_spam = models.ForeignKey(Spam)
child_spam = models.ForeignKey(Spam)
Given the input of a "Spam" object, how would the django query looks like that:
Limits this query based on the parent_spam field in the "Eggs" table
Gives me the corresponding child_spam field
And returns a set of "Spam" objects
In SQL:
SELECT * FROM Spam WHERE id IN (SELECT child_spam FROM Eggs WHERE parent_spam = 'input_id')
I know this is only an example, but this model setup doesn't actually validate as it is - you can't have two separate ForeignKeys pointing at the same model without specifying a related_name. So, assuming the related names are egg_parent and egg_child respectively, and your existing Spam object is called my_spam, this would do it:
my_spam.egg_parent.child_spam.all()
or
Spam.objects.filter(egg_child__parent_spam=my_spam)
Even better, define a ManyToManyField('self') on the Spam model, which handles all this for you, then you would do:
my_spam.other_spams.all()
According to your sql code you need something like this
Spam.objects.filter(id__in= \
Eggs.objects.values_list('child_spam').filter(parent_spam='input_id'))
Should entry_set be cached with select_related? My DB is still getting calls even after I use select_related. The pertinent sections
class Alias(models.Model):
achievements = models.ManyToManyField('Achievement', through='Achiever')
def points(self) :
points = 0
for a in self.achiever_set.all() :
points += a.achievement.points * a.count
return points
class Achievement(models.Model):
name = models.CharField(max_length=100)
points = models.IntegerField(default=1)
class Achiever(models.Model):
achievement = models.ForeignKey(Achievement)
alias = models.ForeignKey(Alias)
count = models.IntegerField(default=1)
aliases = Alias.objects.all().select_related()
for alias in aliases :
print "points : %s" % alias.points()
for a in alias.achiever_set.all()[:5] :
print "%s x %d" % (a.achievement.name, a.count)
And I'm seeing a big join query at the start, and then individual calls for each achievement. Both for the points and for the name lookup.
Is this a bug, or am I doing something wrong?
With Django 1.4 you can use prefetch_related which will work for ManyToMany relations:
https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related
Select_related() doesn't work with manytomanyfields. At the moment, this is something that is not planned, but might be a future feature. See http://code.djangoproject.com/ticket/6432
In this case, if you want to make a single query you got two options
1) Make your own SQL, probably won't be pretty or fast.
2) You could also query on the model with the foreignkey. You would be able to use select_related in that case. You stil won't be able to access the modelname_set but with some formatting you would be able to vet the data you need in a single query. None of the options are ideal, but you could get it working at a deacent speed aswell.
In Django 1.3 You can use Queryset.values() and do something like:
Alias.objects[.filter().exclude() etc.].values('achievements__name', 'achievement__points')
Only drwaback is that You get QuerySetList instead of QuerySet. But this can be simply overcome by passing all necessary fields into values() - You have to change Your perception ;)
This can save you few dosen of queries...
Details can be found here in django docs:
http://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.values