Override the user query in Haystack - python

I want the user query in my Django/Haystack app to be sorted in alphabetical order. For example if the user entered "sit" this would be changed to "ist" in the Haystack Search Index.
I believe overriding the default Haystack forms.py will achieve this, but can't get it to work.
#forms.py
from haystack.forms import SearchForm
class WordsSearchForm(SearchForm):
q_default = forms.CharField(required=False, label=_('Search'),
widget=forms.TextInput(attrs={'type': 'search'}))
q = ''.join(sorted(q_default))
Any suggestions on how to achieve this?

Customizing Haystack is a bit tricky it turns out. To override the user query you need to create a forms.py file, update views.py, and update urls.py.
#forms.py
from haystack.forms import SearchForm
class WordsSearchForm(SearchForm):
def search(self):
# added the two lines below
q = self.cleaned_data['q']
q = ''.join(sorted(q))
if not self.is_valid():
return self.no_query_found()
if not self.cleaned_data.get('q'):
return self.no_query_found()
# default is...
# sqs = self.searchqueryset.auto_query(self.cleaned_data['q'])
sqs = self.searchqueryset.auto_query(q)
if self.load_all:
sqs = sqs.load_all()
return sqs
# views.py
from haystack.views import SearchView
from .models import [NAME OF YOUR MODEL]
from .forms import WordsSearchForm
class MySearchView(SearchView):
form = WordsSearchForm
#urls.py
from haystack.views import SearchView, search_view_factory
from scrabble.views import MySearchView
from APP.forms import WordsSearchForm
urlpatterns = patterns('',
# replace default haystack url
# url(r'^search/', include('haystack.urls')),
url(r'^search/$', search_view_factory(
form_class=WordsSearchForm
), name='haystack_search'),
)

Related

What is the best, cleanest and shortest way to check if a given value is valid URL when working with models?

I rather want to use Django's built-in functionalities as much as possible and avoid implementing stuff myself as much as possible!
Why doesn't the following code issue exceptions when given a non-URL value?
models.py:
from django.core.validators import URLValidator
from django.db import models
class Snapshot(models.Model):
url = models.URLField(validators=[URLValidator])
views.py:
from django.http import HttpResponse
from .models import Snapshot
def index(request):
a = Snapshot(url='gott ist tot')
a.save()
Because this validator is run when you use a django form.
More information about validators on the doc : https://docs.djangoproject.com/en/4.1/ref/validators/
if you do a form :
from django import forms
from .models import Snapshot
class SnshotForm(forms.ModelForm):
class Meta:
model = Snapshot
fields = ('url', )
and your views.py :
from django.http import HttpResponse
from .forms import SnapshotForm
def index(request):
a = SnapshotForm(data={'url': 'gott ist tot'})
if a .is_valid()
a.save()
else:
print(a.errors)
Your validator will be run and you will see the errors form message
Without using form, you can call manually validator in your view or in the save method:
# in views
from django.core.validators import URLValidator
from django.core.exceptions import ValidationError
def index(request):
url_validator = URLValidator()
url = 'gott ist tot'
is_valid_url = False
try:
url_validator(url)
except ValidationError:
pass
if is_valid_url:
a = Snapshot(url=url)
a.save()
else:
print(a.errors)
Be careful ! I do not recommanded to bypass the validator with forms, i think it is the better way for maximizing usage of django builtins funtions

How can I receive GET/POST value beside TemplateView class

I'm leaning Python to develop a website. I use Django framework to develop. To create a VIEW using django.views.generic.base.TemplateView.
So I wanna to get value 'user_name' and 'mail' from URL, but don't know how to do that! I cannot import request within this view.
Here is Views.py:
from django.views.generic.base import TemplateView
class MainView(TemplateView):
template_name = 'guestbook/main_page_1.html'
def get_context_data(self, **kwargs):
#I wanna to get value 'user_name' and 'mail' from URL...
name = request.GET.get("user_name") #temp
email = request.GET.get("mail") #temp
context = super(MainView, self).get_context_data(**kwargs)
context['var1'] = name
context['var2'] = email
return context
Here is Urls.py:
from django.conf.urls import patterns, url
from guestbook.views import MainView
urlpatterns = patterns('',
url(r'^$', MainView.as_view(), name='main'),
)
Anybody can help me to do this!
Thanks all!
Request is available in get_context_data() as self.request:
def get_context_data(self, **kwargs):
name = self.request.GET.get("user_name")
email = self.request.GET.get("mail")
...

Importing a class' primary key in to another file's definition using Django

Inside views.py I have this:
def confirm(request):
item = PurchaseOrder.item_number # I want to have the primary key in here and this is wrong
return HttpResponse('test successful')
Inside models.py I have this:
from django.db import models
class PurchaseOrder(models.Model):
item_number = models.AutoField(primary_key=True)
How can I make it so that item will call the primary key of PurchaseOrder? Will I have to import files from models.py? I apologize, I am very new to Django and could not find anything on this.
Part 3 of the tutorial goes through this, but you need a lookup:
from django.shortcuts import get_object_or_404
from myapp.models import PurchaseOrder
def confirm(request, itemnum):
item = get_object_or_404(PurchaseOrder, item_number=itemnum)
print("Got item #: {0.item_number}".format(item)) # a test
return HttpResponse('test successful')
Then in your urls.py:
from django.conf.urls import patterns, url
from myapp import views
urlpatterns = patterns('',
# your other normal url patterns
url(r'^(?P<itemnum>\d+)/$', views.confirm, name='confirm-page'),
)
Yes, you need to import your models into views.
from myappname.models import PurchaseOrder
def confirm(request):
items = PurchaseOrder.objects.all()
return HttpResponse(' '.join([i.item_number for i in items]))
I recommend that you go through the tutorial: https://docs.djangoproject.com/en/dev/intro/tutorial01/
It is explained how to work with the model.

