Simple search engine in Django. Search in html content - django

How to create simple search engine?
I have something like this:
def search(request):
if 'search' in request.GET:
term = request.GET['search']
if len(term) > 3:
d = Data.objects.filter(Q(content__contains=term) | Q(
desc__contains=term))
count = d.count()
return render_to_response('search_result.html', {'d': d, 'count': count}, context_instance=RequestContext(request))
return render_to_response('search_result.html', context_instance=RequestContext(request))
This is ok if I search in model but I need search in html content (I use django-chunks)

Django chunks data is stored in a model too. You can import it and filter it like any other model
class Chunk(models.Model):
"""
A Chunk is a piece of content associated
with a unique key that can be inserted into
any template with the use of a special template
tag
"""
key = models.CharField(_(u'Key'), help_text=_(u"A unique name for this chunk of content"), blank=False, max_length=255, unique=True)
content = models.TextField(_(u'Content'), blank=True)
description = models.CharField(_(u'Description'), blank=True, max_length=64, help_text=_(u"Short Description"))
class Meta:
verbose_name = _(u'chunk')
verbose_name_plural = _(u'chunks')
def __unicode__(self):
return u"%s" % (self.key,)
contains is an ok way to query if you have an extremely small dataset. It just issues a LIKE query, so it will not scale very well. If you are going to have a significant amount of data it will be a good idea to look for an engine that was created specifically for full text searching.

Related

how to use delete() query in django?

I am trying to delete one of the items of a field in the table.
For example, I want to remove the 'hadi', shown in the image, from the table.
I make query to filter and exclude instance but in final part, delete() query does not accept input such as id or variable to remove specific thing in one field.
image
models.py
class Expense(models.Model):
expenser = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
debtors = models.ManyToManyField(
CustomUser,
related_name='debtors',
)
amount = models.PositiveIntegerField()
text = models.TextField()
date = models.DateField(null=True)
time = models.TimeField(null=True)
def get_debtors(self):
return ", ".join([str(d) for d in self.debtors.all()])
def who_has_no_paid(self):
return ", ".join([str(d) for d in self.debtors.all() if str(d) != str(self.expenser)])
def debt(self):
return int(float(self.amount/self.debtors.all().count()))
def get_absolute_url(self):
return reverse('expense_detail', args=[self.id])
Now what is the query that should be used in view?
Since it is a many to many field you need to use expense_obj.debtors.remove(hadi_obj) rather than using delete().
Documentation is really good for referencing
your view could be :
def remove_hadi(request):
expense_obj = Expense.objects.get(id=some_id) #get the expense obj from where u want to remove hadi
hadi_obj = User.objects.get(name="hadi") # get user obj u want to remove eg: hadi
# use m2m query
expense_obj.debtors.remove(hadi_obj)
return response

Filter querySet by value of page tag field

