博客当中的文章分类以及归档

博客当中侧栏一般都会有分类、标签、日期等,一般博主会根据这些将博客归类,并且点击后,会显示出归类好的文章列表。

需要使用的技术为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
models.py

路由设置:

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}),
]
urls.py

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),
]
urls.py

显示博客当中所有用户的文章列表:

一般博客的前端分配比例为左侧略少,显示分类,右侧偏宽,显示文章列表或者文章内容,这里选用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,
    })
View Code
<!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>
index.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,
    }
View Code
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参数来获取值
get_left_menu.html

由于左侧导航栏的样式不变,可以将该内容单独拿出作为一个模板,同时为了前端页面的整洁,可以将获取左侧导航栏内容和方法的方法添加到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参数来获取值
blog_left_menu.py
<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>
blog_left_menu.html
<!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>
base.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 %}
home.html

 

显示文章的路由:
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),
urls.py
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,
    })
views.py

 

转载于:https://www.cnblogs.com/ttyypjt/p/10650778.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值