Django-haystack full text search working but facets don't - ajax

Using django-haystack and elasticsearch. Full text search is working ok, but I have
trouble to implement facets. I've searched tutorial on web but with no success, in other words
didn't understand any of them. I am beginner in programing, so some help it will be appreciated.
Thank you in advance. Sorry on my english if isn't good, it isn't my primary language.
Here is my working full text search.
articles.models.py
class Article(models.Model):
category = models.CharField(max_length=60)
subcategory = models.CharField(max_length=100)
name = models.CharField(max_length=255)
price = models.DecimalField(max_digits=8, decimal_places=2)
pub_date = models.DateTimeField(auto_now_add=True)
country = models.CharField(max_length=60)
city = models.CharField(max_length=60)
# other fields ...
12 categories (Vehicles and Parts, Computers and Parts ....)
Subcategories for Vehicles and Parts (Car, Trucks, Bikes, Parts ....)
I solved this with javascript when submitting form for Article, same for country and city.
articles.search_indexes.py
class ArticleIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
subcategory = indexes.CharField(model_attr='subcategory', faceted=True)
price = indexes.DecimalField(model_attr='price', faceted=True)
pub_date = indexes.DateTimeField(model_attr='pub_date', faceted=True)
country = indexes.CharField(model_attr='country', faceted=True)
city = indexes.CharField(model_attr='city', faceted=True)
content_auto = indexes.EdgeNgramField(model_attr='name')
def get_model(self):
return Article
def index_queryset(self, using=None):
return self.get_model().objects.all()
articles_text
{{ object.name }}
{{ object.subcategory }}
{{ object.price }}
{{ object.pub_date }}
{{ object.country }}
{{ object.city }}
articles.views.py
def searchArticles(request):
articles = SearchQuerySet().autocomplete(content_auto=request.POST.get('search_text', ''))
return render_to_response('ajax_search.html', {'articles': articles})
base.html
{% csrf_token %}
<input type="text" id="search" class="edo-trazi" name="search" />
<ul id="search-results">
</ul>
ajax_search.html
{% if articles.count > 0 %}
{% for article in articles %}
<li class="edo-trazi-artikal"><img class="edo-trazi-slika" src="/static/aktiva/{{ artikal.object.slika }}"/>
<a class="edo-trazi-ime" href="/artikli/prikazi/{{ artikal.object.id }}/{{ artikal.object.slug }}/">{{ artikal.object.name }}</a>
{% endfor %}
{% else %}
<li>No results!</li>
{% endif %}
ajax.js
$(function(){
$('#search').keyup(function() {
$.ajax({
type: "POST",
url: "/search/",
data: {
'search_text' : $('#search').val(),
'csrfmiddlewaretoken' : $("input[name=csrfmiddlewaretoken]").val()
},
success: searchSuccess,
dataType: 'html'
});
});
});
function searchSuccess(data, textStatus, jqXHR)
{
$('#search-results').html(data);
}
project.urls.py
url(r'^search/$', 'articles.views.searchArticles'),
url(r'^vehicles-parts/', include('vehiclesParts.urls')),
Above example code is running ok, if someone is interested in autocomplete I can guide
him as much as I know.
vehiclesParts.urls.py
url(r'^$', 'vehiclesParts.views.vehiclesPartsView', name='vehiclesParts'),
url(r'^search/$', 'vehiclesParts.views.searchVehiclesParts'),
vehiclesParts.views.py
def vehiclesPartsView(request):
return render_to_response('vehiclesParts.html', context_instance=RequestContext(request))
def searchVehiclesParts(request):
articles = SearchQuerySet().facet('subcategory').facet('price').facet('pub_date').facet('country').facet('city')
# how to make this code run in similar way like above autocomplete(with ajax), also to
# filter results by category "filter (category= 'Vehicles and Parts')", because this
# advanced search I'll have to do for each category to display and search
# articles only for that category.
return render_to_response('ajax-vehiclesParts.html', {'articles': articles})
ajax-vehiclesParts.html--Can be same as ajax_search.html I'll just add some additonal fields.
vehiclesParts.html--How to add facets in template and on selected subcategory or something else to display results in ajax-vehiclesParts.html via Ajax? Also if posible to remember selected subcategory so if next is selected 'city London' or something else to display results only for that subcategory.
ajax-vehiclesParts.js ?????

