In Django you can remove items from a QuerySet by doing this as documented here:
queryset = QuerySet.remove(item)
Haystack SearchQuerySet is build on QuerySet but it appears that the remove method was not implemented. Does anyone know of a way to remove items in a SearchQuerySet?
FWIW I am trying to do a second level of filtering for a client. Basically I'm interating over the SearchQuerySet for a couple specific properties. The idea is if they don't have it I want to remove them.
Thanks
Have you tried using exclude? I.e.
searchqueryset = searchqueryset.exclude(id=u'myapp.mymodel.%s' % item.pk)
One problem I see with this solution is if the searchqueryset searches through different models. You'll then exclude all objects with pk = item.pk, which you do not want to do.
Here's the approach I used. I transformed searchqueryset to a list:
searchqueryset_list = list(searchqueryset)
Then I could remove the item:
searchqueryset_list.remove(item)
Although *searchqueryset_list* is not a SearchQuerySet object, I could use it in the templates that render the html page.
Related
Can anyone help me with this
qs = Vine.objects.annotate(votos_count=Count('votomoderacion')).\
annotate(votos_ok=Count('votomoderacion')).filter(votomoderacion__voto="1").\
annotate(votos_no_ok=Count('votomoderacion')).filter(votomoderacion__voto="0")
The problem is that the filters affects to all the annotations, and i want to filter every single annotation separately.
I hope i've been clair enough with my question.
Thank you!
You have to understand that what you are doing is chaining filters.
First you had a queryset with annotated votes count likeannotate(votos_ok=Count('votomoderacion')).filter(votomoderacion__voto="1").
Then you annotated votes_ok with it and filterered it like annotate(votos_ok=Count('votomoderacion')).filter(votomoderacion__voto="1"), which gave you another filtered queryset.
But after that, you added another filter annotate(votos_no_ok=Count('votomoderacion')).filter(votomoderacion__voto="0"), which filtered the queryset which you got from previous filter. so, in this case, you didn't get your desired result.
So better if you separate them. Like:
total_votes= Vine.objects.annotate(votos_count=Count('votomoderacion'))
yes_votes= Vine.objects.annotate(votos_ok=Count('votomoderacion')).filter(votomoderacion__voto="1")
no_votes= Vine.objects.annotate(votos_no_ok=Count('votomoderacion')).filter(votomoderacion__voto="0")
To join those queryset:
from itertools import chain
allvotes = list(chain(total_votes, yes_votes, no_votes))
I've got an app where users create pages. I want to run a simple DB query that returns how many users have created more than 2 pages.
This is essentially what I want to do, but of course it's not the right method:
User.objects.select_related('page__gte=2').count()
What am I missing?
You should use aggregates.
from django.db.models import Count
User.objects.annotate(page_count=Count('page')).filter(page_count__gte=2).count()
In my case, I didn't use last .count() like the other answer and it also works nice.
from django.db.models import Count
User.objects.annotate( our_param=Count("all_comments")).filter(our_param__gt=12)
use aggregate() function with django.db.models methods!
this is so useful and not really crushing with other annotation aggregated columns.
*use aggregate() at the last step of calculation, it turns your queryset to dict.
below is my code snippet using them.
cnt = q.values("person__year_of_birth").filter(person__year_of_birth__lte=year_interval_10)\
.filter(person__year_of_birth__gt=year_interval_10-10)\
.annotate(group_cnt=Count("visit_occurrence_id")).aggregate(Sum("group_cnt"))
When I do this,
>>> b = Blog.objects.all()
>>> b
I get this:
>>>[<Blog: Blog Title>,<Blog: Blog Tile>]
When I query what type b is,
>>> type(b)
I get this:
>>> <class 'django.db.models.query.QuerySet'>
What does this mean? Is it a data type like dict, list, etc?
An example of how I can build data structure like a QuerySet will be appreciated.
I would want to know how Django builds that QuerySet (the gory details).
A django queryset is like its name says, basically a collection of (sql) queries, in your example above print(b.query) will show you the sql query generated from your django filter calls.
Since querysets are lazy, the database query isn't done immediately, but only when needed - when the queryset is evaluated. This happens for example if you call its __str__ method when you print it, if you would call list() on it, or, what happens mostly, you iterate over it (for post in b..). This lazyness should save you from doing unnecessary queries and also allows you to chain querysets and filters for example (you can filter a queryset as often as you want to).
Yes, it's just another type, built like every other type.
A QuerySet represents a collection of objects from your database. It can have zero, one or many filters. Filters narrow down the query results based on the given parameters. In SQL terms, a QuerySet equates to a SELECT statement, and a filter is a limiting clause such as WHERE or LIMIT.
https://docs.djangoproject.com/en/1.8/topics/db/queries/
A QuerySet is a list of objects of a given model, QuerySet allow you to read data from database
I'm using django-haystack for a search page on my site. I'm basically done, but not quite happy with the ordering and not quite sure how haystack decides how to order everything.
I know I can over-ride the SearchQuerySet by using order_by but that over-rides it entirely. Let's say I want to force the search to order by in stock (BooleanField), so that the products that are in stock show up on top, but then do everything else as it normally would. How do I do that?
I tried doing order_by('-in_stock', 'content') figure content was what it used by default but it produces very different results from if I just leave it to do its own ordering.
Thanks for any input on this matter!
You must have a index in your search_indexes.py with in_stock:
class YourModel(indexes.SearchIndex):
in_stock = indexes.BooleanField(model_attr='model_in_stock')
and in your urls:
sqs = SearchQuerySet().models(YourModel).order_by('-in_stock', 'score') # score is a field of haystack
In this way, you show the results first if they are in stock and then by score!
To sort on a CharField, make it storable, but not indexable.
sorted_name = indexes.CharField(indexed=False, stored=True)
If you need to have it sortable and indexable, use two different fields in the SearchIndex.
How can I retrieve the last record in a certain queryset?
Django Doc:
latest(field_name=None) returns the latest object in the table, by date, using the field_name provided as the date field.
This example returns the latest Entry in the table, according to the
pub_date field:
Entry.objects.latest('pub_date')
EDIT : You now have to use Entry.objects.latest('pub_date')
You could simply do something like this, using reverse():
queryset.reverse()[0]
Also, beware this warning from the Django documentation:
... note that reverse() should
generally only be called on a QuerySet
which has a defined ordering (e.g.,
when querying against a model which
defines a default ordering, or when
using order_by()). If no such ordering
is defined for a given QuerySet,
calling reverse() on it has no real
effect (the ordering was undefined
prior to calling reverse(), and will
remain undefined afterward).
The simplest way to do it is:
books.objects.all().last()
You also use this to get the first entry like so:
books.objects.all().first()
To get First object:
ModelName.objects.first()
To get last objects:
ModelName.objects.last()
You can use filter
ModelName.objects.filter(name='simple').first()
This works for me.
Django >= 1.6
Added QuerySet methods first() and last() which are convenience methods returning the first or last object matching the filters. Returns None if there are no objects matching.
When the queryset is already exhausted, you may do this to avoid another db hint -
last = queryset[len(queryset) - 1] if queryset else None
Don't use try...except....
Django doesn't throw IndexError in this case.
It throws AssertionError or ProgrammingError(when you run python with -O option)
You can use Model.objects.last() or Model.objects.first().
If no ordering is defined then the queryset is ordered based on the primary key. If you want ordering behaviour queryset then you can refer to the last two points.
If you are thinking to do this, Model.objects.all().last() to retrieve last and Model.objects.all().first() to retrieve first element in a queryset or using filters without a second thought. Then see some caveats below.
The important part to note here is that if you haven't included any ordering in your model the data can be in any order and you will have a random last or first element which was not expected.
Eg. Let's say you have a model named Model1 which has 2 columns id and item_count with 10 rows having id 1 to 10.[There's no ordering defined]
If you fetch Model.objects.all().last() like this, You can get any element from the list of 10 elements. Yes, It is random as there is no default ordering.
So what can be done?
You can define ordering based on any field or fields on your model. It has performance issues as well, Please check that also. Ref: Here
OR you can use order_by while fetching.
Like this: Model.objects.order_by('item_count').last()
If using django 1.6 and up, its much easier now as the new api been introduced -
Model.object.earliest()
It will give latest() with reverse direction.
p.s. - I know its old question, I posting as if going forward someone land on this question, they get to know this new feature and not end up using old method.
In a Django template I had to do something like this to get it to work with a reverse queryset:
thread.forumpost_set.all.last
Hope this helps someone looking around on this topic.
MyModel.objects.order_by('-id')[:1]
If you use ids with your models, this is the way to go to get the latest one from a qs.
obj = Foo.objects.latest('id')
You can try this:
MyModel.objects.order_by('-id')[:1]
The simplest way, without having to worry about the current ordering, is to convert the QuerySet to a list so that you can use Python's normal negative indexing. Like so:
list(User.objects.all())[-1]