Combining querysets obtained from a loop - python

Let's say I have a list of people that can be "followed".
I'd like to iterate through all the people that a certain user is following and grab posts from all of those users in the form of a queryset.
I understand that I can combine querysets by using chain or |, but I'm a bit confused when it comes to combining querysets that I might grab from looping through everyone being followed.
following = UserFollows.objects.filter(user_id = user.id)
for follow in following.iterator():
UserPost.objects.filter(user=follow.user) #what do I do with this?
How would I combine those if I cant explicitly name them to chain or '|'?

You can do something like this:
following = UserFollows.objects.filter(user__id = user.id).select_related('user')
users_ids = [follow.user.id for follow in following]
posts = UserPost.objects.filter(user__id__in=users_ids)
but look that it is quite expensive operation so it's good to add select_related() method to fetch users in one query. I think you should also consider to cache the users_ids list before get it from database.

Have you tried something like
following = UserFollows.objects.filter(user_id = user.id)
q = UserPost.objects.filter(user=following[0].user)
for follow in following[1:]:
q = q | UserPost.objects.filter(user=follow.user)

Related

searching textfield for each keyword

Right now my views.py function allows me to search each Django textfield for the ENTIRE search phrase. However if I would like to search for a title and author, such as, "biology John", my queryset will end up empty, and I am not sure how to break up the phrase and search for individual words.
def search(request):
query = request.GET.get('search')
if query:
results = Protocol.objects.filter(Q(title__contains=query) | Q(author__contains=query) | Q(description__contains=query) | Q(reagents__contains=query) | Q(protocol_steps__contains=query))
else:
results = ''
return render(request, 'protocat_app/search_protocols.html',{'results':results})
You definitely can set up haystack with solr/elasticsearch. But if you still need some database query, you can use the following:
import operator
def search(request):
terms = request.GET.get('search', '').split(' ')
q_list = []
for term in terms:
if term:
q_list.append(Q(title__contains=query))
q_list.append(Q(author__contains=query))
q_list.append(Q(description__contains=query))
q_list.append(Q(reagents__contains=query))
q_list.append(Q(protocol_steps__contains=query))
if q_list:
results = Protocol.objects.filter(reduce(operator.or_, q_list))
else:
results = ''
return render(request, 'protocat_app/search_protocols.html',{'results':results})
Hope this helps :)
I would suggest setting up a search server like Solr/Elastic Search.
Here you have just one case where you need to split the query among 2 fields. Maybe later you come up with a situation where you need to find among multiple indexed fields. Thus, Solr would be of great help.
You can read about Solr here.
Also, you can make use of django-haystack to make django interact with Solr and get the filtered results as per what the user searched.

In django, how can I filter or exclude multiple things?

If I have this queryset:
player = basketball.objects.all()
How can I do a filter where I ask for multiple people? For example: I only want players who's names are "mike" or "charles" to show up. This doesn't seem to work for me:
player.filter(name = 'mike' , 'charles')
Does anyone know the best way to go about this?
You can use __in:
player.filter(name__in=['mike', 'charles'])
Alongside the use of __in, you can also chain multiple filters using the Q object, so objects.filter(q) where q = Q(Q(name="mike")|Q(name="phil")).
Definitely use __in though in this case.

django conjunctive filter __in query

Consider an array of Tags, T.
Each PhotoSet has a many-to-many relationship to Tags.
We also have a filter, F (consisting of a set of Tags), and we want to return all PhotoSets who have ALL the tags contained in F.
i.e,. if F = ['green', 'dogs', 'cats'], we want every PhotoSet instance that has all the tags in F.
Naturally
PhotoSet.objects.filter(tags__in=F)
Does not do the trick, since it returns every PhotoSet contain any member of F.
I see it's possible to use similar things using "Q" expressions, but that only seemed for a finite amount of conjunctive parameters. Is this something that can be done using a list comprehension??
Thanks in advance!
EDIT -- SOLUTION:
I found the solution using an obvious way. Simply chaining filters...
results = PhotoSets.objects
for f in F:
results = results.filter(tags__in=[f])
results = results.all()
Was staring me in the face the whole time!
Little quick and dirty, but it'll do the trick:
query = None
for tag in F:
if query is None:
query = Q(tags=tag)
else:
query &= Q(tags=tag)
PhotoSet.objects.filter(query)

Django - filter ManyToManyField?

I'm not sure the best way to describe what it is that I'm trying to do so forgive my title.
I have two models, User and Group. Group contains field, members, which is a ManyToManyField referring to User.
Given a User, I want to find all of the Groups to which that user belongs.
My idea would be to do something like this:
groups = Group.objects.filter(user in members)
Something like that. Even though I realize that this isn't right
I tried reading through this link but couldn't figure out how to apply:
http://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships
Thanks
EDIT:
Figured it out
groups = Group.objects.filter(members__username=user.username)
If you have the user and you want to have his groups then start querying from it, not the way around ;)
Here's an example:
james = User.objects.get(pk= 123)
james_groups = james.group_set.all()
The most concise way is probably
groups = user1.group_set.all()
which gives you a queryset that is iterable.

Using data from django queries in the same view

I might have missed somthing while searching through the documentation - I can't seem to find a way to use data from one query to form another query.
My query is:
sites_list = Site.objects.filter(worker=worker)
I'm trying to do something like this:
for site in sites_list:
[Insert Query Here]
Edit: I saw the awnser and im not sure how i didnt get that, maybe thats the sign im up too late coding :S
You could easily do something like this:
sites_list = Site.objects.filter(worker=worker)
for site in sites_list:
new_sites_list = Site.objects.filter(name=site.name).filter(something else)
You can also use the __in lookup type. For example, if you had an Entry model with a relation to Site, you could write:
Entry.objects.filter(site__in=Site.objects.filter(...some conditions...))
This will end up doing one query in the DB (the filter condition on sites would be turned into a subquery in the WHERE clause).

Categories