Skip to content

Commit e8b05f0

Browse files
author
rovsen762
committed
New updates by Chapter 2.
1.First I created search form and search view for searching posts.Also I created searchvertor from postgres by searching blog and body. 2.I define searchrank in view.It allow users that when them search any post they will see the results by relevancy. 3.I define config parametr in searchview.It do possible for us emove stop words in any language or ect. 4.Also searchview provide us to give weith by field.SearchVector() has a default weights are D, C, B, and A, and they refer to the numbers 0.1, 0.2, 0.4, and 1.0, respectively.Also we can define with for search rank to title and body. 5.Also we can use trigram similarity.Trigram similarity provide users when they type different words what is matches 2 letter by our post titles,they can see that post.
1 parent 65b2735 commit e8b05f0

File tree

11 files changed

+1158
-20
lines changed

11 files changed

+1158
-20
lines changed

project/apps/blog/feeds.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import markdown
2+
from django.contrib.syndication.views import Feed
3+
from django.template.defaultfilters import truncatewords_html
4+
from django.urls import reverse_lazy
5+
from .models import Post
6+
class LatestPostsFeed(Feed):
7+
title = 'My blog'
8+
link = reverse_lazy('blog:post_list')
9+
description = 'New posts of my blog.'
10+
11+
def items(self):
12+
return Post.published.all()[:5]
13+
14+
def item_title(self, item):
15+
return item.title
16+
17+
def item_description(self, item):
18+
return truncatewords_html(markdown.markdown(item.body), 30)
19+
20+
def item_pubdate(self, item):
21+
return item.publish

project/apps/blog/forms.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,7 @@ class EmailPostForm(forms.Form):
1010
class CommentForm(forms.ModelForm):
1111
class Meta:
1212
model = Comment
13-
fields = ['name', 'email', 'body']
13+
fields = ['name', 'email', 'body']
14+
15+
class SearchForm(forms.Form):
16+
query = forms.CharField()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Generated by Django 4.1.7 on 2023-03-23 12:13
2+
3+
from django.conf import settings
4+
from django.db import migrations, models
5+
import django.db.models.deletion
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
12+
('blog', '0005_alter_comment_options_and_more'),
13+
]
14+
15+
operations = [
16+
migrations.AlterField(
17+
model_name='post',
18+
name='author',
19+
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='blog_post', to=settings.AUTH_USER_MODEL),
20+
),
21+
]

project/apps/blog/models.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class Status(models.TextChoices):
1717

1818
title = models.CharField(max_length=250)
1919
slug = models.SlugField(max_length=250,unique_for_date='publish')
20-
author = models.ForeignKey(User,on_delete=models.CASCADE,related_name='blog_posts')
20+
author = models.ForeignKey(User,on_delete=models.CASCADE,related_name='blog_post')
2121
body = models.TextField()
2222
publish = models.DateTimeField(default=timezone.now)
2323
status = models.CharField(max_length=2,choices=Status.choices,default=Status.DRAFT)
@@ -41,6 +41,9 @@ def get_absolute_url(self):
4141
self.publish.day,
4242
self.slug])
4343

