Changing ordering of results in django-haystack - django

I am using django-haystack for search. By default it is showing oldest objects first whereas i want to show latest on top. Can anyone guide me how can i do this?
My code sample is shown below:
search_indexes.py
class PostIndex(indexes.RealTimeSearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
title = indexes.CharField(model_attr='title')
created = indexes.DateTimeField(model_attr='created')
def get_model(self):
return Post
def index_queryset(self):
return self.get_model().objects.filter(created__lte=datetime.datetime.now())
Can anyone tell me the exact file where i'll have to make changes and what changes? Do i have to make changes to query.py file in haystack? Query.py has
def order_by(self, *args):
"""Alters the order in which the results should appear."""
clone = self._clone()
for field in args:
clone.query.add_order_by(field)
return clone
How can i make changes to this to show the latest on the top?

You can set order_by in your haystack_urls.py (or whatever you called it) e.g
qs = SearchQuerySet().order_by('-created')
urlpatterns = patterns('haystack.views',
url(r'^$', SearchView(searchqueryset=qs), name='haystack_search'),
)

Related

Disabling options in django-autocomplete-light

Just started using django-autocomplete-light (autocomplete.ModelSelect2) and while I have managed to get it working, I wondered if it is possible to pass disabled options?
I have a list of customers to choose from but some, for various reasons, shouldn't be selected they shouldn't be able to use them. I know I could filter these non-selectable customers out, but this wouldn't be very usable as the user might think that the customer isn't in the database. If so, could someone point me in the right direction as I'm not sure where to start.
It says in the Select2 documentation that disabling options should be possible. Presumably if I could also send a 'disabled':true within the returned json response that might do it.
OK, so here is what I came up with and it works.
view.py
The Select2ViewMixin is subclassed and then a 'disabled' attribute is added to the customer details. This value provided by the ParentAutocomplete view.
from dal import autocomplete
from dal_select2.views import Select2ViewMixin
from dal.views import BaseQuerySetView
class CustomSelect2ViewMixin(Select2ViewMixin):
def get_results(self, context):
return [
{
'id': self.get_result_value(result),
'text': self.get_result_label(result),
'selected_text': self.get_selected_result_label(result),
'disabled': self.is_disabled_choice(result), # <-- this gets added
} for result in context['object_list']
]
class CustomSelect2QuerySetView(CustomSelect2ViewMixin, BaseQuerySetView):
"""Adds ability to pass a disabled property to a choice."""
class ParentAutocomplete(CustomSelect2QuerySetView):
def get_queryset(self):
qs = Customer.objects.all()
if self.q:
qs = qs.filter(org_name__icontains=self.q)
return qs.order_by('org_name', 'org_city')
def get_result_label(self, item):
return item.selector_name
def get_selected_result_label(self, item):
return item.selector_name
def is_disabled_choice(self, item): # <-- this is where we determine if the record is selectable or not.
customer_id = self.forwarded.get('customer_id', None)
return not (item.can_have_children and not str(item.pk) == customer_id)
form.py
The form is then used as normal.
from dal import autocomplete
class CustomerBaseForm(forms.ModelForm):
customer_id= forms.IntegerField(required=False, widget=forms.HiddenInput)
class Meta:
model = Customer
widgets = {
'parent':autocomplete.ModelSelect2(
url='customer:parent-autocomplete',
forward=['customer_id'],
)
}
Hopefully this might be useful to someone.

Django - get_redirect_url() causes Page not found (404)

I'm trying to implement favorite feature so that user can choose favorite stores. I'm currently referencing the video https://www.youtube.com/watch?v=pkPRtQf6oQ8&t=542s and stuck with the beginning.
When I try to move to the url https://www.fake-domain.com/my-domain/like, it throws the error message saying No Store matches the given query. So, I guess self.kwargs.get("domainKey") this snippet seems to throw the error, but I don't know why.
I'm not sure if I'm showing my codes enough, so please let me know I need to show more.
models.py
class Store(models.Model):
...
domainKey = models.CharField(max_length=100)
likes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True)
...
urls.py
url(r'^(?P<store_domainKey>.*)/$', views.detail, name='detail'),
url(r'^(?P<store_domainKey>.*)/like/$', views.StoreLikeRedirect.as_view(), name='like'),
views.py
class StoreLikeRedirect(RedirectView):
def get_redirect_url(self, *args, **kwargs):
store_domainKey = self.kwargs.get("domainKey")
print(store_domainKey)
obj = get_object_or_404(Store, pk='store_domainKey')
return obj.get_absolute_url()
--------------------------------EDIT------------------------------
Revised the codes based on the feedback, but still not working.
When I typed the url, the terminal says the following:
None <-- this is shown by print(store_domainKey) in views.py
Not Found: /down-east/like/
Since the print function in views.py prints None, I think there's something wrong on the line store_domainKey = self.kwargs.get("domainKey"). The part self.kwargs.get() seems not working. In the example video at the top of the post, the guy used SlugField(), but I used CharField() for my domainKey. Can it be an issue to use self.kwargs.get()?
views.py
class StoreLikeRedirect(RedirectView):
def get_redirect_url(self, *args, **kwargs):
store_domainKey = self.kwargs.get("domainKey")
print(store_domainKey)
obj = get_object_or_404(Store, domainKey=store_domainKey)
return obj.get_absolute_url()
urls.py
url(r'^(?P<store_domainKey>.*)/like/$', views.StoreLikeRedirect.as_view(), name='like'),
url(r'^(?P<store_domainKey>.*)/$', views.detail, name='detail'),
models.py
class Store(models.Model):
...
domainKey = models.CharField(max_length=100)
likes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True)
...
def get_absolute_url(self):
return reverse('boutique:detail', kwargs={"domainKey":self.domainKey})
----------------------------2nd Update-----------------------------
So, now self.kwargs.get("domainKey") returns the domain key very well!
but having
NoReverseMatch at /down-east/like/
Reverse for 'detail' with arguments '()' and keyword arguments '{'domainKey': 'down-east'}' not found. 1 pattern(s) tried: ['(?P<store_domainKey>.*)/$']
In your view you are using a string instead of the variable you created. And you probably need to filter on the field domainKey instead of pk.
Try changing
obj = get_object_or_404(Store, pk='store_domainKey')
to
obj = get_object_or_404(Store, domainKey=store_domainKey)

