I'm using Django to build a website for a football club, which contains many blog articles. I'm trying to include a search bar, but I can't make it work. When submitting the search term, the following error is shown:
DoesNotExist at /web/search/
Articulo matching query does not exist.
Here is my code:
views.py
def search(request):
query = request.GET.get('q', '')
if query:
try:
qset = (
Articulo(titulo__icontains=query) |
Articulo(cuerpo_icontains=query)
)
results = Articulo.objects.filter(qset).distinct()
except Articulo.DoesNotExist:
results = None
else:
results = []
return render_to_response('web/buscar.html', {"results": results, "query": query})
index.html
<div id="busqueda" class="row">
<div class="col-md-12">
<span id="cruz" class="fas fa-times fa-2x"></span>
<form method="GET" action="/web/search/" class="form my-2 my-lg-0">
<input id="searchBox" value="{{ query|escape }}" class="form-control mr-sm-2" type="text" name="q" placeholder="Buscar" aria-label="Buscar">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Buscar</button>
</form>
</div>
</div>
urls.py
url(r'^search/$', search),
models.py
class Articulo(models.Model):
"""Un artículo de la página"""
id = models.AutoField(primary_key=True)
titulo = models.CharField(max_length=100)
slug = models.SlugField(unique=True, default="")
CATEGORIAS = (
('Primera y Sub 21', 'Primera y Sub 21'),
('Inferiores', 'Inferiores'),
('Básquet', 'Básquet'),
('Hockey', 'Hockey'),
('Gurises', 'Gurises'),
('Generales', 'Generales'),
('Institucionales', 'Institucionales'),
('Senior', 'Senior'),
)
categoria = models.CharField(
max_length=200,
choices=CATEGORIAS
)
cuerpo = RichTextField()
fecha_hora= models.DateTimeField()
foto = models.ImageField()
url_video = models.CharField(help_text='Url del video de facebook (opcional). Para obtener el link, ir al video, apretar donde están los 3 puntitos y poner "insertar". Pegar aquí solo el link del video, borrar el resto. Ejemplo: https://www.facebook.com/plugins/video.php?href=https%3A%2F%2Fwww.facebook.com%2FJuanCruzPiornoOficial%2Fvideos%2F302760100205413', max_length=500,blank=True)
album_flickr = models.CharField(help_text="Subir fotos a Flickr, crear un álbum, compartirlo eligiendo la opción 'Insertar', elegir el tamaño más grande, y pegar el link aquí", max_length=700, blank=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.titulo)
super(Articulo, self).save(*args, **kwargs)
def __str__(self):
return self.titulo
try this
def search(request):
query = request.GET.get('q', '')
if query:
try:
qset = Articulo.objects.filter(Q(titulo__icontains=query) | cuerpo_icontains = query) # change is here <<
results = Articulo.objects.filter(some_field=some_value).distinct() # change is here <<
except Articulo.DoesNotExist:
results = None
else:
results = []
return render_to_response('web/buscar.html', {"results": results, "query": query})
Note: I'm not sure why you are using qset and result there!
Since you are trying to perform a "search" (or filtering) you should use "fitler()" instead of get(), it makes more sense semantically. For your information, filter does not raise an exception if the result is empty.
Your code will look similar to:
from django.db.models import Q
def search(request):
results = []
query = request.GET.get('q', '')
if query:
qset = Q(titulo__icontains=query) | Q(cuerpo__icontains=query)
results = Articulo.objects.filter(qset).distinct()
ctx = {"results": results, "query": query}
return render_to_response('web/buscar.html', ctx)
If you are getting DoesNotExist exceptions with code which uses filter() you should take a look to the traceback to look for the liurls.py file to ensure that your desired views is being called and not other one.
first you need to import Q after that you can lookup function that takes keyword-arguments (e.g. filter(), exclude(), get()
from django.db.models import Q
def search(request):
query = request.GET.get('q', '')
if query:
Articulo.objects.get(
Q(titulo__icontains=query) |
Q(cuerpo_icontains=query)
)
return query
for more info you can check the docs here
from django.db.models import Q
def search(request):
results = []
query = request.GET.get('q', None)
if query:
try:
results = Articulo.objects.filter(Q(titulo__icontains=query) | Q(cuerpo_icontains=query))
except Articulo.DoesNotExist:
pass
return render_to_response('web/buscar.html',{"results": results, "query": query})
Related
I need to display a pdf file in a browser, but I cannot find the solution to take the PDF for the folder media, the PDF file was save in my database, but I cannot show.
my urls.py:
urlpatterns = [
path('uploadfile/', views.uploadFile, name="uploadFile"),
path('verPDF/<idtermsCondition>', views.verPDF, name='verPDF'),
]
my models.py:
class termsCondition(models.Model):
title = models.CharField(max_length=20, verbose_name="title")
uploadPDF = models.FileField(
upload_to="PDF/", null=True, blank=True)
dateTimeUploaded = models.DateTimeField(auto_now_add=True)
deleted_at = models.DateTimeField(
auto_now=False, verbose_name="Fecha eliminacion", blank=True, null=True)
class Meta:
verbose_name = "termsCondition"
verbose_name_plural = "termsConditions"
my views.py:
def uploadFile(request):
user = request.user
if user.is_authenticated:
if user.is_admin:
if request.method == "POST":
# Fetching the form data
fileTitle = request.POST["fileTitle"]
loadPDF = request.FILES["uploadPDF"]
# Saving the information in the database
termscondition = termsCondition.objects.create(
title=fileTitle,
uploadPDF=loadPDF
)
termscondition.save()
else:
listfiles = termsCondition.objects.all()[:1].get()
return render(request, 'subirTerminos.html', context={
"files": listfiles
})
else:
messages.add_message(request=request, level=messages.SUCCESS,
message="No tiene suficientes permisos para ingresar a esta página")
return redirect('customer')
else:
return redirect('login2')
def verPDF(request, idtermsCondition):
user = request.user
if user.is_authenticated():
if user.is_admin:
getPDF = termsCondition.objects.get(pk=idtermsCondition)
seePDF = {'PDF': getPDF.uploadPDF}
print(seePDF)
return render(request, 'subirTerminos.html', {'termsCondition': getPDF, 'uploadPDF': getPDF.uploadPDF})
else:
messages.error(request, 'Do not have permission')
else:
return redirect('login2')
my html:
<div>
<iframe id="verPDF" src="media/PDF/{{ uploadPDF.url }}"
style="width:800px; height:800px;"></iframe>
</div>
I want to see my pdf and I cannot do, I want to know how to do, I tried many solutions, I accept js, embed iframe whatever to can solve.
It should be user.is_authenticated not user.is_authenticated() in verPDF view and also I'd recommend you to change <idtermsCondition> to <int:idtermsCondition> as by default (if nothing is given) it is considered as string.
urls.py
urlpatterns = [
path('uploadfile/', views.uploadFile, name="uploadFile"),
path('verPDF/<int:idtermsCondition>/', views.verPDF, name='verPDF'),
]
And the {{uploadPDF.url}} already has the url (full path to the media directory) and try to use <embed> tag so:
<div>
<embed id="verPDF" src="{{uploadPDF.url}}" width="500" height="375" type="application/pdf">
</div>
Note: Always add / at the end of every route
Finally I can solve it, I had problems in my views.py and in the html, when I called uploadPDF my views called another name which was loadpdf and when I rendered it it was another name.
now, views.py:
``def uploadFile(request):
user = request.user
if user.is_authenticated:
if user.is_admin:
if request.method == "POST":
# Fetching the form data
fileTitle = request.POST["fileTitle"]
loadPDF = request.FILES["uploadPDF"]
if termsCondition.objects.all().exists():
listfiles = termsCondition.objects.all()[:1].get()
listfiles.uploadPDF = loadPDF
listfiles.save()
else:
# Saving the information in the database
termscondition = termsCondition.objects.create(
title=fileTitle,
uploadPDF=loadPDF
)
return redirect('uploadFile')
else:
if termsCondition.objects.all().exists():
listfiles = termsCondition.objects.all()[:1].get()
return render(request, 'subirTerminos.html', context={
"files": listfiles.uploadPDF
})
else:
listfiles = {}
return render(request, 'subirTerminos.html', context={"files": listfiles})
else:
messages.add_message(request=request, level=messages.SUCCESS,
message="No tiene suficientes permisos para ingresar a esta página")
return redirect('customer')
else:
return redirect('login2') ``
and html:
<h1 class="title">Visualizador de PDF</h1>
<embed id="verPDF" src="{{files.url}}" width="500" height="375" type="application/pdf">
I have this problem
UnboundLocalError at /products/search local variable 'query' referenced before assignment
/on this code help out, am searching a product using title and category
def search(request):
try:
q = request.GET.get('q', '')
except:
q = False
if q:
query = q
product_queryset = Product.objects.filter(
Q(name__icontains=q)|
Q(description__icontains=q)
)
category_queryset = Category.objects.filter(
Q(title__icontains=q)|
Q(description__icontains=q)
)
results = list(chain(product_queryset,category_queryset))
context = {
'query':query,
'product_queryset':product_queryset,
'category_queryset':category_queryset,
'results':results,
}
return render(request,"products/search.html", context)
Like Selcuk said, you're not defining query if q is None/False. Try:
def search(request):
try:
q = request.GET.get('q', '')
except:
q = False
if q:
query = q
else:
query = None
product_queryset = Product.objects.filter(
Q(name__icontains=q)|
Q(description__icontains=q)
)
category_queryset = Category.objects.filter(
Q(title__icontains=q)|
Q(description__icontains=q)
)
results = list(chain(product_queryset,category_queryset))
context = {
'query':query,
'product_queryset':product_queryset,
'category_queryset':category_queryset,
'results':results,
}
return render(request,"products/search.html", context)
We're not sure what query is supposed to be or how you're using it though. Setting it to None should fix the UnboundLocalError.
I also don't see any reason that you need to wrap q = request.GET.get('q', '') in a try/except block. get will return '' if q isn't defined. You could simplify the code to be:
def search(request):
q = request.GET.get('q', '')
product_queryset = Product.objects.filter(
Q(name__icontains=q)|
Q(description__icontains=q)
)
category_queryset = Category.objects.filter(
Q(title__icontains=q)|
Q(description__icontains=q)
)
results = list(chain(product_queryset,category_queryset))
context = {
'query': q,
'product_queryset':product_queryset,
'category_queryset':category_queryset,
'results':results,
}
return render(request,"products/search.html", context)
template form
<form method="get" action="{% url 'products:search' %}">
<button class="flex-c-m trans-04">
<i class="zmdi zmdi-search"></i>
</button>
<input class="plh3" type="text" placeholder="Search..." name="q">
</form>
I'm creating a blog in which i want to perform a search query based on ones rating (1-5). Here my search would be like query:"smart phone tech updates", rating:"3". Result should be list of post that contains query word(at least one word) which has rating 3, in a sorted way on val(for each query word, if found in title val+=1 if found in content val+=0.4).
My models.py file has the following :
class Post(models.Model):
title = models.CharField(max_length=50)
content = models.CharField(max_length=500)
rating = models.IntegerField(default=1)
enter code here
date = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
My view.py file has the following:
def search(request):
contents = Post.objects.all()
if request.method == 'GET':
query = request.GET['query']
rating = request.GET['rating']
# search function
# contents = InSearch.search_fun(contents,query,rating)
vector = SearchVector('title', weight='A') + SearchVector('content', weight='B')
qry = SearchQuery(str(query))
contents = Post.objects.annotate(rank=SearchRank(vector, qry)).order_by('-rank')
#print("---->\n\t"+query+ str(contents))
context = {
'contents': contents
}
else:
context = {
'contents': Post.objects.all()
}
return render(request, 'feed/home.html', context)
My urls.py is:
urlpatterns = [
#...
path('feed/search-result/', views.search, name='feed_search'),
]
I'm getting this error
django.db.utils.OperationalError: no such function: plainto_tsquery
You can try like this in your views for searching.
from django.db.models import Q
def search(request):
q = request.GET.get('q')
if q:
search_results = Post.objects.filter(Q(title__icontains=q)|Q(rating=q))
# if you want the exact then do Post.objects.filter(Q(title__iexact=q) & Q(rating=q))
return render(request, 'feed/home.html','search_results':search_results)
else:
messages.info(request,'no results found for {}',format(q))
If you want to sort search query result by number of matches then you can try like this:
search_results = Post.objects.filter(Q(title__icontains=q)|Q(rating=q)).annotate(title_counts=Count('title')).order_by('-title_counts')
And in your template give name='q' in the search form.
<form action="{% url 'your search action' %}">
<input type="text" name="q">
<input type='submit' value='Search'>
</form>
i added a second model to my app and now i also want to search trough the fields for that model and return it in the same view as my first model.
views.py
#Elasticsearch
def globalsearch_elastic(request):
qs = request.GET.get('qs')
page = request.GET.get('page')
if qs:
qs = PostDocument.search().query("multi_match", query=qs, fields=["title", "content", "tag"])
qs = qs.to_queryset()
else:
qs = ''
paginator = Paginator(qs, 10) # Show 10 results per page
try:
qs = paginator.page(page)
except PageNotAnInteger:
qs = paginator.page(1)
except EmptyPage:
qs = paginator.page(paginator.num_pages)
return render(request, 'MyProject/search/search_results_elastic.html', {'object_list':qs})
currently only PostDocument get searched for a match, how do i add a second one here from documents.py in this function?
or to be more specific, what do i have to change in this line to Search multiple documents?
qs = PostDocument.search().query("multi_match", query=qs, fields=["title", "content", "tag"])
this is where "qs" comes from (base.html):
<div class="globalsearch">
<form id="searchform" action="{% url 'search' %}" method="get" accept-charset="utf-8">
<div class="form-row align-items-center">
<input class="class-search-input-fields" id="searchbox" name="qs" required="required" type="text" placeholder="Search ..."><a>in</a>
<div class="custom-dropdown">
<a>{{ categorysearch_form.category }}</a>
</div>
<button class="btn btn-dark" type="submit">
<i class="fa fa-search"></i>
</button>
</div>
</form>
</div>
documents.py:
Thanks in advance
Got it working like this:
def globalsearch_elastic(request):
qs = request.GET.get('qs')
page = request.GET.get('page')
if qs:
post = PostDocument.search().query("multi_match", query=qs, fields=["title", "content", "tag"]).to_queryset()
post_extra = PostExtraDocument.search().query("multi_match", query=qs, fields=["title", "content_preview", "tag"]).to_queryset()
qs = list(
sorted(
chain(post, post_extra),
key=lambda objects: objects.pk
))
else:
qs = ''
paginator = Paginator(qs, 10) # Show 10 results per page
try:
qs = paginator.page(page)
except PageNotAnInteger:
qs = paginator.page(1)
except EmptyPage:
qs = paginator.page(paginator.num_pages)
return render(request, 'MyProject/search/search_results_elastic.html', {'object_list': qs})
i know that this is maybe not "best-practice" because i always have to load all posts, sort them afterwards and display them by creation-date (pk).
Anyways, from my point of view it's fine if you don't have to search millions f posts ... Beside that you still have the power of elastic even if that does not sort my qs list of posts
The accepted answer is correct but not efficient because it fetches rows from the database to convert the results to a querysets and finally chain and sort...
I hope my answer will help others. I'm using django-oscar and dajngo-elasticsearch-dsl and I assume that you're at least using elasticsearch-dsl. So you can simply do
# *********************************************** documents.py in user module
from django_elasticsearch_dsl import Document
from django_elasticsearch_dsl.registries import registry
from oscar.core.compat import get_user_model
User = get_user_model()
#registry.register_document
class UserDocument(Document):
class Index:
name = 'users'
settings = {
'number_of_shards': 1,
'number_of_replicas': 0
}
class Django:
model = User # <-- User model class
fields = [
'first_name',
'last_name',
'username'
]
# *********************************************** documents.py in product module
from django_elasticsearch_dsl import Document, TextField
from django_elasticsearch_dsl.registries import registry
from oscar.core.loading import get_model
Product = get_model('catalogue', 'product')
#registry.register_document
class ProductDocument(Document):
upc = TextField(attr='upc', required=False)
class Index:
name = 'products'
settings = {
'number_of_shards': 1,
'number_of_replicas': 0
}
class Django:
model = Product # <-- Product model class
fields = [
'title',
'description'
]
# *********************************************** search method
from django.shortcuts import render
from elasticsearch_dsl import Search
def global_search(request):
q = request.GET.get('q')
objects = ''
if q:
search = Search(index=['users', 'products'])
objects = search.query("multi_match", query=q, fields=['first_name', 'last_name', 'username', 'title', 'description', 'upc'])
return render(request, 'oscar/search/search.html', {'objects': objects})
In a match query you already search all the tokens in the query as an OR query in SQL . In your case, if you have a multimatch query against 3 field means that you are searching for a match of any of your token in your query against any of that 3 fields - if you haven't assigned any specific mapping to ES, it means that your text fields have processed with a standard analyzer please read here that breaks your string in tokens on whitespace. So to add a new key to be queryied, just concatenate a new value to the string qs:
from document import DocClass
def globalsearch_elastic(request):
qs = request.GET.get('qs')
document = DocClass()
document_value = document.my_function() # you invoke a function in a class inside document.py that returns to you a string
page = request.GET.get('page')
if any([qs, document_value]):
queryable = " ".join([qs, document_value])
qs = PostDocument.search().query("multi_match", query=queryable, fields=["title", "content", "tag"])
qs = qs.to_queryset()
else:
return "No values to query"
I want to join 3 tables and get the results of them without any duplicates
SELECT * FROM `database`.project
INNER JOIN post on project.id = post.project_id
INNER JOIN media on media.post_id = post.id
;
Current output
I was wondering if the output could be something like
floaty
Headphone
fasion + technolgie
I tried using the distinct function. but then it only returns the names's i would like to return the joined tables, because i still want to use that data.
models.py
I am using the Project.with_media() all
"""models."""
from app import db
from peewee import *
import datetime
class Project(Model):
"""Projects."""
name = CharField(unique=True)
content = CharField()
created_date = DateTimeField(default=datetime.datetime.today())
class Meta(object):
"""Select database."""
database = db
def get_project_media(self):
"""Grab image from get_posts."""
post = Post.select().where(Post.project_id == self).get()
return Media.select().where(Media.post_id == post).get().media
def check_media(self):
"""Check if project has media."""
try:
post = Post.select().where(Post.project_id == self).get()
Media.select().where(Media.post_id == post.id).get()
print('True')
return True
except DoesNotExist:
print('False')
return False
This is my calling so i can display it on jinja engine
def with_media():
"""Grab image from get_posts."""
return (Project.select(Project, Post, Media)
.join(Post)
.join(Media)
.where(Post.id == Media.post_id
and
Project.id == Post.project_id))
def posts(self):
"""Return all posts that are accosicated with this project."""
return Post.select().where(Post.project_id == self)
def media_post(self):
"""Return all posts that are accosicated with this project."""
post = Post.select().where(Post.project_id == self)
return post.get_media()
# return Media.select().where(Media.post_id == post).get()
class Post(Model):
"""Model for posts."""
project = ForeignKeyField(Project, backref='Post', null=True, default=None)
name = CharField()
content = TextField()
"Media Model"
"Category Model"
"Project Model"
created_date = DateTimeField(default=datetime.datetime.today())
class Meta(object):
"""Select database."""
database = db
def get_category(self):
"""Grab all the posts from project."""
return (Category.select()
.where(Category.post_id == self))
def get_media(self):
"""Grab all media from this post."""
return (Media.select()
.where(Media.post_id == self))
def standalone():
"""Return a model of all posts not bound to a project."""
return (Post.select()
.where(Post.project.is_null())
.order_by(Post.created_date.desc()))
def date():
"""Return dates order_by."""
return(Post.select()
.order_by(Post.created_date.desc()))
class Media(Model):
"""Media for post."""
post = ForeignKeyField(Post, backref='Media')
media = CharField()
class Meta(object):
"""Select database."""
database = db
class Category(Model):
"""model for all avaible category's."""
post = ForeignKeyField(Post, backref='Category')
name = CharField()
class Meta(object):
"""Select database."""
database = db
def get_name():
"""Get all category's without overlaping."""
categorys = Category.select()
categoryList = []
for category in categorys:
categoryName = category.name.title()
if categoryName not in categoryList:
categoryList.append(categoryName)
return categoryList
def initialize():
"""Create tables."""
db.connect()
db.create_tables([Category, Project, Post, Media], safe=True)
db.close()
main.py
I want to call the projects with media() function so i can use the database items to call images and display content
<ul class='projects'>
{% for project in projects.with_media() %}
{% if loop.index <= 3 %}
<li class='project_w'>
<img src="{{project.media_post()}}" alt="">
<a href="{{url_for('project', id=project.id)}}">
<h2>{{project.name}}</h2>
</a>
</li>
{% else %}
<li class='project_h'>
<img src="{{project.post.media.media}}" alt="">
<a href="{{url_for('project', id=project.id)}}">
<h2>{{project.name}}</h2>
</a>
</li>
{% endif %}
{% endfor %}
</ul>
The problem:
.where(Post.id == Media.post_id
and
Project.id == Post.project_id))
Instead of "and" you must use "&". Please see http://docs.peewee-orm.com/en/latest/peewee/query_operators.html