I simply want to implement a search view into my Django app. But when i try to search something on my App i get the following error:
'unrecognized token: "#"'
In the end i want that my Query is a combination of category and searchword. So that the user can filter specific categories (Just like Amazon.com searchfield) e.g.: http://127.0.0.1:8000/search/?category=1&q=hallo
base.html
...
<div class="globalsearch">
<form id="searchform" action="{% url 'search' %}" method="get" accept-charset="utf-8">
<label for="{{ categorysearch_form.category.id_for_label }}">In category: </label> {{ categorysearch_form.category }}
<input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search for ...">
<button class="searchbutton" type="submit">
<i class="fa fa-search"></i>
</button>
</form>
</div>
</div>
...
categorysearch_form is a dropdown selector that gets his ID from the Database.
views.py
...
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
from django.views.generic import ListView
class globalsearch(ListView):
"""
Display a Post List page filtered by the search query.
"""
model = Post
paginate_by = 10
def get_queryset(self):
qs = Post.objects.all()
keywords = self.request.GET.get('q')
if keywords:
query = SearchQuery(keywords)
title_vector = SearchVector('title', weight='A')
content_vector = SearchVector('content', weight='B')
tag_vector = SearchVector('tag', weight='C')
vectors = title_vector + content_vector + tag_vector
qs = qs.annotate(search=vectors).filter(search=query)
qs = qs.annotate(rank=SearchRank(vectors, query)).order_by('-rank')
return qs
...
urls.py
...
url(r'^search/$', views.globalsearch.as_view(), name='search'),
...
Search.html results are getting displayd here:
{% extends 'quickblog/base.html' %}
{% block content %}
{% for post in object_list %}
<div class="post">
<h1><u>{{ post.title }}</u></h1>
<p>{{ post.content|linebreaksbr }}</p>
<div class="date">
<a>Published by: {{ post.author }}</a><br>
<a>Published at: {{ post.published_date }}</a><br>
<a>Category: {{ post.category }}</a><br>
<a>Tag(s): {{ post.tag }}</a>
</div>
</div>
{% endfor %}
Post Model
...
#Post Model
class Post(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
title = models.CharField(max_length=75)
content = models.TextField(max_length=10000)
tag = models.CharField(max_length=50, blank=True)
category = models.ForeignKey(Category, verbose_name="Category", on_delete=models.CASCADE, null=True)
postattachment = fields.FileField(upload_to='postattachment/%Y/%m/%d/', blank=True ,null=True)
postcover = fields.ImageField(upload_to='postcover/%Y/%m/%d/', null=True, dependencies=[
FileDependency(processor=ImageProcessor(
format='JPEG', scale={'max_width': 200, 'max_height': 200}))
])
created_date = models.DateField(auto_now_add=True)
published_date = models.DateField(blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
class Meta:
ordering = ["-title"]
def __str__(self):
return self.title
...
i guess im simply missing something
at that point...
I already read that this issue comes from local SQL database aka. SQLite, could that be true?
Smb. has a solution?
Thanks
After a bit of tinkering with a friend i found a solution, the Django Documentation according to vector searching is really not that good...
views.py
class globalsearch(ListView):
"""
Display a Post List page filtered by the search query.
"""
model = Post
paginate_by = 10
template_name = 'quickblog/search.html'
def get_queryset(self):
keywords = self.request.GET.get('q')
if keywords:
query = SearchQuery(keywords)
title_vector = SearchVector('title', weight='A')
content_vector = SearchVector('content', weight='B')
tag_vector = SearchVector('tag', weight='C')
vectors = title_vector + content_vector + tag_vector
qs = Post.objects.annotate(rank=SearchRank(vectors, query)).filter(rank__gte=0.1).order_by('-rank')
return qs
models.py
#Post Model
class Post(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
title = models.CharField(max_length=75)
content = models.TextField(max_length=10000)
tag = models.CharField(max_length=50, blank=True)
category = models.ForeignKey(Category, verbose_name="Category", on_delete=models.CASCADE, null=True)
postattachment = fields.FileField(upload_to='postattachment/%Y/%m/%d/', blank=True ,null=True)
postcover = fields.ImageField(upload_to='postcover/%Y/%m/%d/', null=True, dependencies=[
FileDependency(processor=ImageProcessor(
format='JPEG', scale={'max_width': 200, 'max_height': 200}))
])
created_date = models.DateField(auto_now_add=True)
published_date = models.DateField(blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
class Meta:
ordering = ["-title"]
def __str__(self):
return self.title
search.html
{% extends 'quickblog/base.html' %}
{% block content %}
{% for post in object_list %}
<div class="post">
<h1><u>{{ post.title }}</u></h1>
<p>{{ post.content|linebreaksbr }}</p>
<div class="date">
<a>Published by: {{ post.author }}</a><br>
<a>Published at: {{ post.published_date }}</a><br>
<a>Category: {{ post.category }}</a><br>
<a>Tag(s): {{ post.tag }}</a>
</div>
</div>
{% endfor %}
{% if is_paginated %}
<ul class="pagination">
{% if page_obj.has_previous %}
<li>«</li>
{% else %}
<li class="disabled"><span>«</span></li>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
{% else %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
{% endif %}
{% endblock %}
urls.py
url(r'^search/$', views.globalsearch.as_view(), name='search'),
Hope that i was able to help the next one with that Post :D
Related
I followed a tutorial on Youtube that makes a website to create posts. Currently, I am working on displaying other people's profiles and their posts on their profile pages. I did it by accessing the author of the first post, but it only works if the user posted something. Is there another way to do it?
The view:
class UserProfileView(ListView):
model = Post
template_name = 'blog/user_profile.html' # defaults to <app>/<model>_<viewtype>.html--> blog/post_list.html
context_object_name = 'posts' #defaults to objectlist
paginate_by = 5
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(author=user).order_by('-date_posted')
user_profile.html:
{% extends 'blog/base.html' %}
{% block title %}{{ view.kwargs.username }}'s Profile{% endblock title %}
{% block content %}
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img" src="{{ posts.first.author.profile.image.url }}">
<div class="media-body">
<h2 class="account-heading">{{ view.kwargs.username }}</h2>
<p class="text-secondary">{{ posts.first.author.email }}</p>
<p class="article-content">{{ posts.first.author.profile.bio }}</p>
</div>
</div>
{% if posts.first.author == user %}
<a class="btn btn-outline-secondary ml-2" href="{% url 'change_profile' %}">Edit Profile</a>
{% endif %}
</div>
<br>
{% if posts.first.author == user %}
<h3 class="ml-2 article-title">Blogs You Posted</h3>
{% else %}
<h3 class="ml-2 article-title">Blogs By {{ view.kwargs.username }}</h3>
{% endif %}
And the Post and Profile module:
class Post(models.Model):
title = models.CharField(max_length=50)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self) -> str:
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk':self.pk})
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
bio = models.CharField(max_length=225, blank=True, default='')
def __str__(self) -> str:
return f"{self.user.username}'s Profile"
def save(self, *args, **kwargs):
super(Profile, self).save(*args, **kwargs)
img = Image.open(self.image.path)
if img.height > 300 or img.width > 300:
img.thumbnail((300,300))
img.save(self.image.path)
First off, you probably don't need .first in your template, because you are using the first item from the QuerySet. If you are accessing a User profile, you can use the DetailView. In addition, you can try from a different page and provide filtered posts in context. Something like this, for example.
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['posts'] = Post.objects.filter(author=user) # from kwargs
return context
#template
<ul>
{% for post in posts %}
<li>{{ post.title }}</li>
<li>{{ post.content }}</li>
<li>{{ post.date_posted }}</li>
{% endfor %}
</ul>
PS Regards to Corey.
I have made a Slider Model which contains 3 images and Texts related to it to slide in a Carousel
My issue is that I want these images to be shown as per the order assigned as per the model but only one appears.
If I remove the {% if sliders %} {% for slider in sliders %} the latest image only appears because in the views it is filtered by .latest('timestamp')
I have also tried to replace .latest('timestamp') in the views with .all() it still didn't work
This is the model:
class Slider(models.Model):
title = models.CharField(max_length=60)
image = models.ImageField(blank=False, upload_to='Marketing')
order = models.IntegerField(default=0)
header_text = models.CharField(max_length=120, null=True, blank=True)
middle_text = models.CharField(max_length=120, null=True, blank=True)
footer_text = models.CharField(max_length=120, null=True, blank=True)
button_text = models.CharField(max_length=120, null=True, blank=True)
active = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
class Meta:
ordering = ['order']
def __str__(self):
return self.title
def get_image_url(self):
return "%s/%s" % (settings.MEDIA_URL, self.image)
This is the view:
class HomeView(ListView):
model = Item
paginate_by = 10
template_name = "home.html"
def get_context_data(self, **kwargs):
context = super(HomeView, self).get_context_data(**kwargs)
try:
context['marketing_message'] = MarketingMessage.objects.filter(
active=True).latest('timestamp')
except MarketingMessage.DoesNotExist:
context['marketing_message'] = None
try:
context['slider'] = Slider.objects.filter(
active=True).latest('timestamp')
except Slider.DoesNotExist:
context['slider'] = None
return context
This is the template:
{% if slider %}
{% for slider in sliders %}
<div class="carousel-item {% if forloop.first %} active {% endif %}">
<div class="view" style="background-image: url('{{ slider.get_image_url }}'); background-repeat: no-repeat; background-size: cover;">
<div class="mask rgba-black-strong d-flex justify-content-center align-items-center">
<div class="text-center white-text mx-5 wow fadeIn">
<h1 class="mb-4">
{% if slider.header_text %}
<strong>{{ slider.header_text }}</strong>
{% endif %}
</h1>
<p>
{% if slider.middle_text %}
<strong>{{ slider.middle_text }}</strong>
{% endif %}
</p>
<p class="mb-4 d-none d-md-block">
{% if slider.footer_text %}
<strong>{{ slider.footer_text }}
</strong>
{% endif %}
</p>
{% if slider.button_text %}
<a target="_blank" href="" class="btn btn-outline-white btn-lg">
{{ slider.button_text }}
<i class="fas fa-graduation-cap ml-2"></i>
</a>
{% endif %}
</div>
</div>
</div>
</div>
{% endfor %}
{% endif %}
make following changes
views.py
class HomeView(ListView):
model = Item
paginate_by = 10
template_name = "home.html"
def get_context_data(self, **kwargs):
context = super(HomeView, self).get_context_data(**kwargs)
try:
context['marketing_message'] = MarketingMessage.objects.filter(active=True).latest('timestamp')
except MarketingMessage.DoesNotExist:
context['marketing_message'] = None
try:
context['sliders'] = Slider.objects.filter(active=True).order_by('timestamp')
except Slider.DoesNotExist:
context['sliders'] = None
return context
template
{% if sliders %}
{% for slider in sliders %}
#Your html code
{% endfor %}
{% endif %}
You have declared context['slider'] in views.py whereas, you call it sliders in your templates.
Now you will not be able to loop through because that calls one object only so do the following changes in views.py:
context['slider'] = Slider.objects.filter(active=True).latest('timestamp')
to
context['slider'] = Slider.objects.filter(active=True)
I am trying to implement dynamic tabs in my project that gives multiple tabs based on the values stored in the database.
In my case, I have two values stored in database so it's displaying just two, If I will increase more, it will show accordingly.
Category.objects.filter(category='MEDICINES')
Out[14]: <QuerySet [<Category: FRUITS>, <Category: GRAINS>]>
Here is my models.py file,
from django.db import models
from django.contrib.auth.models import User
STATUS = ((0, "Draft"), (1, "Publish"))
class Category(models.Model):
category_names = (
('DISEASES','DISEASES'),
('MEDICINES','MEDICINES'),
('ENCYCLOPEDIA','ENCYCLOPEDIA'),
)
category = models.CharField(max_length=100, choices=category_names)
sub_category = models.CharField(max_length=100, unique=True)
def __str__(self):
return self.sub_category
class Medicine(models.Model):
title = models.CharField(max_length=200, unique=True)
display_name = models.CharField(max_length=17, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='medicine_posts')
category = models.ForeignKey(Category, on_delete=models.CASCADE)
updated_on = models.DateTimeField(auto_now=True)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=0)
class Meta:
ordering = ["-created_on"]
def __str__(self):
return self.title
def get_absolute_url(self):
from django.urls import reverse
return reverse("medicine_detail", kwargs={"slug": str(self.slug)})
Here it my views.py file,
from django.views import generic
from .models import Medicine, Category
from django.shortcuts import render, get_object_or_404
class MedicineList(generic.ListView):
queryset = {'medicine' : Medicine.objects.filter(status=1).order_by("-created_on"),
'category' : Category.objects.all()
}
#queryset = Medicine.objects.filter(status=1).order_by("-created_on")
print(queryset)
template_name = "medicine.html"
context_object_name = 'element'
#paginate_by = 10
Here is my medicine.html file,
<div class="container">
<div class="row">
<div class="col-md-8 mt-3 left">
<nav>
<div class="nav nav-tabs nav-fill" id="nav-tab" role="tablist">
{% for item in element.category %}
<a class="nav-item nav-link active" id="{{ item.id }}" data-toggle="tab" href="#{{ item }}" role="tab" aria-controls="nav-home" aria-selected="true">{{ item }}</a>
{% endfor %}
</div>
</nav>
{% for item in element.category %}
<div class="tab-content py-3 px-3 px-sm-0" id="nav-tabContent">
<div class="tab-pane fade show active" id="{{ item }}" role="tabpanel" aria-labelledby="{{ item.id}}">
<table class="col-md-8 mt-3 left">
{% for post in element.medicine %}
{% cycle 'row' '' as row silent %}
{% if row %}<tr>{% endif %}
<td style="padding: 10px;">
<div class="card mb-4">
<div class="card-body">
<h6 class="card-title text-center"> {{ post.display_name }}</h6>
</div>
</div>
</td>
{% if not row %}</tr>{% endif %}
{% endfor %}
</table>
</div>
</div>
{% endfor %}
</div>
{% block sidebar %}
{% include 'sidebar.html' %}
{% endblock sidebar %}
</div>
</div>
Please help me out with this code, it;s not working.
Your queryset should not be a dictionary, Django expects a queryset instance here.
Try:
class MedicineList(generic.ListView):
queryset = Category.objects.all()
# or: model = Category
template_name = "medicine.html"
context_object_name = 'element'
i'm building a following model. I have created a following model as shown below and it is working fine in the admin. I did not create a view for the following because i'm in primary stage of building i'm testing in templates to bring that usernames in userspostlist, but it's not working.
my models.py for following:
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='owner', on_delete=models.CASCADE)
following = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='followed_by')
def __str__(self):
return str(self.following.all().count())
class post(models.Model):
parent = models.ForeignKey("self", on_delete=models.CASCADE, blank=True, null=True)
title = models.CharField(max_length=100)
image = models.ImageField(upload_to='post_pics', null=True, blank=True)
video = models.FileField(upload_to='post_videos', null=True, blank=True)
content = models.TextField()
likes = models.ManyToManyField(User, related_name='likes', blank=True)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
objects = postManager()
def __str__(self):
return self.title
my views.py for userpostlist:
class UserPostListView(ListView):
model = post
template_name = 'blog/user_post.html' #<app>/<model>_<viewtype>.html
context_object_name = 'posts'
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return post.objects.filter(author=user).order_by('-date_posted')
and my userpostlist.html:
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<h1 class="mb-3">posts by {{view.kwargs.username}}</h1>
{% for user in username.owner.following.all %}
{{ user.username }}
{% endfor %}
{% for post in posts %}
<article class="content-section">
<div class="article-metadata">
<div class="img">
<img class="rounded-circle article-img" data-toggle="modal" data-target="#mymodal" src="{{ post.author.profile.image.url }}">
</div>
<div class="profile-info">
<a class="h2" href="{% url 'user-posts' post.author.username %}">{{ post.author }}</a>
<div class="text-muted">{{ post.date_posted }}</div>
</div>
</div>
{% endfor %}
{% endblock content %}
Is there any problem with the userpostlist view in views.py? do i need to add some code there?
You have some options here, where one is to pass users into context:
class UserPostListView(ListView):
...
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['author'] = get_object_or_404(User, username=self.kwargs.get('username')
return context
And then instead of this:
{% for user in username.owner.following.all %}
{{ user.username }}
{% endfor %}
Use this:
{{ author.username }}
I have some issue with displaying WebSubCategory under WebCategory in Django. I have already displayed WebCategory but I am unable to display WebSubCategory under WebCategory.
Here is my models.py file:
class WebCategory(models.Model):
name = models.CharField(max_length=50, unique=True, verbose_name='Category name')
slug = models.SlugField(verbose_name='Slug')
title = models.CharField(max_length=165, null=True)
metadesc = models.TextField(max_length=165, null=True)
created_at = models.DateTimeField(auto_now_add=True, null=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name_plural = 'WebCategory'
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(WebCategory, self).save(*args, **kwargs)
def __str__(self):
return self.name
class WebSubCategory(models.Model):
category = models.ForeignKey('WebCategory', related_name='subcategory', on_delete=models.CASCADE, blank=True,
null=True, verbose_name='Select category')
name = models.CharField(max_length=50)
slug = models.SlugField(unique=True, null=True)
title = models.CharField(max_length=100, null=True)
metadesc = models.TextField(max_length=165, null=True)
description = RichTextField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True, null=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name_plural = 'WebSubCategory'
def __str__(self):
return self.name
Here is my views.py file
def home(request):
context = RequestContext(request)
category_list = WebCategory.objects.order_by('-created_at')[:5]
subcategory_list = WebSubCategory.objects.order_by('-created_at')[:5]
context_dict = {'webcat': category_list, 'websubcat':category_list}
return render_to_response('home.html', context_dict, context)
And here is my header.html file, where i want to diplay category and subcategory
<ul class="nav nav-pills" id="mainNav">
{%if webcat %}
{% for category in webcat %}
<li class="dropdown dropdown-mega">
<a class="dropdown-item dropdown-toggle" href="JavaScript:void()">
{{category.name}}
</a>
{% if websubcat.webcat %}
<ul class="dropdown-menu">
<li>
<div class="dropdown-mega-content">
<div class="row">
{% for subcategory in websubcat.webcat %}
<div class="col-lg-3">
<span class="dropdown-mega-sub-title">Elements 1</span>
<ul class="dropdown-mega-sub-nav">
<li><a class="dropdown-item" href="elements-accordions.html">{{subcategory.name}}</a></li>
</ul>
</div>
{% endfor %}
</div>
</div>
</li>
</ul>
{% else %}
<p>Not Found Submenu</p>
{% endif %}
</li>
{% endfor %}
{% else %}
<p>No Category Found</p>
{% endif %}
Blog
Please help me to display the WebSubCategory under WebCategory.
{% if webcat_set.all|length > 0 %}
{% for subcategory in webcat_set.all %}
<div class="col-lg-3">
<span class="dropdown-mega-sub-title">Elements 1</span>
<ul class="dropdown-mega-sub-nav">
<li><a class="dropdown-item" href="elements-accordions.html"> {{subcategory.name}}</a></li>
</ul>
</div>
{% endfor %}
{% endif %}