Related

Display something upon a change to a BooleanField in a django database in django app

I have an uber like django app. A customer can signal that they are looking for someone to provide a service and people in the same area who are looking to be service providers can view a list of actively seeking customers. When the customer presses the button signaling they are looking for a service, they are redirected to a page that says "Thank you, you will be notified when someone is on the way" and it sets attribute active to True. This displays them on the previously mentioned list where customers can be 'claimed.' When a service provider claims a customer. I want the customer's page to display 'Someone will be there shortly" or something of that nature. But how can I let the customer's page (customer_active.html) know that active has been set to False(ie they have been claimed) and then display a message on the occurrence of that event? I have read about potentially using django signals or ajax/jquery but I do not know what the right route is nor how to implement the solution in said route. I have the following code:
models.py:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
active = models.BooleanField(default = False)
urls.py
urlpatterns = [
#home
url(r'^home/$', views.home, name = 'home'),
#/claim/user_id
url(r'^claim/(?P<user_id>[0-9]+)/$', views.ClaimView.as_view(), name = "claim"),
#/active
url(r'^active/$', views.customer_active, name='customer_active'),
]
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
customer_active.html (the customer is looking at this after they signal they are looking for the service):
{% extends 'core/base.html' %}
{% block head %}
{% load static %}
<link rel="stylesheet" href="{% static 'core/customer_active.css' %}">
<title>Active</title>
{% endblock %}
{% block body %}
<div class="container text-center">
<div class="row">
<div class="col-md-12 mb-3">
<h1 class="lead">Thank you, {{ user.first_name}} {{user.last_name }}, you will be alerted
when someone claims your laundry</h1>
</div>
</div>
</div>
{% endblock %}
home.html:
{% for customer in customers%}
<tr>
<td style = "text-align:center">{{ customer.user.first_name|title }} {{ customer.user.last_name|title }}</td>
<td style = "text-align:center">{{ customer.user.profile.address|title }}</td>
<td style = "text-align:center">Claim</td>
</tr>
{% endfor %}
views.py:
#the service provider that claimed a customer gets redirected to 'claim.html', upon this 'active' gets set to False
class ClaimView(View):
def get(self, request, user_id, *args, **kwargs):
customer = User.objects.get(id=user_id)
customer.profile.active = False
customer.save()
return render(request, 'core/claim.html', {'customer': customer})
def customer_active(request):
request.user.profile.active = True;
request.user.save()
return render(request, 'core/customer_active.html', {'user': request.user})
How can I use ajax/jquery to display a message saying 'Someone will be there shortly" in customer_active.html upon a service provider claiming the customer?
So.. if a customer is in customer_active.html page, when service provider claims the customer, the customer should be alerted in customer_active.html page. If I have perceived the problem correctly, then it is a matter of creating a timer that will send Ajax calls every few seconds to check if a service provider has claimed the customer.
setInterval(function(){
minAjax({
url:"/serviceprovider/",//request URL
type:"GET",//Request type GET/POST
//CALLBACK FUNCTION with RESPONSE as argument
success: function(data){
//check if someone has claimed
if (data == true){
alert("Someone will be there shortly");
}
}
});
}, 5000); //5000 represents 5 seconds
Views.py
#login_required
def serviceprovider(request):
claimed=False
claim=Model.objects.filter(user=User.objects.get(username=request.user), claimed=True)
if claim:
claimed=True
return HttpResponse(json.dumps(claimed))
urls.py
url(r'^serviceprovider/', views.serviceprovider, name = 'serviceprovider'),
You need minAjax for this to work, it is a very small library using pure javascript. Just download the library and put it in your js folder, and import it. I haven't tested the above example but I have used this method in a project and it works. This is just to guide you to the right direction. Good luck!