44+
45+
46+
4447
class Comment(models.Model):
4548
post = models.ForeignKey(Post,
4649
on_delete=models.CASCADE,

project/apps/blog/sitemaps.py

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from django.contrib.sitemaps import Sitemap
22
from .models import Post
3+
34
class PostSitemap(Sitemap):
45
changefreq = 'weekly'
56
priority = 0.9

project/apps/blog/urls.py

+4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
from django.urls import path
22
from . import views
3+
from .feeds import LatestPostsFeed
34
app_name = 'blog'
5+
46
urlpatterns = [
57
path('', views.post_list, name='post_list'),
68
path('tag/<slug:tag_slug>/',views.post_list, name='post_list_by_tag'),
79
path('<int:year>/<int:month>/<int:day>/<slug:post>/', views.post_detail, name='post_detail'),
810
path('<int:post_id>/share/',views.post_share, name='post_share'),
911
path('<int:post_id>/comment/',views.post_comment, name='post_comment'),
12+
path('feed/', LatestPostsFeed(), name='post_feed'),
13+
path('search/', views.post_search, name='post_search'),
1014
]

project/apps/blog/views.py

+34-9
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,39 @@
11
from django.shortcuts import render
2-
from .models import Post,Comment
2+
from .models import Post, Comment
33
from django.http import Http404
44
from django.shortcuts import render, get_object_or_404
5-
from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger
5+
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
66
from django.views.generic import ListView
7-
from .forms import EmailPostForm , CommentForm
7+
from .forms import EmailPostForm, CommentForm , SearchForm
88
from django.core.mail import send_mail
99
from django.views.decorators.http import require_POST
1010
from taggit.models import Tag
11+
from django.contrib.postgres.search import SearchVector,SearchQuery, SearchRank
1112
from django.db.models import Count
13+
from django.contrib.postgres.search import TrigramSimilarity
14+
1215
def post_list(request, tag_slug=None):
1316
post_list = Post.published.all()
1417
tag = None
1518
if tag_slug:
1619
tag = get_object_or_404(Tag, slug=tag_slug)
1720
post_list = post_list.filter(tags__in=[tag])
21+
1822
paginator = Paginator(post_list, 3)
1923
page_number = request.GET.get('page', 1)
24+
2025
try:
2126
posts = paginator.page(page_number)
27+
2228
except PageNotAnInteger:
2329
posts = paginator.page(1)
30+
2431
except EmptyPage:
25-
# If page_number is out of range deliver last page of results
32+
# If page_number is out of range deliver last page of results
2633
posts = paginator.page(paginator.num_pages)
27-
return render(request,'list.html',{'posts': posts,'tag': tag})
34+
35+
return render(request, 'list.html', {'posts': posts, 'tag': tag})
36+
2837

2938
def post_detail(request, year, month, day, post):
3039
post = get_object_or_404(Post,
@@ -37,13 +46,14 @@ def post_detail(request, year, month, day, post):
3746
comments = post.comments.filter(active=True)
3847
# Form for users to comment
3948
form = CommentForm()
40-
return render(request,'detail.html',{'post': post,'comments': comments,'form': form})
49+
return render(request, 'detail.html', {'post': post, 'comments': comments, 'form': form})
50+
4151

4252
def post_share(request, post_id):
4353
post = get_object_or_404(Post, id=post_id, status=Post.Status.PUBLISHED)
4454
sent = False
4555
if request.method == 'POST':
46-
# Form was submitted
56+
# Form was submitted
4757
form = EmailPostForm(request.POST)
4858
if form.is_valid():
4959
cd = form.cleaned_data
@@ -57,12 +67,14 @@ def post_share(request, post_id):
5767
sent = True
5868
else:
5969
form = EmailPostForm()
60-
return render(request, 'share.html', {'post': post,'form': form,'sent': sent})
70+
return render(request, 'share.html', {'post': post, 'form': form, 'sent': sent})
71+
6172

6273
@require_POST
6374
def post_comment(request, post_id):
6475
post = get_object_or_404(Post, id=post_id, status=Post.Status.PUBLISHED)
6576
comment = None
77+
print(request.POST)
6678
form = CommentForm(data=request.POST)
6779
if form.is_valid():
6880
# Create a Comment object without saving it to the database
@@ -71,4 +83,17 @@ def post_comment(request, post_id):
7183
comment.post = post
7284
# Save the comment to the database
7385
comment.save()
74-
return render(request, 'comment.html',{'post': post,'form': form,'comment': comment})
86+
return render(request, 'comment.html', {'post': post, 'form': form, 'comment': comment})
87+
88+
def post_search(request):
89+
form = SearchForm()
90+
query = None
91+
results = []
92+
if 'query' in request.GET:
93+
form = SearchForm(request.GET)
94+
if form.is_valid():
95+
query = form.cleaned_data['query']
96+
results = Post.published.annotate(
97+
similarity=TrigramSimilarity('title', query),
98+
).filter(similarity__gt=0.1).order_by('-similarity')
99+
return render(request,'search.html',{'form': form,'query': query,'results': results})

project/config/settings.py

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""
1+
""""
22
Django settings for config project.
33
44
Generated by 'django-admin startproject' using Django 4.1.7.
@@ -15,7 +15,6 @@
1515
# Build paths inside the project like this: BASE_DIR / 'subdir'.
1616
BASE_DIR = Path(__file__).resolve().parent.parent
1717

18-
1918
# Quick-start development settings - unsuitable for production
2019
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
2120

@@ -42,14 +41,14 @@
4241
'django.contrib.staticfiles',
4342
'django.contrib.sites',
4443
'django.contrib.sitemaps',
44+
'django.contrib.postgres',
4545
# Local apps:
4646
'apps.blog',
4747

4848
# 3-rd party apps:
4949
'django_extensions',
5050
'taggit',
5151

52-
5352
]
5453

5554
MIDDLEWARE = [
@@ -82,16 +81,25 @@
8281

8382
WSGI_APPLICATION = 'config.wsgi.application'
8483

85-
8684
# Database
8785
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
8886

8987
DATABASES = {
9088
'default': {
91-
'ENGINE': 'django.db.backends.sqlite3',
92-
'NAME': BASE_DIR / 'db.sqlite3',
89+
'ENGINE': 'django.db.backends.postgresql_psycopg2',
90+
'NAME': 'blog',
91+
'USER': 'blog',
92+
'PASSWORD': 'blog',
93+
'HOST': 'localhost',
94+
'PORT': 5432,
9395
}
9496
}
97+
# DATABASES = {
98+
# 'default': {
99+
# 'ENGINE': 'django.db.backends.sqlite3',
100+
# 'NAME': BASE_DIR / 'db.sqlite3',
101+
# }
102+
# }
95103

96104

97105
# Password validation
@@ -112,7 +120,6 @@
112120
},
113121
]
114122

115-
116123
# Internationalization
117124
# https://docs.djangoproject.com/en/4.1/topics/i18n/
118125

@@ -124,12 +131,11 @@
124131

125132
USE_TZ = True
126133

127-
128134
# Static files (CSS, JavaScript, Images)
129135
# https://docs.djangoproject.com/en/4.1/howto/static-files/
130136

131137
STATIC_URL = 'static/'
132-
STATICFILES_DIRS = [os.path.join(BASE_DIR , 'static')]
138+
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
133139

134140
EMAIL_HOST = 'smtp.gmail.com'
135141
EMAIL_HOST_USER = 'djangoapp762@gmail.com'

0 commit comments

Comments
 (0)