当前位置 : 主页 > 编程语言 > python >

Django之博客系统

来源:互联网 收集:自由互联 发布时间:2022-06-15
项目流程: 1、搞清楚需求 基于用户认证组件auth和Ajax实现登录验证(图片验证码) 基于forms组件和Ajax实现注册功能 设计博客系统首页(文章列表渲染) 设计个人站点页面 文章详情页

项目流程:

1、搞清楚需求

  • 基于用户认证组件auth和Ajax实现登录验证(图片验证码)
  • 基于forms组件和Ajax实现注册功能
  • 设计博客系统首页(文章列表渲染)
  • 设计个人站点页面
  • 文章详情页
  • 实现文章点赞功能
  • 实现文章的评论
  • 文章的评论
  • 评论的子评论
  • 富文本编辑框以及xss攻击
  • 2、设计表结构

    Django之博客系统_htmlDjango之博客系统_python_02

    from django.contrib.auth.models import User,AbstractUser

    class UserInfo(AbstractUser):
    """
    用户信息
    """
    nid = models.AutoField(primary_key=True)
    telephone = models.CharField(max_length=11, null=True, unique=True)
    avatar = models.FileField(upload_to='avatars/', default="/avatars/default.png")
    create_time = models.DateTimeField(verbose_name='创建时间', 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 Blog(models.Model):

    """
    博客信息表(站点表)
    """
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='个人博客标题', max_length=64)
    site_name = models.CharField(verbose_name='站点名称', max_length=64)
    theme = models.CharField(verbose_name='博客主题', max_length=32)

    def __str__(self):
    return self.title


    class Category(models.Model):
    """
    博主个人文章分类表
    """
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='分类标题', max_length=32)
    blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid',on_delete=models.CASCADE)

    def __str__(self):
    return self.title


    class Tag(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name='标签名称', max_length=32)
    blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid',on_delete=models.CASCADE)

    def __str__(self):
    return self.title


    class Article(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=50, verbose_name='文章标题')
    desc = models.CharField(max_length=255, verbose_name='文章描述')
    create_time = models.DateTimeField(verbose_name='创建时间',auto_now_add=True)
    content = models.TextField()

    comment_count=models.IntegerField(default=0)
    up_count=models.IntegerField(default=0)
    down_count=models.IntegerField(default=0)

    user = models.ForeignKey(verbose_name='作者', to='UserInfo', to_field='nid',on_delete=models.CASCADE)
    category = models.ForeignKey(to='Category', to_field='nid', null=True,on_delete=models.CASCADE)
    tags = models.ManyToManyField(
    to="Tag",
    through='Article2Tag',
    through_fields=('article', 'tag'),
    )



    def __str__(self):
    return self.title


    class Article2Tag(models.Model):
    nid = models.AutoField(primary_key=True)
    article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid',on_delete=models.CASCADE)
    tag = models.ForeignKey(verbose_name='标签', to="Tag", to_field='nid',on_delete=models.CASCADE)

    class Meta:
    unique_together = [
    ('article', 'tag'),
    ]

    def __str__(self):
    v = self.article.title + "---" + self.tag.title
    return v


    class ArticleUpDown(models.Model):
    """
    点赞表
    """

    nid = models.AutoField(primary_key=True)
    user = models.ForeignKey('UserInfo', null=True,on_delete=models.CASCADE)
    article = models.ForeignKey("Article", null=True,on_delete=models.CASCADE)
    is_up = models.BooleanField(default=True)

    class Meta:
    unique_together = [
    ('article', 'user'),
    ]


    class Comment(models.Model):
    """

    评论表

    """
    nid = models.AutoField(primary_key=True)
    user = models.ForeignKey(verbose_name='评论者', to='UserInfo', to_field='nid',on_delete=models.CASCADE)
    article = models.ForeignKey(verbose_name='评论文章', to='Article', to_field='nid',on_delete=models.CASCADE)
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    content = models.CharField(verbose_name='评论内容', max_length=255)


    parent_comment=models.ForeignKey("self",null=True,on_delete=models.CASCADE)


    def __str__(self):
    return self.content



    根评论:对文章的评论

    子评论:对评论的评论


    111
    444
    555
    222
    333


    Comment

    nid user_id article_id content parent_comment_id(null=True)
    1 1 1 111 null
    2 2 1 222 null
    3 3 1 333 null
    4 4 1 444 1
    5 5 1 555 4

    models.py

    3、按照每一个功能分别进行开发

    Myforms.py

    Django之博客系统_htmlDjango之博客系统_python_02

    # -*- coding:utf-8 -*-
    # Author : yuchao
    # Data : 2018/7/12 09:19


    from django import forms
    from django.forms import widgets
    from blog.models import UserInfo
    from django.core.exceptions import NON_FIELD_ERRORS, ValidationError


    # widgets属性是django对html输入元素的表示,负责渲染html和提取get/post的字典数据

    class UserForm(forms.Form):
    user = forms.CharField(max_length=32,
    error_messages={"required": "该字段不能为空"},
    label="用户名",
    # 渲染后,widget将设置属性attrs={"class": "form-control"}
    widget=widgets.TextInput(attrs={"class": "form-control"}, )
    )
    pwd = forms.CharField(
    max_length=32,
    label="密码",
    widget=widgets.PasswordInput(attrs={"class": "form-control"}, ))

    re_pwd = forms.CharField(max_length=32,
    label='确认密码',
    widget=widgets.PasswordInput(attrs={"class": "form-control"}, ))

    email = forms.EmailField(max_length=32,
    label="邮箱",
    widget=widgets.EmailInput(attrs={"class": "form-control"}, ))

    def clean_user(self):
    # clean_data是提交成功后的字典数据
    val = self.cleaned_data.get("user")
    user = UserInfo.objects.filter(username=val).first()
    if not user:
    return val
    else:
    raise ValidationError("该用户已注册") # 描述错误的信息

    def clean(self):
    pwd = self.cleaned_data.get("pwd")
    re_pwd = self.cleaned_data.get("re_pwd")
    # 判断两次密码都存在,且密码确认正常,返回数据
    if pwd and re_pwd:
    if pwd == re_pwd:
    return self.cleaned_data
    else:
    raise ValidationError("两次密码不一致") # 可以传入元祖数据,定义错误信息,错误代码,传递给错误信息的参数
    else:
    return self.cleaned_data

    自定义form

    models.py

    Django之博客系统_htmlDjango之博客系统_python_02

    from django.db import models

    from django.contrib.auth.models import AbstractUser


    # verbose_name 给类模型,起一个可读的名字

    class UserInfo(AbstractUser):
    """
    用户信息
    """
    nid = models.AutoField(primary_key=True)
    telephone = models.CharField(max_length=11, null=True, unique=True) # 电话
    avatar = models.FileField(upload_to='avatars/', default='avatars/default.png') # 默认头像
    # 创建时间,auto_now_add作用是无法修改时间
    create_time = models.DateTimeField(verbose_name="创建时间", auto_now_add=True)
    blog = models.OneToOneField(to="Blog", to_field='nid', null=True, on_delete=models.CASCADE)

    # UserInfo对象的返回结果,以用户名显示
    def __str__(self):
    return self.username


    # 用户和博客,一对一
    class Blog(models.Model):
    """
    博客信息
    """
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name="个人博客标题", max_length=64)
    site_name = models.CharField(verbose_name="站点名称", max_length=64)
    theme = models.CharField(verbose_name="博客主题", max_length=32)

    def __str__(self):
    return self.title


    # 博客分类
    class Category(models.Model):
    """
    博主个人文章分类表
    """
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name="分类标题", max_length=32)
    #关联博客表,一个博客可以有多个分类
    blog = models.ForeignKey(verbose_name="所属博客", to='Blog',to_field='nid',on_delete=models.CASCADE)

    def __str__(self):
    return self.title


    # 标签分类
    # 一个blog对应多个tag
    class Tag(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(verbose_name="标签名称", max_length=32)
    blog = models.ForeignKey(verbose_name="所属博客", to="Blog", to_field='nid', on_delete=models.CASCADE)

    # tag对象返回tag名字
    def __str__(self):
    return self.title


    # 文章
    class Article(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=50, verbose_name="文章标题")
    desc = models.CharField(max_length=255, verbose_name="文章描述")
    create_time = models.DateTimeField(verbose_name="创建时间", auto_now_add=True)
    content = models.TextField() # 文章内容

    comment_count = models.IntegerField(default=0) # 评论数
    up_count = models.IntegerField(default=0) # 点赞数
    down_count = models.IntegerField(default=0) # 点踩数
    # 一对多,一个作者可以有多个文章,外键放在'多'的表里
    user = models.ForeignKey(verbose_name="作者", to="UserInfo", to_field="nid", on_delete=models.CASCADE)
    # 一对多,一个分类可以有多个文章,
    category = models.ForeignKey(to="Category", to_field="nid", null=True, on_delete=models.CASCADE)
    # 一个文章可以有多个标签,一个标签可以有多个文章,多对多

    '''
    manytomanyfield字段会自动生成第三张表
    使用through参数,找到自己编写的class,创建第三张表模型,方便扩展字段
    '''
    tags = models.ManyToManyField(
    to="Tag",
    through="Article2Tag",
    through_fields=("article", "tag"),
    )

    def __str__(self):
    return self.title


    # 文章多对多关联标签表
    class Article2Tag(models.Model):
    nid = models.AutoField(primary_key=True)
    article = models.ForeignKey(verbose_name="文章", to="Article", to_field="nid", on_delete=models.CASCADE)
    tag = models.ForeignKey(verbose_name="标签", to="Tag", to_field="nid", on_delete=models.CASCADE)

    class Meta:
    unique_together = [
    ('article', 'tag'),
    ]

    def __str__(self):
    v = self.article.title + "---" + self.tag.title
    return v


    class ArticleUpDown(models.Model):
    '''
    点赞表
    哪个用户对哪张表,进行点赞,还是踩灭
    '''
    nid = models.AutoField(primary_key=True)
    # 哪个用户操作的,关联用户表
    user = models.ForeignKey("UserInfo", null=True, on_delete=models.CASCADE)
    # 对哪个文章操作的,关联文章表
    article = models.ForeignKey("Article", null=True, on_delete=models.CASCADE)
    is_up = models.BooleanField(default=True)

    class Meta:
    # 通过两个字段保持唯一性,文章和用户的组合必须唯一
    unique_together = [
    ('article', 'user'),
    ]


    # 评论
    class Comment(models.Model):
    '''
    评论表
    '''
    nid = models.AutoField(primary_key=True)
    # 关联用户表,一个用户可以有多条评论
    user = models.ForeignKey(verbose_name="评论者", to="UserInfo", to_field="nid", on_delete=models.CASCADE)

    # 关联文章表,一个文章能有多个文章
    article = models.ForeignKey(verbose_name="评论文章", to="Article", to_field='nid', on_delete=models.CASCADE)

    create_time = models.DateTimeField(verbose_name="创建时间", auto_now_add=True)
    # 内容
    content = models.CharField(verbose_name="评论内容", max_length=255)

    # 父评论,自关联写法,关联comment,可以写 self
    parent_comment = models.ForeignKey('self', null=True,on_delete=models.CASCADE)

    def __str__(self):
    return self.content

    '''
    根评论:对文章的评论
    子评论:对评论的评论
    ---------
    如此结构,无法存储子评论
    comment表
    nid user_id article_id create_time content 这里应该有个parent_comment父评论(自关联)
    1 1 1 xx 11111
    2 2 1 xx 2222
    3 3 1 xx 33333
    '''

    自定义models.py

    settings.py

    Django之博客系统_htmlDjango之博客系统_python_02

    """
    Django settings for project.

    Generated by 'django-admin startproject' using Django 2.0.1.

    For more information on this file, see
    https://docs.djangoproject.com/en/2.0/topics/settings/

    For the full list of settings and their values, see
    https://docs.djangoproject.com/en/2.0/ref/settings/
    """

    import os

    # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


    # Quick-start development settings - unsuitable for production
    # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/

    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY = 'eclvh_i(m99c*)$)j$5+pgpjhuv!4lc#z9t3j00d)x3c&*js)x'

    # SECURITY WARNING: don't run with debug turned on in production!
    DEBUG = True

    ALLOWED_HOSTS = []


    # Application definition

    INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    "blog",
    ]

    MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]

    ROOT_URLCONF = '.urls'

    TEMPLATES = [
    {
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [os.path.join(BASE_DIR, 'templates')]
    ,
    'APP_DIRS': True,
    'OPTIONS': {
    'context_processors': [
    'django.template.context_processors.debug',
    'django.template.context_processors.request',
    'django.contrib.auth.context_processors.auth',
    'django.contrib.messages.context_processors.messages',
    ],
    },
    },
    ]

    WSGI_APPLICATION = '.wsgi.application'


    # Database
    # https://docs.djangoproject.com/en/2.0/ref/settings/#databases

    # DATABASES = {
    # 'default': {
    # 'ENGINE': 'django.db.backends.sqlite3',
    # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    # }
    # }



    DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME':'', # 要连接的数据库,连接前需要创建好
    'USER':'root',# 连接数据库的用户名
    'PASSWORD':'',# 连接数据库的密码
    'HOST':'127.0.0.1', # 连接主机,默认本级
    'PORT':3306 # 端口 默认3306
    }
    }

    # Password validation
    # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators

    AUTH_PASSWORD_VALIDATORS = [
    {
    'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
    'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
    'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
    'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
    ]

    '''这里不写这个,
    模板继承AbstractUser报错:
    auth.User.groups: (fields.E304)
    '''
    AUTH_USER_MODEL="blog.UserInfo"

    # Internationalization
    # https://docs.djangoproject.com/en/2.0/topics/i18n/

    LANGUAGE_CODE = 'en-us'

    TIME_ZONE = 'Asia/Shanghai'

    USE_I18N = True

    USE_L10N = True

    USE_TZ = False


    # Static files (CSS, JavaScript, Images)
    # https://docs.djangoproject.com/en/2.0/howto/static-files/

    STATIC_URL = '/static/'

    STATICFILES_DIRS=[
    os.path.join(BASE_DIR,"static"),
    ]


    # 与用户上传相关的配置
    MEDIA_ROOT=os.path.join(BASE_DIR,"media")
    MEDIA_URL="/media/"








    LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
    'console':{
    'level':'DEBUG',
    'class':'logging.StreamHandler',
    },
    },
    'loggers': {
    'django.db.backends': {
    'handlers': ['console'],
    'propagate': True,
    'level':'DEBUG',
    },
    }
    }








    EMAIL_HOST = 'smtp.exmail.qq.com' # 如果是 163 改成 smtp.163.com
    EMAIL_PORT = 465
    EMAIL_HOST_USER = '' # 帐号
    EMAIL_HOST_PASSWORD = '' # 密码
    # DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
    EMAIL_USE_SSL = True




    LOGIN_URL="/login/"

    django配置文件

    urls.py

    Django之博客系统_htmlDjango之博客系统_python_02

    """ URL Configuration

    The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.0/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

    from django.views.static import serve
    from blog import views
    from import settings
    from django.urls import include


    urlpatterns = [

    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('index/', views.index),
    path('logout/', views.logout),
    re_path('^$', views.index),
    path('get_validCode_img/', views.get_valid_code_img),
    path('register/', views.register),

    # 文本编辑器上传图片url
    path('upload/', views.upload),

    # 后台管理url
    re_path("cn_backend/$",views.cn_backend),
    re_path("cn_backend/add_article/$",views.add_article),

    # 点赞
    path("digg/",views.digg),
    # 评论
    path("comment/",views.comment),
    # 获取评论树相关数据
    path("get_comment_tree/",views.get_comment_tree),


    # media配置:
    re_path(r"media/(?P<path>.*)$",serve,{"document_root":settings.MEDIA_ROOT}),

    re_path('^(?P<username>\w+)/articles/(?P<article_id>\d+)$', views.article_detail), # article_detail(request,username="yuan","article_id":article_id)

    # 个人站点的跳转

    re_path('^(?P<username>\w+)/(?P<condition>tag|category|archive)/(?P<param>.*)/$', views.home_site), # home_site(reqeust,username="yuan",condition="tag",param="python")

    # 个人站点url
    re_path('^(?P<username>\w+)/$', views.home_site), # home_site(reqeust,username="yuan")


    ]

    路由控制器

    模板文件配置

    templates文件夹

    Django之博客系统_htmlDjango之博客系统_python_02

    {% extends "base.html" %}


    {% block content %}
    {% csrf_token %}
    <div class="article_info">
    <h3 class="text-center title">{{ article_obj.title }}</h3>
    <div class="cont">
    {{ article_obj.content|safe }}
    </div>

    <div class="clearfix">
    <div id="div_digg">
    <div class="diggit action">
    <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
    </div>
    <div class="buryit action">
    <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
    </div>
    <div class="clear"></div>
    <div class="diggword" id="digg_tips" style="color: red;"></div>
    </div>
    </div>

    <div class="comments list-group">
    <p class="tree_btn">评论树</p>
    <div class="comment_tree">


    </div>

    <script>

    $.ajax({
    url: "/get_comment_tree/",
    type: "get",
    data: {
    article_id: "{{ article_obj.pk }}"
    },
    success: function (comment_list) {
    console.log(comment_list);

    $.each(comment_list, function (index, comment_object) {

    var pk = comment_object.pk;
    var content = comment_object.content;
    var parent_comment_id = comment_object.parent_comment_id;
    var s = '<div class="comment_item" comment_id=' + pk + '><span>' + content + '</span></div>';

    if (!parent_comment_id) {

    $(".comment_tree").append(s);
    } else {

    $("[comment_id=" + parent_comment_id + "]").append(s);

    }

    })


    }
    })

    </script>


    <p>评论列表</p>

    <ul class="list-group comment_list">

    {% for comment in comment_list %}
    <li class="list-group-item">
    <div>
    <a href=""># {{ forloop.counter }}楼</a> &nbsp;&nbsp;
    <span>{{ comment.create_time|date:"Y-m-d H:i" }}</span>&nbsp;&nbsp;
    <a href=""><span>{{ comment.user.username }}</span></a>
    <a class="pull-right reply_btn" username="{{ comment.user.username }}"
    comment_pk="{{ comment.pk }}">回复</a>
    </div>

    {% if comment.parent_comment_id %}
    <div class="pid_info well">
    <p>
    {{ comment.parent_comment.user.username }}: {{ comment.parent_comment.content }}
    </p>
    </div>
    {% endif %}

    <div class="comment_con">
    <p>{{ comment.content }}</p>
    </div>

    </li>
    {% endfor %}


    </ul>

    <p>发表评论</p>
    <p>昵称:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
    value="{{ request.user.username }}">
    </p>
    <p>评论内容:</p>
    <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
    <p>
    <button class="btn btn-default comment_btn">提交评论</button>
    </p>
    </div>
    <script>
    // 点赞请求
    $("#div_digg .action").click(function () {
    var is_up = $(this).hasClass("diggit");


    $obj = $(this).children("span");

    $.ajax({
    url: "/digg/",
    type: "post",
    data: {
    "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
    "is_up": is_up,
    "article_id": "{{ article_obj.pk }}",
    },
    success: function (data) {
    console.log(data);

    if (data.state) {
    var val = parseInt($obj.text());
    $obj.text(val + 1);
    }
    else {
    var val = data.handled ? "您已经推荐过!" : "您已经反对过!";
    $("#digg_tips").html(val);

    setTimeout(function () {
    $("#digg_tips").html("")
    }, 1000)

    }

    }
    })

    })

    // 评论请求
    var pid = "";

    $(".comment_btn").click(function () {

    var content = $("#comment_content").val();

    if (pid) {
    var index = content.indexOf("\n");
    content = content.slice(index + 1)
    }


    $.ajax({
    url: "/comment/",
    type: "post",
    data: {
    "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
    "article_id": "{{ article_obj.pk }}",
    "content": content,
    pid: pid
    },
    success: function (data) {

    console.log(data);

    var create_time = data.create_time;
    var username = data.username;
    var content = data.content;

    var s = `
    <li class="list-group-item">
    <div>

    <span>${create_time}</span>&nbsp;&nbsp;
    <a href=""><span>${username}</span></a>

    </div>
    <div class="comment_con">
    <p>${content}</p>
    </div>

    </li>`;

    $("ul.comment_list").append(s);

    // 清空评论框
    pid = "",
    $("#comment_content").val("");

    }
    })


    });

    // 回复按钮事件

    $(".reply_btn").click(function () {

    $('#comment_content').focus();
    var val = "@" + $(this).attr("username") + "\n";
    $('#comment_content').val(val);


    pid = $(this).attr("comment_pk");


    })
    </script>

    </div>
    {% endblock %}

    article_detail.html

    Django之博客系统_htmlDjango之博客系统_python_02

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>

    <link rel="stylesheet" href="/static/blog/css/home_site.css">
    <link rel="stylesheet" href="/static/theme/{{ blog.theme }}">
    <link rel="stylesheet" href="/static/blog/css/article_detail.css">
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <script src="/static/js/jquery-3.2.1.min.js"></script>

    </head>
    <body>

    <div class="header">
    <div class="content">
    <p class="title">
    <span>{{ blog.title }}</span>
    <a href="/cn_backend/" class="backend">管理</a>
    </p>
    </div>
    </div>


    <div class="container">
    <div class="row">
    <div class="col-md-3 menu">
    {% load my_tags %}
    {% get_classification_style username %}
    </div>
    <div class="col-md-9">
    {% block content %}

    {% endblock %}
    </div>
    </div>
    </div>





    </body>
    </html>

    base.html

    Django之博客系统_htmlDjango之博客系统_python_02

    <div>
    <div class="panel panel-warning">
    <div class="panel-heading">我的标签</div>
    <div class="panel-body">
    {% for tag in tag_list %}
    <p><a href="/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p>
    {% endfor %}

    </div>
    </div>

    <div class="panel panel-danger">
    <div class="panel-heading">随笔分类</div>
    <div class="panel-body">
    {% for cate in cate_list %}
    <p><a href="/{{ username }}/category/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p>
    {% endfor %}
    </div>
    </div>

    <div class="panel panel-success">
    <div class="panel-heading">随笔归档</div>
    <div class="panel-body">
    {% for date in date_list %}
    <p><a href="/{{ username }}/archive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p>
    {% endfor %}
    </div>
    </div>
    </div>

    classification.html

    Django之博客系统_htmlDjango之博客系统_python_02

    {% extends 'base.html' %}


    {% block content %}
    <div class="article_list">
    {% for article in article_list %}
    <div class="article-item clearfix">
    <h5><a href="/{{ article.user.username }}/articles/{{ article.pk }}">{{ article.title }}</a></h5>
    <div class="article-desc">
    {{ article.desc }}
    </div>
    <div class="small pub_info pull-right">
    <span>发布于 &nbsp;&nbsp;{{ article.create_time|date:"Y-m-d H:i" }}</span>&nbsp;&nbsp;
    <span class="glyphicon glyphicon-comment"></span>评论({{ article.comment_count }})&nbsp;&nbsp;
    <span class="glyphicon glyphicon-thumbs-up"></span>点赞({{ article.up_count }})&nbsp;&nbsp;
    </div>
    </div>
    <hr>
    {% endfor %}

    </div>
    {% endblock %}

    home_site.html

    Django之博客系统_htmlDjango之博客系统_python_02

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <script src="/static/js/jquery-3.2.1.min.js"></script>
    <script src="/static/blog/bs/js/bootstrap.min.js"></script>

    <style>
    #user_icon {
    font-size: 18px;
    margin-right: 10px;
    vertical-align: -3px;
    }

    .pub_info{
    margin-top: 10px;
    }

    .pub_info .glyphicon-comment{
    vertical-align: -1px;
    }
    </style>
    </head>
    <body>

    <nav class="tab 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="#">博客园</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="#">随笔 <span class="sr-only">(current)</span></a></li>
    <li><a href="#">新闻</a></li>
    <li><a href="#">博文</a></li>

    </ul>

    <ul class="nav navbar-nav navbar-right">

    {% if request.user.is_authenticated %}
    <li><a href="#"><span id="user_icon"
    class="glyphicon glyphicon-user"></span>{{ request.user.username }}</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="#">修改密码</a></li>
    <li><a href="#">修改头像</a></li>
    <li><a href="/cn_backend/">管理</a></li>
    <li><a href="/logout/">注销</a></li>
    <li role="separator" class="divider"></li>
    <li><a href="#">Separated link</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-fluid">
    <div class="row">
    <div class="col-md-3">
    <div class="panel panel-warning">
    <div class="panel-heading">Panel heading without title</div>
    <div class="panel-body">
    Panel content
    </div>
    </div>

    <div class="panel panel-info">
    <div class="panel-heading">Panel heading without title</div>
    <div class="panel-body">
    Panel content
    </div>
    </div>

    <div class="panel panel-danger">
    <div class="panel-heading">Panel heading without title</div>
    <div class="panel-body">
    Panel content
    </div>
    </div>

    </div>
    <div class="col-md-6">
    <div class="article_list">
    {% for article in article_list %}
    <div class="article-item small">
    <h5><a href="/{{ article.user.username }}/articles/{{ article.pk }}">{{ article.title }}</a></h5>
    <div class="article-desc">
    <span class="media-left">
    <a href="/{{ article.user.username }}/"><img width="56" height="56" src="media/{{ article.user.avatar }}" alt=""></a>
    </span>
    <span class="media-right">
    {{ article.desc }}
    </span>
    </div>
    <div class="small pub_info">
    <span><a href="/{{ article.user.username }}/">{{ article.user.username }}</a></span> &nbsp;&nbsp;&nbsp;
    <span>发布于 &nbsp;&nbsp;{{ article.create_time|date:"Y-m-d H:i" }}</span>&nbsp;&nbsp;
    <span class="glyphicon glyphicon-comment"></span>评论({{ article.comment_count }})&nbsp;&nbsp;
    <span class="glyphicon glyphicon-thumbs-up"></span>点赞({{ article.up_count }})&nbsp;&nbsp;
    </div>
    </div>
    <hr>
    {% endfor %}

    </div>
    </div>
    <div class="col-md-3">
    <div class="panel panel-primary">
    <div class="panel-heading">Panel heading without title</div>
    <div class="panel-body">
    Panel content
    </div>
    </div>
    <div class="panel panel-default">
    <div class="panel-heading">Panel heading without title</div>
    <div class="panel-body">
    Panel content
    </div>
    </div>
    </div>
    </div>
    </div>

    </body>
    </html>

    index.html

    Django之博客系统_htmlDjango之博客系统_python_02

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">

    </head>
    <body>
    <h3>登录页面</h3>
    <div class="container">
    <div class="row">
    <div class="col-md-6 col-lg-offset-3">

    <form>
    {% csrf_token %}
    <div class="form-group">
    <label for="user">用户名</label>
    <input type="text" id="user" class="form-control">
    </div>
    <div class="form-group">
    <label for="pwd">密码</label>
    <input type="password" id="pwd" class="form-control">
    </div>


    <div class="form-group">
    <label for="pwd">验证码</label>
    <div class="row">
    <div class="col-md-6">
    <input type="text" class="form-control" id="valid_code">
    </div>
    <div class="col-md-6">
    <img width="270" height="36" id="valid_code_img" src="/get_validCode_img/" alt="">
    </div>
    </div>
    </div>


    <input type="button" class="btn btn-default login_btn" value="submit"><span class="error"></span>
    <a href="/register/" class="btn btn-success pull-right">注册</a>
    </form>

    </div>
    </div>
    </div>


    <script src="/static/js/jquery-3.2.1.min.js"></script>
    <script>

    // 刷新验证码
    $("#valid_code_img").click(function () {

    $(this)[0].src += "?"

    });

    // 登录验证
    $(".login_btn").click(function () {


    $.ajax({
    url: "",
    type: "post",
    data: {
    user: $("#user").val(),
    pwd: $("#pwd").val(),
    valid_code: $("#valid_code").val(),
    csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(),
    },
    success: function (data) {
    console.log(data);

    if (data.user) {
    if (location.search){
    location.href = location.search.slice(6)
    }
    else {
    location.href = "/index/"
    }

    }
    else {
    $(".error").text(data.msg).css({"color": "red", "margin-left": "10px"});
    setTimeout(function(){
    $(".error").text("");
    },1000)

    }
    }
    })

    })

    </script>
    </body>
    </html>

    login.html

    Django之博客系统_htmlDjango之博客系统_python_02

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    </head>
    <body>


    <div class="container" style="margin-top: 100px">
    <div class="text-center">
    <a href="http://www.cnblogs.com/"><img src="/static/blog/img/logo_small.gif" alt="cnblogs"></a>
    <p><b>404.</b> 抱歉! 您访问的资源不存在!</p>
    <p class="d">请确认您输入的网址是否正确,如果问题持续存在,请发邮件至 404042726@qq.com 与 <strong style="font-size: 28px">老村长</strong> 联系。</p>
    <p><a href="/">返回网站首页</a></p>

    </div>
    </div>
    </body>
    </html>

    not_found.html

    Django之博客系统_htmlDjango之博客系统_python_02

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <script src="/static/js/jquery-3.2.1.min.js"></script>
    <style>
    #avatar_img {
    margin-left: 20px;
    }

    #avatar {
    display: none;
    }

    .error {
    color: red;
    }
    </style>

    </head>
    <body>
    <h3>注册页面</h3>
    <div class="container">
    <div class="row">
    <div class="col-md-6 col-lg-offset-3">

    <form id="form">
    {% csrf_token %}

    {% for field in form %}
    <div class="form-group">
    <label for="{{ field.auto_id }}">{{ field.label }}</label>
    {{ field }} <span class="error pull-right"></span>
    </div>
    {% endfor %}

    <div class="form-group">
    <label for="avatar">
    头像
    <img id="avatar_img" width="60" height="60" src="/static/blog/img/default.png" alt="">
    </label>
    <input type="file" id="avatar" name="avatar">
    </div>

    <input type="button" class="btn btn-default reg_btn" value="submit"><span class="error"></span>

    </form>

    </div>
    </div>
    </div>


    <script>
    // 头像预览
    $("#avatar").change(function () {

    // 获取用户选中的文件对象
    var file_obj = $(this)[0].files[0];
    // 获取文件对象的路径
    var reader = new FileReader();
    reader.readAsDataURL(file_obj);
    // 修改img的src属性 ,src=文件对象的路径
    reader.onload = function () {
    $("#avatar_img").attr("src", reader.result)
    };

    });

    // 基于Ajax提交数据

    $(".reg_btn").click(function () {
    //console.log($("#form").serializeArray());
    var formdata = new FormData();
    var request_data = $("#form").serializeArray();
    $.each(request_data, function (index, data) {
    formdata.append(data.name, data.value)
    });

    formdata.append("avatar", $("#avatar")[0].files[0]);

    $.ajax({
    url: "",
    type: "post",
    contentType: false,
    processData: false,
    data: formdata,
    success: function (data) {
    //console.log(data);

    if (data.user) {
    // 注册成功
    location.href="/login/"
    }
    else { // 注册失败

    //console.log(data.msg)
    // 清空错误信息
    $("span.error").html("");
    $(".form-group").removeClass("has-error");

    // 展此次提交的错误信息!
    $.each(data.msg, function (field, error_list) {
    console.log(field, error_list);
    if (field=="__all__"){
    $("#id_re_pwd").next().html(error_list[0]).parent().addClass("has-error");
    }
    $("#id_" + field).next().html(error_list[0]);
    $("#id_" + field).parent().addClass("has-error");


    })

    }
    }
    })

    })


    </script>

    </body>
    </html>

    register.html

    backend文件夹

    Django之博客系统_htmlDjango之博客系统_python_02

    {% extends 'backend/base.html' %}

    {% block content %}

    <form action="" method="post">
    {% csrf_token %}
    <div class="add_article">
    <div class="alert-success text-center">添加文章</div>

    <div class="add_article_region">
    <div class="title form-group">
    <label for="">标题</label>
    <div>
    <input type="text" name="title">
    </div>
    </div>

    <div class="content form-group">
    <label for="">内容(Kindeditor编辑器,不支持拖放/粘贴上传图片) </label>
    <div>
    <textarea name="content" id="article_content" cols="30" rows="10"></textarea>
    </div>
    </div>

    <input type="submit" class="btn btn-default">

    </div>



    </div>
    </form>
    <script src="/static/js/jquery-3.2.1.min.js"></script>
    <script charset="utf-8" src="/static/blog/kindeditor/kindeditor-all.js"></script>

    <script>
    KindEditor.ready(function(K) {
    window.editor = K.create('#article_content',{
    width:"800",
    height:"600",
    resizeType:0,
    uploadJson:"/upload/",
    extraFileUploadParams:{
    csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val()
    },
    filePostName:"upload_img"


    });
    });
    </script>


    {% endblock %}

    add_article.html

    Django之博客系统_htmlDjango之博客系统_python_02

    {% extends 'backend/base.html' %}



    {% block content %}
    <div class="article_list small">

    <table class="table table-hover table-striped">
    <thead>
    <th>标题</th>
    <th>评论数</th>
    <th>点赞数</th>
    <th>操作</th>
    <th>操作</th>
    </thead>
    <tbody>
    {% for article in article_list %}
    <tr>
    <td>{{ article.title }}</td>
    <td>{{ article.comment_count }}</td>
    <td>{{ article.up_count }}</td>
    <td><a href="">编辑</a></td>
    <td><a href="">删除</a></td>
    </tr>
    {% endfor %}

    </tbody>
    </table>
    </div>
    {% endblock %}

    backend.html

    Django之博客系统_htmlDjango之博客系统_python_02

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>博客后台管理 - 博客园</title>

    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
    <script src="/static/js/jquery-3.2.1.min.js"></script>
    <script src="/static/blog/bs/js/bootstrap.min.js"></script>
    <link rel="stylesheet" href="/static/blog/css/backend.css">
    </head>
    <body>

    <div class="header">
    <p class="title">
    后台管理

    <a class="info" href="/logout/">注销</a>
    <span class="info"><span class="glyphicon glyphicon-user"></span>&nbsp;&nbsp;{{ request.user.username }}</span>
    </p>
    </div>


    <div class="container">
    <div class="col-md-3">
    <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
    <div class="panel panel-default">
    <div class="panel-heading" role="tab" id="headingOne">
    <h4 class="panel-title">
    <a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseOne"
    aria-expanded="true" aria-controls="collapseOne">
    操作
    </a>
    </h4>
    </div>
    <div id="collapseOne" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne">
    <div class="panel-body">
    <p><a href="/cn_backend/add_article/">添加文章</a></p>
    </div>
    </div>
    </div>

    </div>
    </div>
    <div class="col-md-9">

    <div>

    <!-- Nav tabs -->
    <ul class="nav nav-tabs" role="tablist">
    <li role="presentation" class="active"><a href="#home" aria-controls="home" role="tab"
    data-toggle="tab">文章</a></li>
    <li role="presentation"><a href="#profile" aria-controls="profile" role="tab"
    data-toggle="tab">日记</a></li>
    <li role="presentation"><a href="#messages" aria-controls="messages" role="tab" data-toggle="tab">眼镜</a>
    </li>
    <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">相册</a>
    </li>
    </ul>

    <!-- Tab panes -->
    <div class="tab-content">
    <div role="tabpanel" class="tab-pane active" id="home">

    {% block content %}

    {% endblock %}


    </div>
    <div role="tabpanel" class="tab-pane" id="profile">

    <img src="/static/blog/img/meinv2.jpg" alt="">
    <img src="/static/blog/img/meinv3.jpg" alt="">
    <img class="pull-right" src="/static/blog/img/meinv.jpg" alt="">
    </div>
    <div role="tabpanel" class="tab-pane" id="messages">

    <img width="180" height="180" src="/static/blog/img/hashiqi2.jpg" alt="">

    <img width="180" height="180" src="/static/blog/img/dogg4.jpg" alt="">
    <img width="180" height="180" src="/static/blog/img/linhaifeng.jpg" alt=""><br>
    <img width="180" height="180" src="/static/blog/img/dogg3.jpeg" alt="">
    <img width="180" height="180" src="/static/blog/img/dogge2.jpg" alt="">

    <img width="180" height="180" src="/static/blog/img/dogg5.jpg" alt="">

    </div>
    <div role="tabpanel" class="tab-pane" id="settings">

    </div>
    </div>

    </div>

    </div>
    </div>

    </body>
    </html>

    base.html


    4、功能测试

    5、项目部署上线


    努力成为一个开发者 个人站点:www.pythonav.cn




    上一篇:代码风格与文件模板
    下一篇:没有了
    网友评论