zoukankan      html  css  js  c++  java
  • 6.2

    一、简介

    博客系统开发

    1.注册,登录,首页
    2.个人站点,分组:(分类,标签,归档)
    3.文章详细页
    4.点赞,踩灭
    5.评论楼,评论树
    6.后台管理,发布文章,文件上传
    7.BeautifulSoup
    8.日志
    数据库          models.py

    注册 /reg/
    上传头像 request.FILES.get('avatar')

    登录 /login/
    随机验证码 /get_valid_img/

    首页 /index/

    个人站点
    分类,标签,归档 /blog/egon/

    文章详细页 /blog/egon/articles/2/

    点赞,踩灭 /blog/poll/
    ajax的post 事务

    评论楼,评论树 /blog/comment/
    根评论,子评论
    render显示,ajax显示

    后台管理,发布文章 /backend/index/
    新建APP
    认证装饰器
    编辑器(KindEditor)
    文件上传 /media/article_imgs/...

    防止XSS攻击
    BeautifulSoup

    二、数据库

    知识点:

    1.继承AbstractUser
    目的:为了使用用户认证组件 auth User
    配置:AUTH_USER_MODEL = "blog.UserInfo"

    class UserInfo(AbstractUser):
    ...


    2.中介模型
    多对多,第三张表自己生成。
    class Article(models.Model):
    ...
    tags = models.ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article', 'tag'))

    class Article2Tag(models.Model):
    ...
    class Meta: # 联合唯一
    unique_together = [
    ('article', 'tag'),
    ]

    3.联合唯一
    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)

    class Meta: # 联合唯一
    unique_together = [
    ('user', 'article'),
    ]

     

    from django.db import models
    from django.contrib.auth.models import 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 = models.CharField(verbose_name='个人博客后缀', max_length=32, unique=True)
        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):
        """
        文章信息
        comment_count up_count down_count 为了查询时,效率高。
        """
        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)
    
        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 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 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):
            return self.article.title + '--' + self.tag.title
    
    
    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 = [
                ('user', 'article'),
            ]
    
    
    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)
        content = models.CharField(verbose_name='评论内容', max_length=255)
        create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    
        parent_comment = models.ForeignKey('self', null=True, on_delete=models.CASCADE)
    
        def __str__(self):
            return self.content
    models.py

    三、admin

    from django.contrib import admin

    # Register your models here.

    from blog.models import *

    admin.site.register(UserInfo)
    admin.site.register(Blog)
    admin.site.register(Category)
    admin.site.register(Tag)
    admin.site.register(Article)
    admin.site.register(ArticleDetail)
    admin.site.register(Article2Tag)
    admin.site.register(ArticleUpDown)
    admin.site.register(Comment)

      

    http://127.0.0.1:8020/admin/

    四、注册

     知识点:

    1.form组件
    class RegForm(forms.Form):pass
    局部钩子 全局钩子

    2.上传头像 avatar
    图像预览
    var reader = new FileReader();
    上传文件
    formdata = new FormData();

    3.用户文件配置
    avatar = models.FileField(upload_to='avatars/', default='avatars/default.png')
    MEDIA_ROOT = os.path.join(BASE_DIR, 'blog', 'media')
    MEDIA_URL = '/media/'
    re_path(r'media/(?P<path>.*)$',serve,{'document_root':settings.MEDIA_ROOT})


    五、登录

     知识点:

    1.验证码
    随机生成5个字符,0-9 a-z A-Z

    pip install pillow
    from PIL import Image, ImageDraw, ImageFont
    image = Image.new()

    在内存中生成图片直接返回
    from io import BytesIO
    f = BytesIO()

    2.request.session['valid_str'] = valid_str
    存在session中,为了之后登录,验证是否通过

    3.验证码点击刷新:
    $('#valid_img').click(function () {
    $(this)[0].src += '?'
    });

    4.认证组件
    valid_str = request.session.get('valid_str')
    if valid_str.upper() == valid_code.upper():
    user = auth.authenticate(username = user, password = pwd)
    if user:
    auth.login(request, user)

    六、首页

     知识点:

    1.bootstrap搭建页面

    2.导航条
    登录: username / 注销
    未登录: 登录 / 注册

    3.for循环

    {% for article in article_list %}
    {% endfor %}

    七、个人站点

     知识点:

    1.文章列表,分类列表,标签列表,日期归档列表
    文章列表: /blog/egon/
    分类列表: /blog/egon/cate/python
    标签列表: /blog/egon/tag/生活
    日期归档列表: /blog/egon/archive/2018-06

    2.模板继承
    {% extends 'base.html' %}

    {% block content %}
    {% endblock content%}}

    3.自定义标签
    /blog/templatetags/my_tag.py

    @register.inclusion_tag('menu.html')
    def get_menu(username):
    ...
    return {} # 去渲染 menu.html

    4.分组查询 .annotate() / extra()应用
    多表分组
    tag_list = Tag.objects.filter(blog=blog).annotate(
    count = Count('article')).values_list('title', 'count')

    单表分组 / DATE_FORMAT() / extra()
    date_list = Article.objects.filter(user=user).extra(
    select={"create_ym": "DATE_FORMAT(create_time,'%%Y-%%m')"}).values('create_ym').annotate(
    c = Count('nid')).values_list('create_ym', 'c')

    5. 时间、区域配置
    TIME_ZONE = 'Asia/Shanghai'
    USE_TZ = False

    八、文章详细页

     知识点:

    1.模板继承
    article = Article.objects.filter(pk=article_id).first()
    {% extends 'base.html' %}
    {% block content %}
    ...
    {{ article.articledetail.content|safe }}
    {% endblock content %}

    九、点赞、踩灭

    知识点:

    1.ajax的post
    var csrfmiddlewaretoken = $('input[name="csrfmiddlewaretoken"]').val();

    2.事务
    try: # article_id 与 user_id 联合唯一 所有使用 try ...
    with transaction.atomic():
    ArticleUpDown.objects.create(is_up=is_up, article_id=article_id, user_id=user_id)
    ...
    Article.objects.filter(pk=article_id).update(up_count=F('up_count')+1)

    except Exception as e:
    ...

    3.F查询:
    Article.objects.filter(pk=article_id).update(up_count=F('up_count')+1)

    十、评论楼、评论树

     知识点:

    1.提交根评论
    2.显示根评论
    --- render显示
    --- ajax显示
    3.提交子评论
    4.显示子评论
    --- render显示
    --- ajax显示
    评论楼
    评论树
    1.ajax提交评论
    post (csrfmiddlewaretoken)
    pid = "" 根评论
    pid = value 子评论

    2.回复事件
    @alex
    val ="@" + $(this).attr('username')+ ' ';

    3.事务
    with transaction.atomic():
    ...
    多个orm sql操作!

    4.F查询,更新
    Article.objects.filter(pk=article_id).update(comment_count=F("comment_count")+1)

     评论树:

    5.js匿名函数
    (function(){})()

    6.ajax get方式获取comment_list
    $.each(comment_list,function(index,comment)){
    ...
    s = '...'
    if(pid){ //子评论
    $('#'+pid).append(s)
    }else{ //根评论
    $('.comment_tree').append(s)
    }
    }

    7.JsonResponse() 返回 non-dict objects 需要 safe=False
    def get_comment_tree(request, article_id):
    ret = list(Comment.objects.filter(article_id=article_id).values(
    'pk', 'content', 'parent_comment_id', 'user__username').order_by('nid'))

    return JsonResponse(ret, safe=False)

    十一、后台管理、KindEditor、BeautifulSoup

     知识点:

    1.新建APP(backend)
    settings:
    INSTALLED_APPS = [..., 'backend.apps.BackendConfig',]

    2.url分配
    re_path(r'backend/', include(('backend.urls', 'backend'))),

    3.认证装饰器
    @login_required
    settings:
    LOGIN_URL = '/login/'

    4.static配置
    STATIC_URL = '/static/'
    STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'blog', 'static'),
    os.path.join(BASE_DIR, 'backend', 'static'),
    ]

    5.编辑器(KindEditor)
        <textarea name="article_con" id="article_box" cols="30" rows="10"></textarea>
        <script src="/static/kindeditor/kindeditor-all.js"></script>
    KindEditor.ready(function (k) {
    window.editor = k.create('#article_box', {
    ...
    ...
    uploadJson: 'upload_img/',
    extraFileUploadParams: {"csrfmiddlewaretoken":$('input[name="csrfmiddlewaretoken"]').val()},
    filePostName: 'img'
    })
    })

    6.文件上传
    用户文件存在 /media/article_imgs/...
    media_path = settings.MEDIA_ROOT
    path = os.path.join(media_path, 'article_imgs', img_obj.name)
    返回json
    img_obj = request.FILES.get('img')
    res = {
    "url": "/media/article_imgs/"+img_obj.name,
    "error": 0
    }
    return HttpResponse(json.dumps(res))

    7.发布文章
    防止XSS攻击 BeautifulSoup,对网页,解析数据

    article_con = request.POST.get('article_con')
    soup = BeautifulSoup(article_con, 'html.parser')

    # 过滤script, 删除了所有的script标签
    for tag in soup.find_all():
    if tag.name == 'script':
    tag.decompose()

    # soup.prettify() == str(soup)
    return redirect(reverse('backend:index'))

    十二、code

    https://github.com/alice-bj/cnblog

    结构:

    cnblog
    ├── backend
    │   ├── static
    │   │   ├── css
    │   │   │   ├── backend.css
    │   │   ├── js
    │   │   │   ├── add_article.js
    │   │   │   ├── jquery-3.2.1.js
    │   │   │   └── jquery-3.2.1.min.js
    │   │   └── kindeditor
    │   │   ├── kindeditor-all.js
    │   │   ├── kindeditor-all-min.js
    │   ├── tests.py
    │   ├── urls.py
    │   └── views.py
    ├── blog
    │   ├── admin.py
    │   ├── apps.py
    │   ├── media
    │   │   ├── article_imgs
    │   │   │   ├── girl.jpg
    │   │   │   ├── jiqimao.gif
    │   │   │   ├── jiqimao.jpg
    │   │   │   └── lufei.jpg
    │   │   ├── avatars
    │   │   │   ├── girl.jpg
    │   │   │   ├── lufei.jpg
    │   ├── models.py
    │   ├── myforms.py
    │   ├── settings.py
    │   ├── static
    │   │   ├── bootstrap-3.3.7
    │   │   │   ├── css
    │   │   │   │   ├── bootstrap.css
    │   │   │   ├── fonts
    │   │   │   └── js
    │   │   │   ├── bootstrap.js
    │   │   │   ├── bootstrap.min.js
    │   │   ├── css
    │   │   │   ├── article_detail.css
    │   │   │   ├── login.css
    │   │   │   └── reg.css
    │   │   ├── font
    │   │   │   └── kumo.ttf
    │   │   ├── img
    │   │   │   ├── default.png
    │   │   │   ├── downdown.gif
    │   │   │   ├── icon_form.gif
    │   │   │   └── upup.gif
    │   │   ├── js
    │   │   │   ├── article_detail.js
    │   │   │   ├── jquery-3.2.1.js
    │   │   │   ├── jquery-3.2.1.min.js
    │   │   │   ├── login.js
    │   │   │   └── reg.js
    │   │   └── theme
    │   │   ├── egon.css
    │   │   └── yuan.css
    │   ├── templatetags
    │   │   ├── my_tags.py
    │   ├── tests.py
    │   ├── urls.py
    │   ├── valid_img.py
    │   └── views.py
    ├── cnblog
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    ├── log
    │   ├── cnblog_collect.log
    │   ├── cnblog_err.log
    │   ├── cnblog_info.log
    ├── manage.py
    └── templates
    ├── add_article.html
    ├── article_detail.html
    ├── backend.html
    ├── base.html
    ├── homesite.html
    ├── index.html
    ├── login.html
    ├── menu.html
    └── reg.html

    账号:

    egon egon1234 / yuan yuan1234 / alex alex1234
  • 相关阅读:
    转载: 如何让form表单在enter键入时不提交
    26个Jquery使用小技巧
    PHP网站页面静态化的生成方法介绍
    用jquery绑定输入框正在输入时返回操作
    PHP开发规范手册之PHP代码规范详解
    Web开发中9个有用的提示和技巧
    TSINGSEE青犀视频边缘计算网关EasyNVR在视频整体监控解决方案中的应用分析
    应急消防通道总是被占用?安防告警视频平台越加必要
    新冠疫情涨涨落落,企业做好线上办公该如何转型?
    【解决方案】如何实现AI自动识别高空抛物行为?
  • 原文地址:https://www.cnblogs.com/alice-bj/p/9160388.html
Copyright © 2011-2022 走看看