• Python学习之路—2018/7/10


    Python学习之路—2018/7/10

    博客开发项目流程

    ​ 一般来说,一个项目的开发流程分为:项目需求、设计表结构、功能开发、测试功能、产品上线,本次学习以博客园为蓝本进行开发。

    1.项目需求

    博客的开发的需求主要有以下几点:

    • 基于auth模块和Ajax实现登录验证
    • 基于forms组件和Ajax实现注册功能
    • 设计博客首页
    • 设计个人站点页面
    • 设计文章详情页面
    • 实现文章点赞功能
    • 实现文章的评论功能,包括对文章的评论以及对文章评论的评论
    • 实现富文本编辑框
    • 防止xss攻击(例如当用户的文章中含有JS代码,其他用户进行访问时浏览器会执行JS代码,大大降低了用户的安全性)

    2.设计表结构

    根据功能分析主要有用户信息表(User)、博客信息表(Blog)、博客文章分类信息表(Sort)、博客文章标签信息表(Tag)、博客文章表(Article)、文章点赞表(Like)、文章评论表(Comment),它们之间的关系如下图所示:

    models.py

    from django.db import models
    from django.contrib.auth.models import AbstractUser
    
    
    class User(AbstractUser):
        """
        用户信息表
        """
        uid = models.AutoField(primary_key=True)
        phone = models.CharField(max_length=11, unique=True, null=True)
        avatar = models.FileField(upload_to="avatars/", default="/avatars/default.jpg")
        create_time = models.DateField(verbose_name="创建日期", auto_now_add=True)
    
        blog = models.OneToOneField(to="Blog", to_field="bid", null=True, on_delete=models.CASCADE)  # 与博客建立一对一关系
    
        def __str__(self):
            return self.username
    
    
    class Blog(models.Model):
        """
        博客信息表
        """
        bid = models.AutoField(primary_key=True)
        title = models.CharField(max_length=32, verbose_name="个人博客标题")
        theme = models.CharField(max_length=32, verbose_name="博客主题")
        site = models.CharField(max_length=32, verbose_name="个人站点名称")
    
        def __str__(self):
            return self.site
    
    
    class Sort(models.Model):
        """
        博客文章分类信息表
        """
        sid = models.AutoField(primary_key=True)
        title = models.CharField(max_length=32, verbose_name="分类标题")
    
        blog = models.ForeignKey(to="Blog", to_field="bid", on_delete=models.CASCADE)  # 与博客建立一对多关系
    
        def __str__(self):
            return self.title
    
    
    class Tag(models.Model):
        """
        博客文章标签信息表
        """
        tid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32, verbose_name="标签名称")
    
        blog = models.ForeignKey(to="Blog", to_field="bid", on_delete=models.CASCADE)  # 与博客建立一对多关系
    
        def __str__(self):
            return self.name
    
    
    class Article(models.Model):
        """
        博客文章表
        """
        aid = models.AutoField(primary_key=True)
        title = models.CharField(max_length=32, verbose_name="文章标题")
        abstract = models.CharField(max_length=32, verbose_name="文章摘要")
        create_time = models.DateField(verbose_name="创建日期", auto_now_add=True)
        content = models.TextField()
    
        user = models.ForeignKey(to="User", to_field="uid", verbose_name="作者", on_delete=models.CASCADE)
        sort = models.ForeignKey(to="Sort", to_field="sid", null=True, on_delete=models.CASCADE)
        # 与标签建立多对多关系
        tag = models.ManyToManyField(to="Tag", through="ArticleToTag", through_fields=("article", "tag"))
    
        def __str__(self):
            return self.title
    
    
    class ArticleToTag(models.Model):
        aid = models.AutoField(primary_key=True)
        article = models.ForeignKey(to="Article", to_field="title", verbose_name="文章题目", on_delete=models.CASCADE)
        tag = models.ForeignKey(to="Tag", to_field="name", verbose_name="文章标签", on_delete=models.CASCADE)
    
        def __str__(self):
            name = self.article.title + "---" + self.tag.name
            return name
    
    
    class Like(models.Model):
        """
        文章点赞表
        """
        lid = models.AutoField(primary_key=True)
        user = models.ForeignKey(to="User", to_field="uid", null=True, on_delete=models.CASCADE)
        article = models.ForeignKey(to="Article", to_field="aid", null=True, on_delete=models.CASCADE)
        is_like = models.BooleanField(default=True)
    
    
    class Comment(models.Model):
        """
        文章评论表
        """
        cid = models.AutoField(primary_key=True)
        user = models.ForeignKey(to="User", to_field="uid", null=True, on_delete=models.CASCADE)
        article = models.ForeignKey(to="Article", to_field="aid", null=True, on_delete=models.CASCADE)
        create_time = models.DateField(verbose_name="创建日期", auto_now_add=True)
        content = models.CharField(max_length=255, verbose_name="评论内容")
    
        parent_comment = models.ForeignKey(to="Comment", to_field="cid", null=True, on_delete=models.CASCADE)  # 根评论
    
        def __str__(self):
            return self.content
    

    由于需要用到mysql,所以需要在setteings.py中配置数据库信息

    在第一张User表中,由于是继承了AbstractUser,所以也需要配置信息

    settings.py

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'blog',
            'USER': 'root',
            'PASSWORD': 'admin',
            'HOST': 'localhost',
            'PORT': 3306
        }
    }
    
    AUTH_USER_MODEL = "app01.User"
    

    注意,使用mysql时需要在项目的init.py中添加如下代码:

    import pymysql
    pymysql.install_as_MySQLdb()
    

    3.功能开发

    3.1 登录验证

    login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/blog/css/bootstrap.min.css">
        <link rel="icon" href="/static/blog/image/favicon.ico">
        <style type="text/css">
            body {
                background: url(../static/blog/image/bk.jpeg) no-repeat;
                background-size: 100%;
                overflow: hidden;
            }
            h3 {
                padding: 5px;
                border-bottom: 1px solid #ddd;
            }
        </style>
    </head>
    <body>
    <div class="row">
        <div class="col-md-4 col-md-offset-4" style="margin-top: 100px">
            <form>
                <div class="well">
                    <h3 style="text-align: center">登录界面</h3>
                    <div class="form-group">
                        <label for="username">用户名</label>
                        <input type="text" class="form-control" id="username" placeholder="用户名" autocomplete="off">
                    </div>
                    <div class="form-group">
                        <label for="password">密码</label>
                        <input type="password" class="form-control" id="password" placeholder="密码" autocomplete="off">
                    </div>
                    <div class="row form-group">
                        <div class="col-md-6">
                            <label for="password">验证码</label>
                            <input type="text" class="form-control" id="verify_code" placeholder="请输入验证码" autocomplete="off">
                        </div>
                        <div class="col-md-6">
                            <label for="password"></label>
                            <img src="/verify_code" style="height: 40px; 183px">
                        </div>
                    </div>
                    <button type="button" class="btn btn-default">登录</button>
                </div>
            </form>
        </div>
    </div>
    </body>
    </html>
    

    views.py

    from django.shortcuts import render, HttpResponse
    import random
    from PIL import Image, ImageDraw, ImageFont, ImageFilter
    from io import BytesIO
    
    
    def login(request):
        return render(request, "login.html")
    
    
    def random_color():
        color = (random.randint(64, 255), random.randint(64, 255), random.randint(64, 255))
        return color
    
    
    def random_color2():
        color = (random.randint(32, 127), random.randint(32, 127), random.randint(32, 127))
        return color
    
    
    def random_char():
        """
        随机数/字母
        """
        random_num = str(random.randint(0, 9))
        random_low = chr(random.randint(97, 122))  # a~z
        random_upper = chr(random.randint(65, 90))  # A~Z
        random_chars = random.choice([random_num, random_low, random_upper])
        return random_chars
    
    
    def verify_code(request):
        """
        验证码
        """
        image = Image.new("RGB", (183, 40), (255, 255, 255))
        image_font = ImageFont.truetype("static/blog/font/Arial.ttf", 32)
        draw = ImageDraw.Draw(image)
    
        # 给每个坐标填充颜色
        for x in range(183):
            for y in range(40):
                draw.point((x, y), fill=random_color())
    
        for i in range(5):
            draw.text((20+i*30, 0), random_char(), font=image_font, fill=random_color2())
        image = image.filter(ImageFilter.BLUR)  # 模糊处理
        f = BytesIO()
        image.save(f, "png")
        data = f.getvalue()
    
        return HttpResponse(data)
    

    登录界面效果如下图所示:

  • 相关阅读:
    你真的了解try{ return }finally{}中的return?
    js删除一个div
    js清空 input file上传文件控件
    获取配置文件数据库名称
    【转】一文搞定web自动化环境常见问题
    【转】使用SHC加密bash脚本程序以及解密
    【转】Python远程调试图文教程 之 Pycharm Remote Debug
    【转】Windows下安装MySQL详细教程
    将安装CentOS虚机的iso设置为yum源
    【算法】java语言求不定长字符串的最长子串和长度
  • 原文地址:https://www.cnblogs.com/ExBurner/p/9292153.html
Copyright © 2020-2023  润新知