Omit day keyword argument from Django's date_based generic view?

I don't want to have the day in the URL for a detail view while using Django's dated_based generic views. I tried the following but get a TypeError at /logbook/2013/january/testing/ object_detail() takes at least 6 arguments (7 given):
models.py
class Entry(models.Model):
pub_date = models.DateTimeField()
def get_absolute_url(self):
return "/logbook/%s/%s/" % (self.pub_date.strftime("%Y/%B").lower(), self.slug)
urls.py:
from __future__ import absolute_import
from django.conf.urls import patterns, include, url
from .models import Entry
from . import views
urlpatterns += patterns('',
url(r'^logbook/(?P<year>\d{4})/(?P<month>[A-Za-z]+)/(?P<slug>[\w-]+)/$',
views.entry_detail),
)
views.py:
import functools
from django.views.generic import date_based
from .models import Entry
def prepare_arguments(view):
#functools.wraps(view)
def wrapped(request, *args, **kwargs):
kwargs['allow_future'] = request.user.is_staff
kwargs['queryset'] = Entry.objects.all() if request.user.is_staff
else Entry.objects.published()
kwargs['date_field'] = 'pub_date'
return view(request, *args, **kwargs)
return wrapped
#prepare_arguments
def entry_detail(request, *args, **kwargs):
return date_based.object_detail(request, *args, **kwargs)
Is it possible to modify the code above and continue to use the date_based generic view without the day in the URL? If not, can someone please give an example of a simple custom view for the URL pattern url(r'^logbook/(?P<year>\d{4})/(?P<month>[A-Za-z]+)/(?P<slug>[\w-]+)/$', views.entry_detail)?
Thanks to Alasdair for pointing me in the right direction and to ccbv.co.uk. I ended up using DetailView and this worked:
urls.py:
from django.views.generic import DetailView
urlpatterns += patterns('',
url(r'^logbook/(?P<year>\d+)/(?P<month>[-\w]+)/(?P<slug>[\w-]+)/$',
DetailView.as_view(model=Entry),
name="entry_detail"),
)
views.py:
# nothing needed here for the detail view to work, though in the future
# I would like to have the generic view code here instead to accomplish
# the same thing as `DetailView.as_view(model=Entry), name="entry_detail"`
# in urls.py, and would appreciate an example of this.

django registration redirection

I have used custom field in django registration form , every thing is working fine but whenever it try to redirect , it shows following error.
I dont know what i missed here.
NoReverseMatch at /accounts/register/
Reverse for 'registration_complete' with arguments '()' and keyword arguments '{}' not found.
I tried following
URL
url(r'^accounts/register/$', register, {'backend': 'registration.backends.default.DefaultBackend','form_class': RegistrationFormEx}, name='registration_register'),
registrationForm.py
from django import forms
from registration.forms import RegistrationForm
from django.utils.translation import ugettext_lazy as _
from registration.models import RegistrationProfile
class RegistrationFormEx(RegistrationForm):
#ADD ALL CUSTOM FIELDS BELOW
name=forms.CharField()
models.py
import hashlib
import datetime
import hmac
from django.db import models
from django.contrib.auth.models import User
from ecpCommon.models import StateModel
from ecpCommon.enum import enumauto
from ecpPayments.models import PaymentCard
from registration.signals import user_registered
from apps.ecpUser.models import UserProfile
from apps.ecpMerchant.registrationForm import RegistrationFormEx
from apps.ecpCommon.thumbs import ImageWithThumbsField
class MerchantProfile(StateModel):
name = models.CharField('Merchant Name', max_length=64)
def user_created(sender, user, request, **kwargs):
form = RegistrationFormEx(data=request.POST)
new_user = User.objects.get(username=request.POST['username'])
digest=hmac.new(str(request.POST['username'])+str(request.POST['password1']), str(request.POST['password1']),hashlib.sha1).hexdigest()
new_profile = UserProfile(user=new_user,api_key=digest)
new_profile.save()
#now add other fields including password hash as well
uid = new_profile.id
merchant_profile = MerchantProfile(user_id=uid,
create_time=datetime.datetime.now(),
modified_time=datetime.datetime.now(),
payment_card_id=uid,
current_state=1,
name=request.POST['name'],
)
merchant_profile.save()
return new_user
user_registered.connect(user_created)
It's likely because of the registration success redirection in your views is redirecting to a URL: registration_complete, that does not exist.
To fix it, you should add a url record similar to the one you have for registration_register
url(r'^accounts/register/$', register, {'backend': 'registration.backends.default.DefaultBackend','form_class': RegistrationFormEx}, name='registration_register'),
that points to the correct url with name=registration_complete.

Categories