博客当中的文章分类以及归档
博客当中侧栏一般都会有分类、标签、日期等,一般博主会根据这些将博客归类,并且点击后,会显示出归类好的文章列表。
需要使用的技术为model中的annotate,相当于mysql中的group by
例:
django中的model
from django.db import models from django.contrib.auth.models import ( BaseUserManager, AbstractBaseUser, AbstractUser ) # class MyUserManager(BaseUserManager): # def create_user(self, email, name, password=None): # """ # Creates and saves a User with the given email, date of # birth and password. # """ # if not email: # raise ValueError('Users must have an email address') # # user = self.model( # email=self.normalize_email(email), # name=name, # ) # # user.set_password(password) # user.save(using=self._db) # return user # # def create_superuser(self, email, name, password): # """ # Creates and saves a superuser with the given email, date of # birth and password. # """ # user = self.create_user( # email, # password=password, # name=name, # ) # user.is_admin = True # user.save(using=self._db) # return user # # # class MyUser(AbstractBaseUser): # email = models.EmailField( # verbose_name='email address', # max_length=255, # unique=True, # ) # # date_of_birth = models.DateField() # name = models.CharField(max_length=32) # is_active = models.BooleanField(default=True) # is_admin = models.BooleanField(default=False) # # objects = MyUserManager() # # USERNAME_FIELD = 'email' # REQUIRED_FIELDS = ['name'] # # def __str__(self): # return self.email # # def has_perm(self, perm, obj=None): # "Does the user have a specific permission?" # # Simplest possible answer: Yes, always # return True # # def has_module_perms(self, app_label): # "Does the user have permissions to view the app `app_label`?" # # Simplest possible answer: Yes, always # return True # # @property # def is_staff(self): # "Is the user a member of staff?" # # Simplest possible answer: All admins are staff # return self.is_admin # class UserInfo(AbstractBaseUser): # # avatar = models.ImageField(upload_to="img") # # class Blog(models.Model): # info = models.CharField() # # class Artical(models.Model): # title = models.CharField(max_length=128) # publish_date = models.DateTimeField() # author = models.ForeignKey(UserInfo, on_delete=models.CASCADE) # content = models.OneToOneField(Blog, on_delete=models.CASCADE) # # class Commments(models.Model): # user = models.ForeignKey(UserInfo, on_delete=models.CASCADE) # c_time = models.DateTimeField() # comments = models.CharField() # artical = models.ForeignKey(Artical, on_delete=models.CASCADE) # reply = models.ForeignKey("Commments", on_delete=models.CASCADE) # # class Tag(models.Model): # tag_name = models.CharField() # artical = models.ManyToManyField(Artical) # # class Category(models.Model): # name = models.CharField(max_length=64) # artical = models.ManyToManyField(Artical) # # class Praise(models.Model): # tag = models.IntegerField() # artical = models.ForeignKey(Artical, on_delete=models.CASCADE) # user = models.ForeignKey(UserInfo, on_delete=models.CASCADE) class UserInfo(AbstractUser): """ 用户信息表 """ nid = models.AutoField(primary_key=True) phone = models.CharField(max_length=11, null=True, unique=True) avatar = models.FileField(upload_to="avatars/", default="avatars/default.png", verbose_name="头像") create_time = models.DateTimeField(auto_now_add=True) blog = models.OneToOneField(to="Blog", to_field="nid", null=True, on_delete=models.CASCADE) def __str__(self): return self.username # class Meta: # verbose_name="用户" # verbose_name_plural=verbose_name class Blog(models.Model): """ 博客信息 """ nid = models.AutoField(primary_key=True) title = models.CharField(max_length=64) # 个人博客标题 site = models.CharField(max_length=32, unique=True) # 个人博客后缀 theme = models.CharField(max_length=32) # 博客主题 def __str__(self): return self.title class Meta: verbose_name="博客信息" verbose_name_plural=verbose_name class Category(models.Model): """ 个人博客文章分类 """ nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32) # 分类标题 blog = models.ForeignKey(to="Blog", to_field="nid", on_delete=models.CASCADE) # 外键关联博客,一个博客站点可以有多个分类 def __str__(self): return self.title class Meta: verbose_name="分类" verbose_name_plural=verbose_name class Tag(models.Model): """ 标签 """ nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32) # 标签名 blog = models.ForeignKey(to="Blog", to_field="nid", on_delete=models.CASCADE) # 所属博客 def __str__(self): return self.title class Meta: verbose_name="标签" verbose_name_plural=verbose_name class Article(models.Model): """ 文章 """ nid = models.AutoField(primary_key=True) title = models.CharField(max_length=50) # 文章标题 desc = models.CharField(max_length=255) # 文章描述 create_time = models.DateTimeField() # 创建时间 category = models.ForeignKey(to="Category", to_field="nid", null=True, on_delete=models.CASCADE) user = models.ForeignKey(to="UserInfo", to_field="nid", on_delete=models.CASCADE) tags = models.ManyToManyField( # 中介模型 to="Tag", through="Article2Tag", through_fields=("article", "tag"), # 注意顺序!!! ) comment_count = models.IntegerField(verbose_name="评论数", default=0) updown = models.IntegerField(verbose_name="点赞数", default=0) def __str__(self): return self.title class Meta: verbose_name="文章" verbose_name_plural=verbose_name class ArticleDetail(models.Model): """ 文章详情表 """ nid = models.AutoField(primary_key=True) content = models.TextField() article = models.OneToOneField(to="Article", to_field="nid", on_delete=models.CASCADE) class Meta: verbose_name="文章内容" verbose_name_plural=verbose_name def __str__(self): return ("{}".format(self.article.title)) class Article2Tag(models.Model): """ 文章和标签的多对多关系表 """ nid = models.AutoField(primary_key=True) article = models.ForeignKey(to="Article", to_field="nid", on_delete=models.CASCADE) tag = models.ForeignKey(to="Tag", to_field="nid", on_delete=models.CASCADE) class Meta: unique_together = (("article", "tag"),) verbose_name="文章-标签" verbose_name_plural=verbose_name # 给返回对象赋值,否则前端看见的均为"Article2Tag object(n)" def __str__(self): return "{}-{}".format(self.article.title, self.tag.title) class ArticleUpDown(models.Model): """ 点赞表 """ nid = models.AutoField(primary_key=True) user = models.ForeignKey(to="UserInfo", null=True, on_delete=models.CASCADE) article = models.ForeignKey(to="Article", null=True, on_delete=models.CASCADE) is_up = models.BooleanField(default=True) class Meta: unique_together = (("article", "user"),) verbose_name="点赞" verbose_name_plural=verbose_name class Comment(models.Model): """ 评论表 """ nid = models.AutoField(primary_key=True) article = models.ForeignKey(to="Article", to_field="nid", on_delete=models.CASCADE) user = models.ForeignKey(to="UserInfo", to_field="nid", on_delete=models.CASCADE) content = models.CharField(max_length=255) # 评论内容 create_time = models.DateTimeField(auto_now_add=True) parent_comment = models.ForeignKey("self", null=True, blank=True, on_delete=models.CASCADE) def __str__(self): return self.content class Meta: verbose_name="评论" verbose_name_plural=verbose_name
路由设置:
project下的路由
"""Hero URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/2.1/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path, re_path, include from jax import views from django.views.static import serve from django.conf import settings from jax import urls as jax_urls urlpatterns = [ path('admin/', admin.site.urls), path('backend/', views.backend), re_path('artical-(?P<artical_type_id>\d+)-(?P<category_id>\d+).html', views.artical), path('login/', views.login), path('logout/', views.logout), path('index/', views.index), path('register/', views.register), path('reg/', views.reg), path('check_code.html', views.check_code), path('check_username_exist/', views.check_username_exist), path('blog/', include(jax_urls)), # media相关的路由设置 re_path(r'^media/(?P<path>.*)$', serve, {"document_root": settings.MEDIA_ROOT}), ]
app下的路由
from jax import views from django.urls import path, re_path urlpatterns = [ re_path('(?P<username>\w+)/p/(?P<pk>\d+).html', views.artical_detail), #文章筛选,传递的参数为用户名、筛选条件(category、tag)、筛选条件的id(cta=category、tag) re_path('(?P<username>\w+)/(?P<screening>\w+)/(?P<screening_cta_id>\w+).html', views.artical_screening), # 文章筛选,筛选出指定月份的文章,\d{4}代表匹配4个数字,\d{2}代表匹配2个数字 re_path('(?P<username>\w+)/(?P<screening>\w+)/(?P<screening_cta_id>\d{4}-\d{2}).html', views.artical_screening), re_path('(\w+)', views.home), ]
显示博客当中所有用户的文章列表:
一般博客的前端分配比例为左侧略少,显示分类,右侧偏宽,显示文章列表或者文章内容,这里选用bootstrap当中的"col-md-n",页面分为12列,左侧col-md-3,右侧col-md-9,放在div.container和div.row中。"font-awesome"作为评论或者赞的图标。
def index(request): # print(request.user.username) artical_list = models.Article.objects.all() username = "" return render(request, "index.html", { "artical_list": artical_list, })
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/css/backend.css"> <link rel="stylesheet" href="/static/font-awesome-4.7.0/css/font-awesome.css"> </head> <body> <nav class="navbar navbar-default"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="/index/">博客</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li> <li><a href="#">Link</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> <li role="separator" class="divider"></li> <li><a href="#">One more separated link</a></li> </ul> </li> </ul> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> <ul class="nav navbar-nav navbar-right"> {% if request.user.username %} <li><a href="#">{{ request.user.username }}</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">个人中心<span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="/logout/">注销</a></li> </ul> </li> {% else %} <li><a href="/login/">登陆</a></li> <li><a href="/register/">注册</a></li> {% endif %} </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div class="container"> <div class="row"> <div class="col-md-3"> <div class="panel panel-primary"> <div class="panel-heading"> 文章分类 </div> <div class="panel-body"> {% for category in category_list %} <p><a href="#">{{ category.title }}({{ category.c }})</a></p> {% endfor %} </div> </div> <div class="panel panel-info"> <div class="panel-heading"> 文章标签 </div> <div class="panel-body"> {% for tag in tag_list %} <p><a href="#">{{ tag.title }}({{ tag.c }})</a></p> {% endfor %} </div> </div> <div class="panel panel-warning"> <div class="panel-heading"> 文章日期 </div> <div class="panel-body"> {% for archive in archive_list %} <p><a href="#">{{ archive.archive_ym }}({{ archive.c }})</a></p> {% endfor %} </div> </div> </div> <div class="col-md-9"> {% for artical in artical_list %} <div> <h3><a href="/blog/{{ artical.user.username }}/p/{{ artical.pk }}.html">{{ artical }}</a></h3> <div class="media"> <div class="media-left"> <a href="#"> <img class="media-object avatars-img" src="/media/{{ artical.user.avatar }}" alt="..."> </a> </div> <div class="media-body"> {{ artical.desc }} </div> <div style="float: right;"> <div class="artical-footer"> <span><a href="/blog/{{ artical.user }}">{{ artical.user }}</a> </span>发布于 <span>{{ artical.create_time|date:'Y-m-d H:i:s' }}</span> {# <span class="glyphicon glyphicon-comment"><a href="#">评论({{ artical.comment_count }})</a></span>#} {# <span class="glyphicon glyphicon-thumbs-up"><a href="#">点赞({{ artical.updown }})</a> </span>#} <span><i class="fa fa-comment-o" aria-hidden="true"><a href="#">评论({{ artical.comment_count }})</a></i></span> <span><i class="fa fa-thumbs-o-up" aria-hidden="true"><a href="#">点赞({{ artical.updown }})</a></i></span> <span>{{ artical.category }}</span> </div> </div> </div> </div> {% endfor %} </div> </div> </div> <script type="application/javascript" src="/static/bootstrap-3.3.7-dist/js/jquery-1.12.4.js"></script> <script type="application/javascript" src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script> </body> </html>
设计思路:
每个博客下面都显示着文章的作者,当点击文章标题要显示文章内容,点击作者要显示作者的所有文章,并且点击后,页面左侧都会将作者的所有分类、归档的文章数量显示在左侧标题栏。不过,这里首先要把作者的所有博客全都给分组。
这里使用annotate分组
def get_left_menu(username):
user = models.UserInfo.objects.filter(username=username).first()
blog = user.blog # 每一个user都有一个blog名称,相当于博客园当中自己起的名字,每个blog.title下面都有自己的分组和tag
from django.db.models import Count
# 将文章按照分组分类,并且统计出个数
category_list = models.Category.objects.filter(blog=blog).annotate(c=Count("article")).values("title", "c", "nid")
# category_list2 = models.Category.objects.filter(blog=blog).annotate(c=Count("article"))
# print(category_list2.values())
# 将所有文章按照标签分类,并统计个数
tag_list = models.Tag.objects.filter(blog=blog).annotate(c=Count("article")).values("title", "c", "nid")
# 将所有文章按照日期归档,sqlite数据书需要使用strftime('%Y-%m-%d %H:%M:%S', 'now')函数,mysql函数需要使用date_format('now', '%Y-%m-%d %H:%M:%S')函数
archive_list = models.Article.objects.filter(user=user).extra(
select={"archive_ym": "strftime('%%Y-%%m', create_time)"}
).values("archive_ym").annotate(c=Count("nid")).values("archive_ym", "c")
return {
"category_list": category_list,
"tag_list": tag_list,
"archive_list": archive_list,
"username": username,
}
from jax import models
from django import template
register = template.Library()
@register.inclusion_tag("blog_left_menu.html")
def get_left_menu(username):
user = models.UserInfo.objects.filter(username=username).first()
blog = user.blog # 每一个user都有一个blog名称,相当于博客园当中自己起的名字,每个blog.title下面都有自己的分组和tag
from django.db.models import Count
# 将文章按照分组分类,并且统计出个数
category_list = models.Category.objects.filter(blog=blog).annotate(c=Count("article")).values("title", "c", "nid")
# category_list2 = models.Category.objects.filter(blog=blog).annotate(c=Count("article"))
# print(category_list2.values())
# 将所有文章按照标签分类,并统计个数
tag_list = models.Tag.objects.filter(blog=blog).annotate(c=Count("article")).values("title", "c", "nid")
# 将所有文章按照日期归档,sqlite数据书需要使用strftime('%Y-%m-%d %H:%M:%S', 'now')函数,mysql函数需要使用date_format('now', '%Y-%m-%d %H:%M:%S')函数
# extra参数是额外执行sql命令,这里相当于给对象新添加了一个字段"archive_ym",每一行中该字段由strftime('%%Y-%%m', create_time)"赋值
archive_list = models.Article.objects.filter(user=user).extra(
select={"archive_ym": "strftime('%%Y-%%m', create_time)"}
).values("archive_ym").annotate(c=Count("nid")).values("archive_ym", "c")
return {
"category_list": category_list,
"tag_list": tag_list,
"archive_list": archive_list,
"username": username,
}
# annotate前面是什么,就按照什么分组,至于annotate里面定义的变量,名字自起,这里为c,后面需要使用Count或Avg这种参数来对括号里面的变量求值,里面的值可以是一个其他的表,也可以是本身自己表的字段之一,取得的统计值会作为一个{"key": "value"}封装到对象当中,可以通过values参数来获取值
由于左侧导航栏的样式不变,可以将该内容单独拿出作为一个模板,同时为了前端页面的整洁,可以将获取左侧导航栏内容和方法的方法添加到app/templatetags目录当中。创建一个基础模板,将博客左侧的内容和右侧的内容单独拿出,将他们作为一个block来修改。
from jax import models from django import template register = template.Library() @register.inclusion_tag("blog_left_menu.html") def get_left_menu(username): user = models.UserInfo.objects.filter(username=username).first() blog = user.blog # 每一个user都有一个blog名称,相当于博客园当中自己起的名字,每个blog.title下面都有自己的分组和tag from django.db.models import Count # 将文章按照分组分类,并且统计出个数 category_list = models.Category.objects.filter(blog=blog).annotate(c=Count("article")).values("title", "c", "nid") # category_list2 = models.Category.objects.filter(blog=blog).annotate(c=Count("article")) # print(category_list2.values()) # 将所有文章按照标签分类,并统计个数 tag_list = models.Tag.objects.filter(blog=blog).annotate(c=Count("article")).values("title", "c", "nid") # 将所有文章按照日期归档,sqlite数据书需要使用strftime('%Y-%m-%d %H:%M:%S', 'now')函数,mysql函数需要使用date_format('now', '%Y-%m-%d %H:%M:%S')函数 # extra参数是额外执行sql命令,这里相当于给对象新添加了一个字段"archive_ym",每一行中该字段由strftime('%%Y-%%m', create_time)"赋值 archive_list = models.Article.objects.filter(user=user).extra( select={"archive_ym": "strftime('%%Y-%%m', create_time)"} ).values("archive_ym").annotate(c=Count("nid")).values("archive_ym", "c") return { "category_list": category_list, "tag_list": tag_list, "archive_list": archive_list, "username": username, } # annotate前面是什么,就按照什么分组,至于annotate里面定义的变量,名字自起,这里为c,后面需要使用Count或Avg这种参数来对括号里面的变量求值,里面的值可以是一个其他的表,也可以是本身自己表的字段之一,取得的统计值会作为一个{"key": "value"}封装到对象当中,可以通过values参数来获取值
<div class="panel panel-primary"> <div class="panel-heading"> 文章分类 </div> <div class="panel-body"> {% for category in category_list %} <p><a href="/blog/{{ username }}/category/{{ category.nid}}.html">{{ category.title }}({{ category.c }})</a></p> {% endfor %} </div> </div> <div class="panel panel-info"> <div class="panel-heading"> 文章标签 </div> <div class="panel-body"> {% for tag in tag_list %} <p><a href="/blog/{{ username }}/tag/{{ tag.nid }}.html">{{ tag.title }}({{ tag.c }})</a></p> {% endfor %} </div> </div> <div class="panel panel-warning"> <div class="panel-heading"> 文章日期 </div> <div class="panel-body"> {% for archive in archive_list %} <p><a href="/blog/{{ username }}/archive/{{ archive.archive_ym }}.html">{{ archive.archive_ym }}({{ archive.c }})</a></p> {% endfor %} </div> </div>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/css/backend.css"> <link rel="stylesheet" href="/static/font-awesome-4.7.0/css/font-awesome.css"> </head> <body> <nav class="navbar navbar-default"> <div class="container-fluid"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="/index/">博客</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li> <li><a href="#">Link</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> <li role="separator" class="divider"></li> <li><a href="#">One more separated link</a></li> </ul> </li> </ul> <form class="navbar-form navbar-left"> <div class="form-group"> <input type="text" class="form-control" placeholder="Search"> </div> <button type="submit" class="btn btn-default">Submit</button> </form> <ul class="nav navbar-nav navbar-right"> {% if request.user.username %} <li><a href="#">{{ request.user.username }}</a></li> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">个人中心<span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="/logout/">注销</a></li> </ul> </li> {% else %} <li><a href="/login/">登陆</a></li> <li><a href="/register/">注册</a></li> {% endif %} </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div class="container"> <div class="row"> <div class="col-md-3"> {% load blog_left_menu %} <!--导入templatetags目录当中的文件--> {% get_left_menu username %} <!--引用所倒入文件blog_left_menu.py中的get_left_menu方法,并且提供username作为参数}--> </div> <div class="col-md-9"> {% block page_main %} {% endblock %} </div> </div> </div> <script type="application/javascript" src="/static/bootstrap-3.3.7-dist/js/jquery-1.12.4.js"></script> <script type="application/javascript" src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script> </body> </html>
然后创建一个能够extends base.html板的页面,对博客右侧的内容同过block做渲染。
{% extends "base.html" %} {% block page_main %} {% for artical in artical_list %} <div> <h3><a href="/blog/{{ artical.user.username }}/p/{{ artical.pk }}.html">{{ artical }}</a></h3> <div class="media"> <div class="media-left"> <a href="#"> <img class="media-object avatars-img" src="/media/{{ artical.user.avatar }}" alt="..."> </a> </div> <div class="media-body"> {{ artical.desc }} </div> <div style="float: right;"> <div class="artical-footer"> <span><a href="/blog/{{ artical.user }}">{{ artical.user }}</a> </span>发布于 <span>{{ artical.create_time|date:'Y-m-d H:i:s' }}</span> {# <span class="glyphicon glyphicon-comment"><a href="#">评论({{ artical.comment_count }})</a></span>#} {# <span class="glyphicon glyphicon-thumbs-up"><a href="#">点赞({{ artical.updown }})</a> </span>#} <span><i class="fa fa-comment-o" aria-hidden="true"><a href="#">评论({{ artical.comment_count }})</a></i></span> <span><i class="fa fa-thumbs-o-up" aria-hidden="true"><a href="#">点赞({{ artical.updown }})</a></i></span> <span>{{ artical.category }}</span> </div> </div> </div> </div> {% endfor %} {% endblock %}
显示文章的路由: re_path('(?P<username>\w+)/p/(?P<pk>\d+).html', views.artical_detail),
以上内容做完后,在博客首页点击博客title会显示博客所有的内容,点击用户名,会显示该用户的博客列表,并且博客页面左侧会显示分类。这里需要思考前端分类变迁中href的路由以及后台urls.py路由如何匹配:
#文章筛选,传递的参数为用户名、筛选条件(category、tag)、筛选条件的id(cta=category、tag) re_path('(?P<username>\w+)/(?P<screening>\w+)/(?P<screening_cta_id>\w+).html', views.artical_screening), # 文章筛选,筛选出指定月份的文章,\d{4}代表匹配4个数字,\d{2}代表匹配2个数字 re_path('(?P<username>\w+)/(?P<screening>\w+)/(?P<screening_cta_id>\d{4}-\d{2}).html', views.artical_screening), re_path('(\w+)', views.home),
def artical_screening(request, username, screening, screening_cta_id): user = models.UserInfo.objects.filter(username=username).first() if screening == "category": # 如果用户点击的是catgory # category_list1 = models.Article.objects.filter(user=user) c = models.Category.objects.filter(nid=screening_cta_id).first() artical_list = models.Article.objects.filter(user=user, category=c) if screening == "tag": # 如果用户点击的是tag t = models.Tag.objects.filter(nid=screening_cta_id).first() artical_list = models.Article.objects.filter(user=user, tags=t) if screening == "archive": # 如果用户点击的是archive # 将url传递过来的日期分割,切割条件为"-" create_time = screening_cta_id.split("-") artical_list = models.Article.objects.filter(user=user, create_time__year=create_time[0], create_time__month=create_time[1]) return render(request, "home.html", { "artical_list": artical_list, "username": username, })