I'm creating a website using Wagtail. I have a page model called NewsItem. On the page I want to list the most recent news items that have the same tag, alongside the main content of the page itself.
I'm not sure how to get the value of the tag field in order to filter a queryset and return the other news posts.
I've tried various things:
def render(self, value):
news = NewsItem.objects.live().filter(tags__name=value['tags']).order_by('-date')
return render_to_string(self.meta.template, {
'self': value,
'news_items': news,
})
My tag field looks like this:
tags = ClusterTaggableManager(
through=Tags, blank=True, related_name='news_tag',
verbose_name="News tags",
help_text="News, Video..")
I don't know if I need the return render_to_string bit, I just found an similar example online.
Any help appreciated.
NewsItem and Tags model looks like:
class Tags(TaggedItemBase):
content_object = ParentalKey(
'news.NewsItem', related_name='news_tag')
class Meta:
verbose_name = "News tag"
verbose_name_plural = "News tags"
class NewsItem(Page):
thumbnail = models.ForeignKey(
'wagtailimages.Image',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+'
)
tags = ClusterTaggableManager(
through=Tags, blank=True, related_name='news_tag',
verbose_name="News tags",
help_text="News, Video..")
I think you need some extra logic. Not sure if this is correct, but if your value['tags'] is a collection (rather than a value), then you need an IN statement.
This might work:
NewsItem.objects.live().filter(tags__name__in=value['tags'])
If value['tags'] is a list of objects, rather than a list of strings, then you might have to do some formatting on your value['tags']
tags = [tag.name for tag in value['tags']
NewsItem.objects.live().filter(tags__name__in=tags)
https://docs.djangoproject.com/en/2.0/ref/models/querysets/#in

Django bulk edit form

In my project I have a many-to-one relation with one Serie having up to 20 samples. I'm trying to implement a system where a user uploads a (csv)file and is then sent to a page where they can fill in any missing data. I haven't found a way to implement this and was looking for some help. The idea is that I want a table with each row having 4 fields, which are linked to the sample in question and the table will have as many rows as there were samples in the (csv)file. Furthermore, if data is already present for one of the fields, I want it to prefill the field in question. In the end, the updated data is committed by pressing a single save button at the bottom so it's supposed to be one big form.
I've added the models below. The attributes which I want to update in the form are index, pool and remarks, which may be present in the csv file already but often they aren't.
Can anyone give me any tips on how to implement this or hint at methods which are best for implementing something like this?
Models
class Sample(models.Model):
name = models.CharField(max_length=20)
pool = models.ForeignKey(Pool, blank=True, null=True)
serie = models.ForeignKey(Serie, blank=True, null = True)
index = models.ForeignKey(Index, blank=True, null=True)
remarks = models.CharField(max_length=50, blank=True)
def __str__(self):
return self.name
class Serie(models.Model):
a_type = models.ForeignKey(Atype)
name = models.IntegerField()
def __str__(self):
return str(self.a_type)+'-'+str(self.name)
Views
def serie_edit(request,serie_id):
try:
serie = Serie.objects.get(pk=serie_id)
except Serie.DoesNotExist:
raise Http404
index_list = Index.objects.all()
sample_list = Sample.objects.filter(serie__id = serie_id)
return render(request, 'samples/serie_edit.html', {'serie':serie, 'sample_list':sample_list, 'index_list':index_list})

Django Select Drop Down menu Flow

What I'm trying to do is a 2 tier search with drop down menus using Select widget, the results will be a listing of the fields from my Meta.model. the first Tier is a a State listing from State.model. Upon a select it is supposed to list out all of the cities with in the selected state, the problem I'm having (and I think its due to my lack of knowledge) is that the city listing is not filtered but a listing of all cities in my database regardless of state. I'm not sure where or how to pass my variable to be able invoke my .filter() statement.
models.py
class Meta(models.Model):
rcabbr = models.CharField(max_length = 15)
slug = models.SlugField(unique=False)
state = models.ForeignKey('State')
rc_state = models.CharField(max_length = 3)
oerp = models.CharField(max_length=18)
subgrp = models.SlugField()
sonus_pic = models.CharField(max_length=8)
ems = models.CharField(max_length=14)
agc = models.CharField(max_length=14)
def __unicode__(self):
return self.rcabbr
class State(models.Model):
name = models.CharField(max_length=2)
slug = models.SlugField(unique=True)
state_long = models.CharField(max_length=15)
owning_site = models.CharField(max_length=12)
def __unicode__(self):
return self.name
return self.state_long
forms.py
class states(forms.Form):
invent = [(k.name,k.state_long) for k in State.objects.all()]
rclist = forms.ChoiceField(widget=forms.Select, choices=invent)
class rateCenter(forms.Form):
invention = [(k.id,k.rcabbr,k.rc_state) for k in Meta.objects.all()]
rcviews = forms.ChoiceField(widget=forms.Select, choices=invention)
views.py
def StateAll(request):
""" This lists out all of the states within the database that
are served"""
rclist = states()
return render(request, 'statelist.html',{'rclist': rclist})
def RcView(request):
""" this should list all the rateCenters within
the state that was selected in StateAll() """
rclist = request.GET['rclist']
forms = rateCenter()
return render(request, 'rclist.html',{'forms': forms})
Logic tells me I should to do my .filter() statement in the forms.py but unsure how to pass the result from the request.GET in StateAll() view. I do have the debug_toolbar installed so I can see the variable u'rclist' and the value u'LA' (my test state). I had this working 100% using hyperlinks however the size of my test database is miniscule in comparison to what is going to be in the production version and HREF's are just not possible.
my understanding is:
ChainedForeignKey(LinkedModel, LinkedModel.field = "field in first Tier", chained_model_field = "current model_field")
so simple model should I think be something like this?
def State(model.models):
name = models.CharField(max_length=20) #this is the state abbreviation
state_long = models.CharFeild(max_length=20)#this is state long form
def Meta(model.models):
state = models.CharField(max_length=20)
slug = models.SlugField(unique = False) #same values as rcabbr
rcabbr = ChainedForeignKey(State, chained_field = "state_long",
chained_model_field = "slug")
.....
Does that look about right........so the First Field in the drop down should be the State_long, once selected the next should be the slug?. at which time the slug should be passed to my urls and the views for the that final page.
I am going to try this however I'm not 100% sure how to do my views and if I need to do something with forms page or does this cover it? The documentation is not user friendly for someone new to this so any input would be most appreciated!
There are many third party libraries django-smart-selects and dajax come to mind - that will automate this for you along with provide you the necessary javascript to filter the form fields on the fly.
If you are investigating those, here is how you would do it with just the django forms:
class RateCenterForm(forms.Form):
rate_center = forms.ModelChoiceField(queryset=Meta.objects.all())
def __init__(self, *args, **kwargs):
state = kwargs.pop('state')
super(RaterCenterForm, self).__init__(*args, **kwargs)
self.fields['rate_center'].queryset = Meta.objects.filter(state=state)
A ModelChoiceField is a select drop down that takes its values from a model.
Now in your view, you would call it like this:
def show_rate_centers(request):
form = RateCenterForm(state='SomeState')
# .. your normal logic here

Django-Haystack : How to limit search to objects owned by user?

I have successfully made django-haystack with elasticsearch to work.
In the example below, I can search for any sales item and it would show up in the results.
I have created an Index:
class SalesItemIndex(SearchIndex, Indexable):
text = CharField(document=True, use_template=True)
item_description = CharField(model_attr='item_description')
def get_model(self):
return SalesItem
def index_queryset(self):
"""Used when the entire index for model is updated."""
return self.get_model().objects.all()
The model SalesItem:
class SalesItem(models.Model):
item_description = models.CharField(_(u"Item Description"), max_length=40)
company = models.ForeignKey(Company)
def __unicode__(self):
return self.item_description
The problem is though, the user can search for all sales items, even those that don't belong to his company.
Usually instead of returning all salesitems = SalesItem.objects.all() I would rather use this to make sure the user only sees the items that belons to his company:
profile = request.user.get_profile()
sales_items = profile.company.salesitem_set.all()
Would I be able to limit my search with this rule?
You could index the company id in the SalesItemIndex as well:
class SalesItemIndex(SearchIndex, Indexable):
...
company = IntegerField(model_attr='company_id')
And filter it directly in SearchQuerySet:
sales_items = salesitem_set.filter(company=profile.company_id)