Haystack + solr duplicate on update

I'm new to haystack/solr so this is likely a newbie error. I am using solr with haystack.
When I run update_index, it seems to be duplicating the records. I am getting:
get() returned more than one Doctor -- it returned 3!
for this piece of code:
self._object = self.searchindex.read_queryset().get(pk=self.pk)
if I run update_index again, the number return increases by one and if I run rebuild_index, it will work showing only one record until I update again.
So from that, It seems that update_index is duplicating records in the index. How do I get it from not doing that?
Here is my haystack search index:
from haystack import indexes
from .models import Doctor, Zipcode
from django.contrib.gis.measure import D
from django.conf import settings
class DoctorIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.EdgeNgramField(document=True, use_template=True)
name = indexes.EdgeNgramField(model_attr='name')
specialty = indexes.MultiValueField()
condition = indexes.MultiValueField()
procedure = indexes.MultiValueField()
premium = indexes.BooleanField()
location = indexes.LocationField(model_attr='main_office__location')
latitude = indexes.DecimalField(indexed=False)
longitude = indexes.DecimalField(indexed=False)
docid = indexes.IntegerField()
slugify_name = indexes.CharField(indexed=False)
rendered = indexes.CharField(use_template=True, indexed=False)
premium_rendered = indexes.CharField(use_template=True, indexed=False)
include = indexes.BooleanField(indexed=False)
def get_model(self):
return Doctor
def prepare_specialty(self, obj):
return ["%s %s"%((specialty.parent.name if specialty.parent else ""), specialty.name) for specialty in obj.specialty.all()]
def prepare_condition(self, obj):
return [condition.name for condition in obj.conditions.all()]
def prepare_procedure(self, obj):
return [procedure.name for procedure in obj.procedures.all()]
def prepare_premium(self, obj):
return obj.display()['premium']
def prepare_latitude(self, obj):
return obj.main_office.lat
def prepare_longitude(self, obj):
return obj.main_office.lon
def prepare_docid(self,obj):
return obj.id
def prepare_slugify_name(self,obj):
return obj.slugify_name()
def index_queryset(self, using=None):
"""Used when the entire index for model is updated."""
return self.get_model().objects.filter(specialty__search_include=True)
Here is my solr schema: https://gist.github.com/anonymous/5d5b011ca7fa0f3f3e29
I've done a lot of googling, but can't seem to find an answer to this.
So this one was tricky to track down, but the problem was actually in my index_queryset function.
This:
return self.get_model().objects.filter(specialty__search_include=True)
should actually be this:
return self.get_model().objects.filter(specialty__search_include=True).distinct()
That function had duplicates in it and was causing my error, not the solr schema like I had thought. Specialty is a ManyToManyField.
I just faced the same issue.
According to this topic it is necessary to remove .pyc files. Inside of a project simply do the next (for Linux):
find . -name "*.pyc" -type f -delete

