zoukankan      html  css  js  c++  java
  • BBS总结

    表设计

    from django.db import models
    from django.contrib.auth.models import AbstractUser
    
    
    # Create your models here.
    class UserInfo(AbstractUser):
        nid=models.AutoField(primary_key=True)
        # blank=True admin中改字段可以不填,null=True是数据库层面可以为空
        telephone = models.BigIntegerField(null=True,blank=True)
        # auto_now_add 创建时自动添加当前时间
        create_date = models.DateField(auto_now_add=True)
        # upload_to需要传一个路径
        # default 默认头像的路径
        avatar = models.FileField(upload_to='avatar/', default='avatar/default.png')
        # 跟Blog表一对一
        blog = models.OneToOneField(to='Blog', to_field='nid',null=True)
        class Meta:
            verbose_name='用户表'
            verbose_name_plural = verbose_name
    # 个人站点表
    class Blog(models.Model):
        nid = models.AutoField(primary_key=True)
        site_name = models.CharField(max_length=32)
        site_title = models.CharField(max_length=64)
        # 存css文件的路径
        theme = models.CharField(max_length=32)
        def __str__(self):
            return self.site_name
    
    
    class Category(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        blog = models.ForeignKey(to='Blog', to_field='nid')
    
    
    class Tag(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        blog = models.ForeignKey(to='Blog', to_field='nid')
        def __str__(self):
            return self.name
    
    
    class Article(models.Model):
        nid = models.AutoField(primary_key=True)
        title = models.CharField(max_length=64,verbose_name='文章标题')
        desc = models.CharField(max_length=255)
        # 存大文本
        content = models.TextField()
        create_time = models.DateTimeField(auto_now_add=True)
        # 跟站点表一对多
        blog = models.ForeignKey(to='Blog', to_field='nid',null=True)
        # 跟分类一对多
        category = models.ForeignKey(to='Category', to_field='nid',null=True)
        # 跟标签多对多,手动创建第三张表
        tag = models.ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article', 'tag'))
    
        #     后来想到的
        # 评论数,点赞,点踩数
        comment_num=models.IntegerField(default=0)
        up_num=models.IntegerField(default=0)
        down_num=models.IntegerField(default=0)
        def __str__(self):
            return self.title
    
    
    class Article2Tag(models.Model):
        nid = models.AutoField(primary_key=True)
        article = models.ForeignKey(to='Article', to_field='nid')
        tag = models.ForeignKey(to='Tag', to_field='nid')
    
    #谁对哪篇文章,点赞还是点踩
    class UpAndDown(models.Model):
        nid = models.AutoField(primary_key=True)
        user = models.ForeignKey(to='UserInfo')
        article = models.ForeignKey(to='Article', to_field='nid')
        is_up = models.BooleanField()
    
    #评论对评论自关联,
    #谁,什么时候,对哪篇文章,评论了什么内容,父评论是谁
    class Comment(models.Model):
        nid = models.AutoField(primary_key=True)
        user = models.ForeignKey(to='UserInfo')
        article = models.ForeignKey(to='Article', to_field='nid')
        content = models.CharField(max_length=255)
        # 评论时间
        create_time=models.DateTimeField(auto_now_add=True)
        # parent =models.ForeignKey(to='Comment',to_field='nid')
        # 自关联,存父评论id
        parent = models.ForeignKey(to='self', to_field='nid',null=True)
        # parent =models.IntegerField()
    View Code

    1 登陆功能:

    -图形验证码

    -ajax提交
    -认证用的是auth
    -认证通过,login

        1 forms组件
            1 定义
                from django import forms
                from django.forms import widgets
                from django.core.exceptions import ValidationError
                # 2 写一个类
                class RegForm(forms.Form):
                    # 3 写属性
                    name=forms.CharField(max_length=8,min_length=3,label='用户名',error_messages={'max_length':'超长了'},
                                         widget=widgets.TextInput(attrs={'class':'form-control'})
                                         )
                    
                    # 4 局部钩子函数
                    def clean_name(self):
                        name=self.cleaned_data.get('name')
                        if name.startswith('sb'):
                            raise ValidationError('不能以sb开头')
                        else:
                            # 切记,如果正确,一定要返回name
                            return name
                        
                    #     5 全局钩子函数
                    def clean(self):
                        #一系列逻辑判断
                        #如果校验通过:返回cleaned_data
                        #如果校验不通过:raise ValidationError('两次密码不一致'),错误放到__all__
                        pass
            2 views中使用:
                def test(request):
                    if request.method=='GET':
                        regform=RegForm()
                    else:
                        regform=RegForm(request.POST)
                        if regform.is_valid():
                            #一般情况需要存数据库了
                            pass
                        else:
                            error_all=regform.errors.get('__all__')
                            # error_all=regform.errors['__all__']
                    return render(request,'register.html',locals())
            3 模板中使用
                <form action="">
    
                {% for foo in regform %}
                    {{ foo.label }}:{{ foo }} <span>{{ foo.errors.0 }}</span>
                {% endfor %}
                <input type="submit"> <span>{{ error_all }}</span>
    
                </form>
                
        2 cookie和session
            1 cookie:由服务器产生,存放在客户端浏览器上的键值对
            2 django中使用cookie:
                -设置值:
                    obj=HttpResponse('ok')
                    obj.set_cookie('key','value',max_age=10)
                -取值:
                    request.COOKIES.get('key')
                    request.COOKIES['key']
                -删除值:
                    obj=HttpResponse('ok')
                    obj.delete_cookie('key')
                    
            3 session:保存在服务器上的键值对
                -设置值:
                    request.session['key']='value'
                    request.session['key1']='value1'
                    
                         1 生成一个随机字符串:dasfasdf
                         2 在django_session表中存入dasfasdf   {'key':'value','key1':value1}  超时时间
                         3 把sessionid:dasfasdf写入到cookie
                    
                -取值:
                    request.session.get('key')
                -删除值:
                    request.session.flush():全删除
                    request.session.delete():只删除数据库
                -其它配置参数:
                    了解
                    
        3 Auth模块
            1 Django自带的用户认证模块,可以快速的实现登录,注销,修改密码...
            2 扩展auth表,需要继承AbstractUser
            3 一定不要忘记在setting中配置:AUTH_USER_MODEL = "app名.UserInfo"
            4 它提供的功能
                -from django.contrib.auth import authenticate,login,logout
                -用户认证:user=authenticate(username=lqz,password=123)
                -用户一旦认证通过,调用login(request,user),以后从request.user中就能取出当前登录人对象
                -退出:logout(request),request.user就是匿名用户
                -校验是否通过认证(是否登录):request.user.is_authenticated()
                -创建普通用户
                    -models.UserInfo.objects.create_user(username=lqz)
                -创建超级用户
                    -models.UserInfo.objects.create_superuser(username=lqz)
                -修改密码
                    -用user对象.set_password(新密码)
                    -一定要记住save
                -校验密码
                    -check_password(password)
                -登录认证装饰器(没有登陆的时候跳转)
                    -login_required(login_url='/login/')
                    -全局配置(在setting中配置):
                        LOGIN_URL = '/login/' 
                is_staff: 用户是否拥有网站的管理权限:create_superuser:is_staff是1
                is_active: 是否允许用户登录, 设置为 False,可以在不删除用户的前提下禁止用户登录。
                
                
    今日内容:
        1 中间件
            -是什么?中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能
            -怎么用:
            -自定义中间件:
                1 写一个类,继承MiddlewareMixin,
                2 在类中写方法:
                    process_request
                3 在settings中配置
            
            -5个方法(process_request,process_response)
                ******
                process_request(self,request)
                    -执行顺序,settings中中间件自上而下执行
                    -请求来的时候会执行它
                    -request对象,就是本次请求的request对象,对它处理后,视图函数拿到的就是处理后的request对象
                    
                process_view(self, request, callback, callback_args, callback_kwargs)
                    -callback是视图函数,callback_args, callback_kwargs是视图函数的参数
                    -可以调用callback方法
                
                process_template_response(self,request,response)(忘掉)
                    -只有视图函数返回的对象中有render方法的时候,才会执行
                process_exception(self, request, exception)
                    -视图函数出错,会执行它
                *****
                process_response(self, request, response)
                    -执行顺序,settings中中间件自下而上执行
                    -响应走的时候,会执行它
                    -request对象,就是本次请求的request对象,response是响应对象(HttpResponse的对象)
                
                
            -如果process_request方法返回HttpResponse的对象,请求直接返回,按中间件方法执行顺序往回走
            
        2 csrf
            xss攻击/csrf或xsrf跨站请求伪造
            使用:中间件不注释,form表单中写{% csrf_token %}
        
        3 bbs表设计
            -一个项目从无到有
                1 需求分析
                    -登录ajax,图形验证码
                    -注册forms和ajax,上传头像,头像预览
                    -博客首页
                    -个人站点
                    -点赞,点踩
                    -评论
                        -根评论
                        -子评论
                    -后台展示
                    -添加文章
                        -防xss攻击
                2 设计程序以及程序的架构
                    -Django
                    -数据库设计
                    
                    
                3 分任务开发程序
                
                4 测试
                5 上线运行
                
            -数据库设计
                -用户表:UserInfo---auth模块
                    ...
                    -telephone:手机号
                    -create_date:注册时间
                    -avatar:用户头像
                    -blog:跟Blog表一对一
                -个人站点表:Blog
                    -site_name:站点名称
                    -site_title:站点标题
                    -theme:站点主题样式
                -分类表:Category
                    -nid
                    -name:分类名称
                    -blog:属于哪个站点            一对多
                -标签表:Tag
                    -nid
                    -name:标签的名称
                    -blog:属于哪个站点            一对多
                -文章表:Article
                    -nid
                    -title:文章标题
                    -desc:文章摘要
                    -content:文章内容
                    -create_time:文章发布时间
                    -blog:文章属于哪个站点,      一对多
                    -category:文章分类           一对多
                    -tag:文章标签                多对多
                    
                -Article2Tag:文章跟标签的中间表
                    -nid
                    -article_id:文章id
                    -tag_id:标签id
                -点赞点踩表:UpAndDown
                    -nid
                    -user:谁                一对多            
                    -article:给那篇文章     一对多
                    -is_up:点赞或点踩
                -评论表:Comment
                    -nid
                    -user:谁                 一对多
                    -article:给那篇文章      一对多
                    -content:评论了什么内容
                    -parent_id:父评论的id    自关联
                    
            nid     用户id  文章id   内容        parent_id(父评论的id)
            1        1     1       你好          null
            2        2     1       写的真好      null
            3       3     1       你傻么         1
                
    作业:
        1 csrf中间件不注释,用ajax提交post请求
        2 用中间件实现只有登录了以后,才能访问order,userinfo这些路径,如果没有登录,重定向到登录页面
        
                
                
    View Code

    2 注册功能

    -forms组件
    -ajax提交
    -错误信息渲染

        1 注册:
            -forms组件渲染页面
            -头像预览
            -点击img触发头像上传
            -$("#myform").serializeArray()的使用
            -jq的循环 $.each(循环的对象,匿名函数(两个参数)):
                循环对象如果是个列表,匿名函数的两个参数,一个是索引,一个是索引对应的值
                循环对象如果是个字典,匿名函数的两个参数,一个是key,一个是value
            -上传文件:
                processData: false,
                contentType: false,
            -错误信息渲染
            -定时器
            
            -reg_form.is_valid()走了它之后,cleaned_data中才有值
        -2 登陆
            -生成验证码
                -Pillow
            -生成图片
            -在图片上写字
            -指定写字的字体
            -内存管理器BytesIO
            -验证码保存在session中
            
        -验证码刷新:
        $("#id_imgcode")[0].src += '?'
        
        127.0.0.1:8000/getcode/?random=随机数
    View Code

    3 首页

        admin中添加数据要将用户与一个用户表进行关联
         media的配置,设置用户上传头像路径和默认头像
         开口:

          url(r'^media/(?P<path>.*)', serve,{'document_root':settings.MEDIA_ROOT}),

    -全部文章取出来(分页)for循环渲染

            -首页设计:
                -用户是否登陆
                    {% if request.user.is_authenticated %}
                        <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="#">修改密码</a></li>
                                <li><a href="#">修改头像</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 %}
                -for循环显示所有文章
                -文章作者显示:
                    -{{ article.blog.userinfo.username }}:通过文章,正向查询站点(blog),通过站点反向查询用户,通过用户取出姓名
                -文章评论和点赞数显示:
                    -<span>评论({{ article.comment_set.count }})</span>
                    -<span>点赞({{ article.upanddown_set.count}})</span>
                    -通过文章反向查询(表名小写_set)所有评论,计算评论条数
                    比较复杂,所以用了在文章表中加入三个字段
                        comment_num=models.IntegerField(default=0)
                        up_num=models.IntegerField(default=0)
                        down_num=models.IntegerField(default=0)
            -admin的使用(快速录入数据):
                -注册表,才能在admin后台看到
                    admin.site.register(models.UserInfo)
                    admin.site.register(models.Blog)
                    admin.site.register(models.Tag)
                    admin.site.register(models.Category)
                    admin.site.register(models.Article)
                    admin.site.register(models.UpAndDown)
                    admin.site.register(models.Comment)
                -表名的中文显示:
                    class Meta:
                        verbose_name='用户表'
                        verbose_name_plural = verbose_name
                -字段的中文显示(verbose_name):
                    title = models.CharField(max_length=64,verbose_name='文章标题')
                -admin表单提交,是否必填(blank),注意区分null=True
                    -telephone = models.BigIntegerField(null=True,blank=True)
                
            -mediaroot配置
                -media文件:用户上传的静态文件
                -static文件:网站所用的静态文件
                -在settings中配置:MEDIA_ROOT = os.path.join(BASE_DIR, 'media'),用户上传的文件放到里面
                -在路由中写:  url(r'^media/(?P<path>.*)', serve,{'document_root':settings.MEDIA_ROOT}),
    View Code

    4 个人站点

    -文章展示(当前站点的所有文章)
    -左侧标签显示
    -三个分组查询,TruncMonth


    -抽取成inclusion_tag
    -左侧过滤

    -个人站点:
                -路由:url(r'^(?P<username>w+)',views.site),
                -视图函数:
                    def site(request,username):
                        #通过名字取数据库查询此人是否存在,如果存在,返回此人个人站点,如果不存在,返回404
                        user=models.UserInfo.objects.filter(username=username).first()
                        if not user:
                            return render(request,'error.html')
                        # 取到此人个人站点
                        blog=user.blog
                        # 取出该站点下所有文章(从blog取article,反向查询,一对多,按表名小写_set.all())
                        article_list=blog.article_set.all()
                        return render(request,'site.html',locals())
                -页面样式显示:(动态显示)
                    <link rel="stylesheet" href="/static/css/{{ blog.theme }}">
                
                
            -补充:
                如果想django不自动加斜杠,需要配置APPEND_SLASH=False
                -防盗链:
                    -就是根据refer信息
    
        -自定义session(在中间件中处理)
        -自己的图片防盗链(头三次,可以访问)
        -访问频率控制(一分钟只能,同一个ip地址只能访问3次)
            -设置一个全局变量,记录60sip 访问次数
        
        
    View Code
    -个人站点左侧显示
            -截断表分析
                id   时间                           文章内容        month
                1   2019-01-25 03:04:07.844138          111           2019-01
                2   2018-12-01 03:04:54.000000          222           2018-12
                3   2018-12-01 03:05:17.000000          333           2018-12
                4   2018-11-01 03:05:38.000000          444           2018-11
            -官方提供
                from django.db.models.functions import TruncMonth
                Sales.objects
                .annotate(month=TruncMonth('timestamp'))  # Truncate to month and add to select list
                .values('month')  # Group By month
                .annotate(c=Count('id'))  # Select the count of the grouping
                .values('month', 'c')  # (might be redundant, haven't tested) select month and count
    
            -重点总结:
                -查询当前站点分类下的文章数
                    annotate 方法不局限于用于本文提到的统计分类下的文章数,你也可以举一反三,只要是两个 model 类通过 ForeignKey 或者 ManyToMany 关联起来,那么就可以使用 annotate 方法来统计数量。
                    category_ret = models.Category.objects.filter(blog=blog).annotate(c=Count('article')).values_list('name', 'c')
                -查询当前站点标签下的文章数
                    tag_ret=models.Tag.objects.filter(blog=blog).annotate(c=Count('article')).values_list('name','c')
                -查询当前站点下每个月份下的文章数
                    -month_ret=models.Article.objects.filter(blog=blog).annotate(month=TruncMonth('create_time')).values('month').annotate(c=Count('pk')).values_list('month','c')
                -前端显示:
                    {% for category in category_ret %}
                        <p><a href="">{{ category.0 }}({{ category.1 }})</a></p>
                    {% endfor %}
        -个人站点过滤
            -抽取成inclusion_tag
            -路由设计:
                <p><a href="/{{ username }}/category/{{ category.2 }}">{{ category.0 }}({{ category.1 }})</a></p>
    左边栏

    5 文章详情

    -继承了母版
    -marksafe展示html

    6 点赞点踩

    -事务

        -点赞点踩
            -前端:
                -样式:从博客园扣过来的
                -ajax提交数据
                    -谁对哪篇文章点赞或点赞
                    -只写一个ajax,取出当前点击div内的span,后续直接在span上加一
            -后端:
                -先判断是否登录
                -再判断是否已经点过
                -去article表中修改点赞或点踩数
                -去点赞点踩表中插入一条数据
    View Code

    7 评论

    -根评论
    -根评论提交
    -根评论render显示
    -根评论ajax显示
    -子评论
    -子评论提交
    -子评论render显示
    -子评论ajax显示

    -根评论
            -提交
                -跟点赞点踩类似
            -render显示
                -后端取出所有评论
                -模板中渲染: <ul class="list-group">
                -日期过滤:comment.create_time|date:'Y-m-d H:i:s'
                
            -ajax显示:
                -es6的字符串替换语法:`asdfasfd ${变量名}`,变量需要先定义
                -$(".list-group").append(ss) 拼完追加到后面
            
            -es6字符串替换
                'you is %s'%'big'
                var user_name='lqz'
                 ss=`
                     <li class="list-group-item">
                     <p>
                     <span>${ user_name }</span>
                        <span>${ time }</span>
                    </p>
                    ${content}
                    </li>
                    `
    View Code
        1 子评论提交
            -点击回复按钮,1 获取parent_id 2在文本框中输入:@人名 回车
            -提交的时候:如果是子评论,需要切掉头部
                var index=content.indexOf('
    ')+1
                content=content.slice(index)
            -提交的时候:需要把parent_id提交到后台
        2 子评论render显示
            -判断是否有父评论,如果有,显示父评论的人名
                -@{{ comment.parent.user.username }}
        3 子评论的ajax显示
            -根据parent_id是否有值,判断要拼接的html样式
            -评论提交成功,parent_id的值要置为空
            -后台:如果是子评论格式,需要返回父评论评论人的名字
    子评论

    8 后台文章展示

    -table的展示

    9 新增文章

    -富文本编辑器使用
    -富文本编辑器上传图片
    -处理xss攻击(bs4)

        5 文章添加
            -富文本编辑器
                -从官网下载,放到static文件夹下
                -window.editor = K.create('#id_content')
                -其它参数,具体看文档
                -上传图片,携带csrf
                    uploadJson:'/add_img/',
                    extraFileUploadParams : {
                            csrfmiddlewaretoken : '{{ csrf_token }}',
                    }
            -xss攻击(bs4)
                -通过bs4模块,取出script标签,删除decompose()
                -取出html中150个字符:soup.text[0:150]
            beautifulsoup4  模块
                -解析html页面的
                -爬虫中用的多
            
        -局部禁用csrf,局部使用
            from django.views.decorators.csrf import csrf_protect,csrf_exempt
            @csrf_exempt 局部禁用,前提是csrf中间件使用着
            @csrf_protect 局部使用,前提是csrf中间件没有使用
        -CBV加装饰器
            1 可以加在方法上
                @method_decorator(auth_login)
            2 可以加在类上
                -@method_decorator(auth_login,name='dispatch'):全部使用
                -@method_decorator(auth_login,name='get'):只在get上使用
            3 csrf的装饰器,只能加在类上
                @method_decorator(csrf_exempt,name='dispatch')
    View Code
  • 相关阅读:
    bzoj3757 苹果树
    bzoj2743 [HEOI2012]采花
    bzoj4241 历史研究
    bzoj4448 [Scoi2015]情报传递
    bzoj3295 [Cqoi2011]动态逆序对
    bzoj4034 [HAOI2015]T2
    bzoj3339 Rmq Problem
    BZOJ 1017 魔兽地图
    BZOJ 1021 循环的债务
    SUOI #37 清点更多船只
  • 原文地址:https://www.cnblogs.com/xuechengeng/p/10381737.html
Copyright © 2011-2022 走看看