Use AJAX to update django if-else template

In template I have:
{% for item in items %}
{% if item.public is True%}
<a href="{% url 'motifapp:article_public_edit' article.id %}">
show icon1
</a>
{% else %}
<a href="{% url 'motifapp:article_public_edit' article.id %}">
show icon2
</a>
{% endif %}
{endfor}
I use ajax to handle the request here:
$(anchor).click(function(e){
e.preventDefault();
var href = $(this).attr('href')
$.ajax({
type: 'POST',
url: href,
data: {csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),},
success: function (response) {
//refresh a div ?
}
});
});
Ajax handle the post, and in view it reverse a boolean value 'public'.
Question is, how do I update the template? I can pass the opposite icons and value, but it seems very redundant. Is there a way just to refresh that div with anchor and let the if else statement takes care of what's showing ?
Thanks
You are 99% close to answer your own question.
First, you you must wrap the {% for %} in a div and save it as a separate file, say:
<!-- injection.html -->
<div id="some-id>
{% for item in items %}
same code here
{% endfor %}
</div>
Now in your main template you should include that file like this:
<div id="wrapper">
{% include 'templates/injection.html' %}
</div>
Now, once you make an AJAX request to your views function then this view should render that div (which is a separate html file) but with a different items value. Like this:
# views.py
def article_public_edit(request, id):
if request.is_ajax():
# new calculation of the items QuerySet
# depending on the data passed through the $.ajax
return render(request, 'injection.html', locals())
Finally, you can do this inside the $.ajax() success function:
$.ajax({
type: 'POST',
url: href,
data: {csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),},
success: function (response) {
// replace the inside of #wrapper div with the injection.html (that has the new items values)
$("#wrapper").replaceWith(response);
}
});
With ajax calls there is no way the Django template tags will be re-evaluated. They only get evaluated on initial page load.
I think the best way to go is to have the ajax view return the boolean value and then set the image in your front-end code depending on that value.

OctoberCMS Builder Plugin to Show Data on Front End

This my first time to use OctoberCMS, and they provide the Builder Plugin in order to help the developer builds plugin in minutes.
I try to use this plugin to show the data on the front end especially when using Components > Builder > Record list, but the documentation didn't give enough example to get data from some fields. The example on the internet is just show how to get the data from one field.
My code is shown below:
[builderList]
modelClass = "Budiprasetyo\Employees\Models\Employee"
scope = "-"
displayColumn = "name"
noRecordsMessage = "No records found"
detailsPage = "-"
detailsUrlParameter = "id"
pageNumber = "{{ :page }}"
in my case, I want to get the data not only "name" field, but I also want to add "email", "facebook" fields.
I have tried to make it into:
displayColumn = "name", "email", "facebook"
but it returns no data shown and I have tried to make it into array:
displayColumn = ["name", "email", "facebook"]
and it's the same result, no data is shown.
I appreciate any helps, thank you.
Actually I don't like to use plugins' components. Sometimes it doesn't retrieve any data. I don't know why maybe it's just because of wrong using.
Anyway, The best way to retrieve the data from your plugin is to navigate to the code section and then write onStart() function and start to retrieve to data.
function onStart()
{
$data = \Authorname\Pluginname\Models\Model::find(1);
$this['data'] = $data;
}
And this way you'll have a data variable in the markup section.
On the frontend cms page, you need to replace the component call with your custom partial. Your partial file should look something like this:
*podcastList is the component name
{% set records =podcastList.records %}
{% set displayColumn =podcastList.displayColumn %}
{% set noRecordsMessage =podcastList.noRecordsMessage %}
{% set detailsPage =podcastList.detailsPage %}
{% set detailsKeyColumn =podcastList.detailsKeyColumn %}
{% set detailsUrlParameter =podcastList.detailsUrlParameter %}
{% for record in records %}
<span class="date">{{ attribute(record, 'date') }}</span>
<span class="title">{{ attribute(record, 'title') }}</span>
<p>{{ attribute(record, 'description') }}</p>
{% endfor %}
Obviously, this is simplified version, but you get the point. You can easily define more columns without touching the page component settings.