Django haystack search returning items that are excluded

I have been having some issues with django-haystack and need some help.
I run a site that indexes projects and certain projects are in a status where they should not be seen, ie status='DE', status='PR'
my current setup is.
from haystack.indexes import *
from haystack import site
from models import Project
class ProjectIndex(RealTimeSearchIndex):
project_name = CharField(document=True, use_template=True)
description = CharField(use_template=True, model_attr='description')
location = CharField(use_template=True, model_attr='location')
owner = CharField(model_attr='owner')
def search(self):
return Project.objects.filter(status='AP').exclude(status='PR').exclude(status='DE')
def index_queryset(self):
"""Used when the entire index for model is updated."""
return Project.objects.filter(status='AP').exclude(status='PR').exclude(status='DE')
def get_queryset(self):
"""Used when the entire index for model is updated."""
return Project.objects.filter(status='AP').exclude(status='PR').exclude(status='DE')
def read_queryset(self):
"""Used when the entire index for model is updated."""
return Project.objects.filter(status='AP').exclude(status='PR').exclude(status='DE')
site.register(Project, ProjectIndex)
I managed to solve this issue by updating from 1.1 to 1.2
then all of the sudden I started receiving these Caught VariableDoesNotExist while rendering: Failed lookup for key [object] in u'None'
Googled it and found out that certain items might have disappeared out of the system and there is a handy command for that.
now I have a cronjob that does the following /usr/bin/python2.6 /www/mysite/manage.py update_index --remove every few hours

Django 1.1.1's Feed only displays the latest item, while there are many

I've created a Feed subclass to export a simple feed of news
#urls.py
from django.conf.urls.defaults import *
from litenewz.feeds import NewsFeed
feeds = {
'news': NewsFeed,
}
urlpatterns = patterns(
'',
(r'^feeds/(?P<url>.*)/$',
'django.contrib.syndication.views.feed',
{'feed_dict': feeds}),
)
#feeds.py
from django.contrib.syndication.feeds import Feed
from litenewz.models import News
class NewsFeed(Feed):
title = 'example news'
link = 'http://example.net'
description = 'Latest Newz from example.'
item_author_name = '...'
item_author_email = '...'
item_author_link = 'http://example.net'
def items(self):
return News.objects.order_by('-time')[:15]
#models.py
from django.db import models
from django.utils.translation import ugettext as _
from datetime import datetime
class News(models.Model):
class Meta:
ordering = ('-time', )
verbose_name = _('News')
verbose_name_plural = _('News')
title = models.CharField(
_('Title'),
max_length=512)
time = models.DateTimeField(
_('Date and time'),
default=datetime.now
)
content = models.TextField(
_('Content'))
def __unicode__(self):
return self.title
#models.permalink
def get_absolute_url(self):
return ('home', (), {})
As you can see the Feed subclass' items() method returns the first 15 objects in News.objects.order_by('-time'):
def items(self):
return News.objects.order_by('-time')[:15]
Nevertheless, only one item is exported in the feed: hxxp://www.sshguard.net/litenewz/feeds/news/
Unfortunately, there are two objects of the News model:
>>> from litenewz.models import *
>>> News.objects.all()
[<News: Version 1.5 and timing>, <News: SSHGuard news>]
Any help?
I prefer not to switch to Django 1.2, unless this is strictly necessary to solve the issue described.
Update: the RSS returned indeed contains both the objects, but the RSS is not valid and thus readers such as Safari's are fooled:
http://validator.w3.org/feed/check.cgi?url=http://www.sshguard.net/litenewz/feeds/news/
Looks like it's not valid because you've not generated your guid correctly:
The validator says:
This feed does not validate.
line 25, column 83: guid values must not be duplicated within a feed:
... )</author><guid>http://www.sshguard.net/</guid></item></channel></rss>
The reason is that your get_absolute_url method on your News model returns the same thing for each News instance - do you have unique URLs for each News item? If so you should use that rather than:
def get_absolute_url(self):
return ('home', (), {})
The validation error appears to be from the <guid> element in each item of your feed. As far as I can tell, this is auto-generated from the get_absolute_url() method of the model, in your case the News model. Have you defined that method? If so, is it actually returning a distinct URL for each item?