The last blog of Blog System hasn't realized the functions of tag search, date search and classification search. This blog is mainly an increase of the above functions.
Add comments
Step 1: Create a new app:comment, add a new app in the main set. py, and modify the main urls.py file
from django.conf.urls import url, include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'',include('blog.urls')), url(r'',include('comments.urls')), ]
Step 2: Write a database form for reviews
from django.contrib.auth.models import User from django.db import models # Create your models here. from blog.models import Post class Comment(models.Model): user =models.ForeignKey(User,verbose_name='user') email = models.EmailField(verbose_name='Mail box') text = models.TextField(max_length=255,verbose_name='Comment text') # auto_now_add=True auto create_time for the latest change in comment information create_time = models.DateTimeField(auto_now_add=True,verbose_name='Creation time') post = models.ForeignKey(Post) class Meta: verbose_name = 'comment' verbose_name_plural = 'comment' def __str__(self): return self.text[:4]
Step 3: Write comment routes comment.urls.py and comment.views.py
# comment.views.py from django.shortcuts import render, get_object_or_404,redirect # Create your views here. from blog.models import Post from comments.forms import CommentForm def post_comment(request, id): # 1. Get blogs selected by users post = get_object_or_404(Post, id=id) # 2. If users submit comments if request.method == 'POST': print(request.POST) form = CommentForm(request.POST) # 2.1 Judging whether the form is legal if form.is_valid(): comment = form.save(commit=False) comment.post = post comment.save() # 2.2 If it is not legal, submit error message else: return render(request, 'blog/detail.html', context={ 'errors': form.errors }) # 3. If it's not a POST request, visit the user details page return redirect(post.get_url())
# comment.urls from django.conf.urls import url, include from django.contrib import admin from comments import views app_name = 'comment' urlpatterns = [ url(r'^comment/blog/(?P<id>\d+)/$',views.post_comment,name='post_comment'), ]
Step 4: Write a comment form
# Synchronization and the Form of Database Comments from comments.models import Comment class CommentForm(forms.ModelForm): class Meta: model = Comment fields = ['user','email','text']
Step 5: Modify the comments section of the HTML file
<section class="comment-area" id="comment-area"> <hr> <h3>Comment</h3> <form action="{% url 'comment:post_comment' post.id %}" method="post" class="comment-form"> {% csrf_token %} <div class="row"> <div class="col-md-4"> <label for="{{ form.user.id }}">{{ form.user.label }}</label> {{ form.user }} </div> <div class="col-md-4"> <label for="{{ form.email.id }}">{{ form.email.label }}</label> {{ form.email }} </div> <div class="col-md-12"> <label for="{{ form.text.id }}">{{ form.text.label }}</label> {{ form.text }} <button type="submit" class="comment-btn">Publish</button> </div> </div> <!-- row --> </form> <div class="comment-list-panel"> <h3>Comments list, total <span>{{ comments.count }}</span> Article comment</h3> <ul class="comment-list list-unstyled"> {% for comment in comments %} <li class="comment-item"> <span class="nickname">{{ comment.user }}</span> <time class="submit-date" datetime="{{ comment.create_time }}">{{ comment.create_time }}</time> <div class="text"> {{ comment.text }} </div> </li> {% endfor %} </ul> </div> </section>
Custom label
The functions of label search, date search and classification search are realized.
Step 1: Customize Tags
- Preparing (necessary) work:
Create a package called templatetags (required and immutable package name) under an app. Suppose we create a template tags package under app named blog and create a file named blog_tags under that package. Ensure that the INSTALLD_APPS in the settings file must contain the app Modify the time display section of set.py
# TIME_ZONE = 'UTC' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True #If USE_TZ=True is configured in setting s, then UTC time (naive time) is output. # If USE_TZ=False is configured in setting, the output time is exactly the same as datetime.datetime.now(). # USE_TZ = True USE_TZ = False
2. Next, write the following lines in the blog_tags file
from django import template register = template.Library()
3. Use {% load%} tags in templates to load custom tags or decorators
from django import template from django.db.models import Count from blog.models import Post, Category, Tag register = template.Library() @register.simple_tag def get_recent_posts(num=3): return Post.objects.all().order_by('-create_time')[:num] @register.simple_tag def archives(): return Post.objects.dates(field_name='create_time', kind='month', order='DESC') @register.simple_tag def get_category(): return Category.objects.annotate(num_posts=Count('post')).filter(num_posts__gt=0) @register.simple_tag def get_tags(): # return Tag.objects.all() return Tag.objects.annotate(num_posts = Count('post'))
Step 2: Write the routing and view functions for label lookup
Route
#blog.urls.py from django.conf.urls import url from django.contrib import admin from blog import views app_name = 'blog' urlpatterns = [ url(r'^$', views.index, name='index'), url(r'blog/(?P<id>\d+)/$', views.detail, name='detail'), url(r'^archive/(?P<year>\d{4})/(?P<month>\d{1,2})/', views.archive, name='archive'), url(r'^category/(?P<id>\d+)/', views.category, name='category'), url(r'^tag/(?P<id>\d+)/', views.tag, name='tag'), url(r'^search', views.search, name='search') ]
View function
from django.db.models import Q from django.http import HttpResponse from django.shortcuts import render, get_object_or_404 # Create your views here. from markdown import markdown from blog.models import Post, Tag from comments.forms import CommentForm def index(request): # return HttpResponse('ok index!') posts = Post.objects.all() return render(request,'blog/index.html',context={ 'posts':posts }) def detail(request,id): # return HttpResponse('ok,%s detail' %(id)) post = Post.objects.get(id=id) post.add_views() form = CommentForm() comments = post.comment_set.all() post.body = markdown(post.body, extensions=['markdown.extensions.extra', 'markdown.extensions.codehilite', 'markdown.extensions.toc', ], output_format='html') return render(request,'blog/detail.html',context={ 'post':post, 'comments':comments, 'form':form, }) def archive(request,year,month): posts = Post.objects.filter( create_time__year=year, create_time__month=month ).order_by('-create_time') return render(request,'blog/index.html',context={ 'posts':posts }) def category(request,id): posts = Post.objects.filter(category_id=id) return render(request,'blog/index.html', context={ 'posts':posts }) def tag(request,id): tag = get_object_or_404(Tag,id=id) posts = Post.objects.filter(tags=tag).order_by('-create_time') return render( request, 'blog/index.html', context={ 'posts': posts } ) def search(request): query = request.GET.get('query',None) posts = Post.objects.filter( Q(title__icontains=query) | Q(body__icontains=query) ) if not posts: return render(request,'blog/index.html', context={ 'posts':posts, 'message':'No relevant information was found.' } ) else: return render(request, 'blog/index.html', context={ 'posts': posts } )
Step 3: Modify the Html file to intercept only part of the code
The structure (directory) of the blog should be displayed on the details page of the blog, and the code to display the directory should be added.
Modifying View Functions
def detail(request,id): # return HttpResponse('ok,%s detail' %(id)) post = Post.objects.get(id=id) post.add_views() form = CommentForm() comments = post.comment_set.all() # post.body = markdown(post.body, # extensions=['markdown.extensions.extra', # 'markdown.extensions.codehilite', # 'markdown.extensions.toc', ], # output_format='html') md = Markdown( extensions=['markdown.extensions.extra', 'markdown.extensions.codehilite', 'markdown.extensions.toc', ], output_format='html' ) # Convert markdown to serialized XHTML or HTML. post.body = md.convert(post.body) post.toc = md.toc return render(request,'blog/detail.html',context={ 'post':post, 'comments':comments, 'form':form, })
Right navigation bar
{# Base template #} <aside class="col-md-4"> {% block toc %} {% endblock %} <div class="widget widget-recent-posts"> <h3 class="widget-title">Latest articles</h3> <ul> {% get_recent_posts as recent_posts %} {% for post in recent_posts %} <li> <a href="{{ post.get_url }}">{{ post.title }}</a> </li> {% endfor %} </ul> </div> <div class="widget widget-archives"> <h3 class="widget-title">File</h3> <ul> {% archives as dates %} {% for date in dates %} <li> <a href="{% url 'blog:archive' date.year date.month %}">{{ date.year }}year {{ date.month }}month</a> </li> {% endfor %} </ul> </div> <div class="widget widget-category"> <h3 class="widget-title">classification</h3> <ul> {% get_category as categories %} {% for category in categories %} <li> <a href="{% url 'blog:category' category.id %}">{{ category.name }}<span class="post-count">({{ category.num_posts }})</span></a> </li> {% endfor %} </ul> </div> <div class="widget widget-tag-cloud"> <h3 class="widget-title">Tag cloud</h3> <ul> {% get_tags as tags %} {% for tag in tags %} <li> <a href="{% url 'blog:tag' tag.id %}">{{ tag.name }}</a> </li> {% endfor %} </ul> </div>
Details page add blog directory
{# blog/detail.html #} {% block toc %} <div><h3 class="widget-title">Article directory</h3> {{ post.toc | safe }} </div> {% endblock %}
Search by category
Search by label
Search by time
Display blog directories
paging
Django provides a new class to help you manage paging data, which is stored in django/core/paginator.py. It can receive lists, tuples, or other iterative objects.
def index(request): all_posts = Post.objects.count() if all_posts % PER_PAGE != 0: page_nums = all_posts // PER_PAGE + 1 else: page_nums = all_posts // PER_PAGE paginator = Paginator(Post.objects.all(),PER_PAGE) if request.GET.get('page'): page = request.GET.get('page') else: page = 1 try: posts = paginator.page(page) except (PageNotAnInteger,EmptyPage): posts = paginator.page(1) posts.has_previous() posts.has_next() posts.previous_page_number() posts.next_page_number() return render(request, 'blog/index.html', context={ 'title':'Index', 'posts':posts, 'pages_num':page_nums, })
Modify the part of the html file on the home page about paging display
<div class="pager"> {% if posts.has_previous %} <a href="?page={{ posts.previous_page_number }}">Previous page</a> {% else %} <a href="#">Last page</a> {% endif %} <span class="current">The first {{ posts.number }} page / common {{ pages_num }} page</span> {% if posts.has_next %} <a href="?page={{ posts.next_page_number }}">next page</a> {% else %} <a href="#">Next page</a>