Django to save the form details in database and retrieve back using ajax

I want to save details in database and retrieve back to same page using Ajax. I added the code for your reference. Kindly share your ideas.
models.py
class Personal(models.Model):
user=models.ForeignKey(User)
name=models.CharField()
dob = models.CharField()
email = models.EmailField()
address1 = models.CharField()
address2 = models.CharField()
country = models.CharField()
state = models.CharField()
city = models.CharField()
Views.py
def profile(request):
userid=request.user.id
personal=JSPersonal.objects.filter(user_id=userid)
return render(request,'registration/profile.html', {'personal':personal})
templates(profile.html)
{% if personal %}
{% for p in personal %}
<p>Name : {{p.name}}</p>
<p>DOB : {{p.dob}}</p>
<p>Email : {{p.email}}</p>
<p>Address1 : {{p.address1}}</p>
<p>Address2 : {{p.address2}}</p>
<p>Country : {{p.country}}</p>
<p>State : {{p.state}}</p>
<p>City:{{p.city}}</p>
{% endfor %}
{%else%}
<p>Click Here to add details</p>
{% endif %}
By clicking the "Here" model form get loaded here there is a space to enter the personal details.Here I need to store details in database and return back to same page once I click submit button in the model form. Only particular content get loaded not whole page.
The basic idea is that you put an element with an ID around the data that will change, and target that id with a jQuery.load call.
see: Render a django table using ajax
I recommend that you use the forms for such tasks: https://docs.djangoproject.com/en/dev/topics/forms/
In this case, you can easily send your form with jQuery $.post():
$.post('/form/url/', $('form_selector').serialize())
.done(function(data) { ... })
.fail(function(jqXHR) { ... });
A more detailed response:
How to POST a django form with AJAX & jQuery

django render_to_string not working

I am trying to implement an ajax view to create an object and then return it and insert it into the template. It is almost working except I cannot seem to get render_to_string() to work to render the html to insert. The object is being created and html is being returned and inserted into the template however the variables are not included in the html. My view is below.
def tr_create_xhr(request, person, slug):
if request.method == "POST":
form = TopicResourceForm(request.POST)
if form.is_valid():
try:
r = Resource.objects.get(url=form.cleaned_data['resource'])
except Resource.DoesNotExist:
r = Resource.objects.create(url=form.cleaned_data['resource'], rtype=form.cleaned_data['rtype'])
r.save()
obj = form.save(commit=False)
obj.resource = r
try:
topic = Topic.objects.get(person__user=request.user, slug__iexact=slug)
except Topic.DoesNotExist:
return Http404
obj.topic = topic
objs = obj.save()
html = render_to_string('includes/tr_inc.html',{"r":objs, "topic":topic})
res = {'html':html}
if request.is_ajax():
return HttpResponse(simplejson.dumps(res), mimetype="application/json")
else:
return HttpResponseRedirect("../..")
return Http404
This is the template "includes/tr_inc.html":
{% load markup %}
{% load people_tags %}
<li>
<h5>{{ r.title }}</h5>
<p><a class="tru" href={{ r.resource.url }}>{{ r.resource.url|sliceit:70 }}</a></p>
<span class="oc"><p>Added {{ r.added }}{% if r.rtype %} |<a href={% url resource_type_detail r.rtype.slug %}>{{ r.rtype }}</a>{% endif %}
| Delete Edit
{{ r.note|markdown }}</span>
</li>
The html string that is returned is the template without any variables inserted.
Model method 'save' doesn't return an object. So you 'objs' variable is empty. You should write
html = render_to_string('includes/tr_inc.html',{"r":obj, "topic":topic})
I had exact the same problem today. It is quite easy. Please check the Django document for this method, there is actually a third optional parameter: context_instance=RequestContext(request). Therefore your render_to_string should be like this:
html = render_to_string(
'includes/tr_inc.html',{"r":obj, "topic":topic},
context_instance=RequestContext(request))
Then everything should work properly.

Resources