Django进阶

本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

原文链接:blog.ouyangsihai.cn >> Django进阶

点击上方”python宝典”,关注获取python全套视频,

技术文章第一时间送达!

Form

django中的Form一般有两种功能:

输入html

验证用户输入


import re
from django import forms
from django.core.exceptions import ValidationError
def mobile_validate(value):
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
    if not mobile_re.match(value):
        raise ValidationError('手机号码格式错误')

class PublishForm(forms.Form):
    user_type_choice = (
        (0, u'普通用户'),
        (1, u'高级用户'),
    )
    user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
                                                                  attrs={'class': "form-control"}))
    title = forms.CharField(max_length=20,
                            min_length=5,
                            error_messages={'required': u'标题不能为空',
                                            'min_length': u'标题最少为5个字符',
                                            'max_length': u'标题最多为20个字符'},
                            widget=forms.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'标题5-20个字符'}))

    memo = forms.CharField(required=False,
                           max_length=256,
                           widget=forms.widgets.Textarea(attrs={'class': "form-control no-radius", 'placeholder': u'详细描述', 'rows': 3}))

    phone = forms.CharField(validators=[mobile_validate, ],
                            error_messages={'required': u'手机不能为空'},
                            widget=forms.TextInput(attrs={'class': "form-control",
                                                          'placeholder': u'手机号码'}))

    email = forms.EmailField(required=False,
                            error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
                            widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))

def publish(request):
    ret = {'status': False, 'data': '', 'error': '', 'summary': ''}
    if request.method == 'POST':
        request_form = PublishForm(request.POST)
        if request_form.is_valid():
            request_dict = request_form.clean()
            print request_dict
            ret['status'] = True
        else:
            error_msg = request_form.errors.as_json()
            ret['error'] = json.loads(error_msg)
    return HttpResponse(json.dumps(ret))

在使用Model和Form时,都需要对字段进行定义并指定类型,通过ModelForm则可以省去From中字段的定义


class AdminModelForm(forms.ModelForm):
    class Meta:
        model = models.Admin
        #fields = '__all__'
        fields = ('username', 'email')
        widgets = {
            'email' : forms.PasswordInput(attrs={'class':"alex"}),
        }

跨站请求伪造

django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware 来完成。而对于django中设置防跨站请求伪造功能有分为全局和局部。

全局:

  中间件 django.middleware.csrf.CsrfViewMiddleware

局部:

  • @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
  • @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
  • @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

    注:from django.views.decorators.csrf import csrf_exempt,csrf_protect

    应用

    1、普通表单

    
    veiw中设置返回值:
         return render(request, 'xxx.html', data)
    html中设置Token:
      {% csrf_token %}
    

    2、Ajax

    对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,使用如下方式。

    views.py

    
    from django.shortcuts import render,HttpResponse
    from django.template.context import RequestContext
    # Create your views here.
    def test(req):
        if req.method == 'POST':
            print(req.POST.get('username'))
            print(req.POST.get('pwd'))
            return HttpResponse("ok")
        return render(req,'h1.html')
    

    html

    
    !DOCTYPE html
    html lang="en"
    head
        meta charset="UTF-8"
        titleTitle/title
        script src="/static/jquery-3.3.1.min.js"/script
    /head
    body
            input type="text" name="username" id="u"br
            input type="text" name="pwd" id="p"
            input type="button" value="提交" onclick="f1()"
    script
        $.ajaxSetup({
            data: {
                csrfmiddlewaretoken: '{{ csrf_token }}'
            },
        });
        function f1() {
            $.ajax({
                url:'/test/',
                type:'post',
                data:{
                    username:$('#u').val(),
                    pwd:  $('#p').val()
                },
                success:function (data) {
                    console.log(data)
                }
            });
        }
    /script
    
    /body
    /html
    

    1、获取Cookie:

    
    request.COOKIES['key']
    request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
        参数:
            default: 默认值
               salt: 加密盐
            max_age: 后台控制过期时间
    

    2、设置Cookie:

    
    rep = HttpResponse(...) 或 rep = render(request, ...)
    rep.set_cookie(key,value,...)
    rep.set_signed_cookie(key,value,salt='加密盐',...)
        参数:
            key,              键
            value='',         值
            max_age=None,     超时时间
            expires=None,     超时时间(IE requires expires, so set it if hasn't been already.)
            path='/',         Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
            domain=None,      Cookie生效的域名
            secure=False,     https传输
            httponly=False    只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
    

    由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。

    
    script src='/static/js/jquery.cookie.js'/script
    $.cookie("list_pager_num", 30,{ path: '/' });
    

    Session

    Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:

  • 数据库(默认)
  • 缓存
  • 文件
  • 缓存+数据库
  • 加密cookie
  • 缓存

    缓存+数据库

    缓存Session

    
    a. 配置 settings.py
        SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
        SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
        SESSION_COOKIE_NAME = "sessionid"                        # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
        SESSION_COOKIE_PATH = "/"                                # Session的cookie保存的路径
        SESSION_COOKIE_DOMAIN = None                              # Session的cookie保存的域名
        SESSION_COOKIE_SECURE = False                             # 是否Https传输cookie
        SESSION_COOKIE_HTTPONLY = True                            # 是否Session的cookie只支持http传输
        SESSION_COOKIE_AGE = 1209600                              # Session的cookie失效日期(2周)
        SESSION_EXPIRE_AT_BROWSER_CLOSE = False                   # 是否关闭浏览器使得Session过期
        SESSION_SAVE_EVERY_REQUEST = False                        # 是否每次请求都保存Session,默认修改之后才保存
    
    b. 使用
    def index(request):
            # 获取、设置、删除Session中数据
            request.session['k1']
            request.session.get('k1',None)
            request.session['k1'] = 123
            request.session.setdefault('k1',123) # 存在则不设置
            del request.session['k1']
            # 所有 键、值、键值对
            request.session.keys()
            request.session.values()
            request.session.items()
            request.session.iterkeys()
            request.session.itervalues()
            request.session.iteritems()
            # 用户session的随机字符串
            request.session.session_key
     
            # 将所有Session失效日期小于当前日期的数据删除
            request.session.clear_expired()
     
            # 检查 用户session的随机字符串 在数据库中是否
            request.session.exists("session_key")
     
            # 删除当前用户的所有Session数据
            request.session.delete("session_key")
     
            request.session.set_expiry(value)
                * 如果value是个整数,session会在些秒数后失效。
                * 如果value是个datatime或timedelta,session就会在这个时间后失效。
                * 如果value是0,用户关闭浏览器session就会失效。
                * 如果value是None,session会依赖全局session失效策略。
    

    分页

    Django内置分页

    views.py

    
    from django.shortcuts import render
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    L = []
    for i in range(999):
        L.append(i)
    def index(request):
        current_page = request.GET.get('p')
    
        paginator = Paginator(L, 10)
        # per_page: 每页显示条目数量
        # count:    数据总个数
        # num_pages:总页数
        # page_range:总页数的索引范围,如: (1,10),(1,200)
        # page:     page对象
        try:
            posts = paginator.page(current_page)
            # has_next              是否有下一页
            # next_page_number      下一页页码
            # has_previous          是否有上一页
            # previous_page_number  上一页页码
            # object_list           分页之后的数据列表
            # number                当前页
            # paginator             paginator对象
        except PageNotAnInteger:
            posts = paginator.page(1)
        except EmptyPage:
            posts = paginator.page(paginator.num_pages)
        return render(request, 'index.html', {'posts': posts})
    

    Html

    
    !DOCTYPE html
    html
    head lang="en"
        meta charset="UTF-8"
        title/title
    /head
    body
    ul
        {% for item in posts %}
            li{{ item }}/li
        {% endfor %}
    /ul
    div class="pagination"
          span class="step-links"
            {% if posts.has_previous %}
                a href="?p={{ posts.previous_page_number }}"Previous/a
            {% endif %}
              span class="current"
                Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
              /span
              {% if posts.has_next %}
                  a href="?p={{ posts.next_page_number }}"Next/a
              {% endif %}
          /span
    /div
    /body
    /html
    Html
    

    自定义分页

    分页功能在每个网站都是必要的,对于分页来说,其实就是根据用户的输入计算出应该在数据库表中的起始位置。

    1、设定每页显示数据条数

    2、用户输入页码(第一页、第二页…)

    3、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置

    4、在数据表中根据起始位置取值,页面上输出数据

    需求又来了,需要在页面上显示分页的页面。如:[上一页][1][2][3][4][5][下一页]

    1、设定每页显示数据条数

    2、用户输入页码(第一页、第二页…)

    3、设定显示多少页号

    4、获取当前数据总条数

    5、根据设定显示多少页号和数据总条数计算出,总页数

    6、根据设定的每页显示条数和当前页码,计算出需要取数据表的起始位置

    7、在数据表中根据起始位置取值,页面上输出数据

    8、输出分页html,如:[上一页][1][2][3][4][5][下一页]

    分页实例

    
    #!/usr/bin/env python
    # _*_coding:utf-8_*_
    from django.utils.safestring import mark_safe
     
    class PageInfo(object):
        def __init__(self,current,totalItem,peritems=5):
            self.__current=current
            self.__peritems=peritems
            self.__totalItem=totalItem
        def From(self):
            return (self.__current-1)*self.__peritems
        def To(self):
            return self.__current*self.__peritems
        def TotalPage(self):  #总页数
            result=divmod(self.__totalItem,self.__peritems)
            if result[1]==0:
                return result[0]
            else:
                return result[0]+1
     
    def Custompager(baseurl,currentPage,totalpage):  #基础页,当前页,总页数
        perPager=11
        #总页数11
        #0 -- totalpage
        #总页数11
            #当前页大于5 currentPage-5 -- currentPage+5
                #currentPage+5是否超过总页数,超过总页数,end就是总页数
            #当前页小于5 0 -- 11
        begin=0
        end=0
        if totalpage = 11:
            begin=0
            end=totalpage
        else:
            if currentPage5:
                begin=currentPage-5
                end=currentPage+5
                if end  totalpage:
                    end=totalpage
            else:
                begin=0
                end=11
        pager_list=[]
        if currentPage=1:
            first="a href=''首页/a"
        else:
            first="a href='%s%d'首页/a" % (baseurl,1)
        pager_list.append(first)
     
        if currentPage=1:
            prev="a href=''上一页/a"
        else:
            prev="a href='%s%d'上一页/a" % (baseurl,currentPage-1)
        pager_list.append(prev)
     
        for i in range(begin+1,end+1):
            if i == currentPage:
                temp="a href='%s%d' class='selected'%d/a" % (baseurl,i,i)
            else:
                temp="a href='%s%d'%d/a" % (baseurl,i,i)
            pager_list.append(temp)
        if currentPage=totalpage:
            next="a href='#'下一页/a"
        else:
            next="a href='%s%d'下一页/a" % (baseurl,currentPage+1)
        pager_list.append(next)
        if currentPage=totalpage:
            last="a href=''末页/a"
        else:
            last="a href='%s%d'末页/a" % (baseurl,totalpage)
        pager_list.append(last)
        result=''.join(pager_list)
        return mark_safe(result)   #把字符串转成html语言
    
    Django进阶

    识别图中二维码,欢迎关注python宝典

    本人花费半年的时间总结的《Java面试指南》已拿腾讯等大厂offer,已开源在github ,欢迎star!

    本文GitHub https://github.com/OUYANGSIHAI/JavaInterview 已收录,这是我花了6个月总结的一线大厂Java面试总结,本人已拿大厂offer,欢迎star

    原文链接:blog.ouyangsihai.cn >> Django进阶


      转载请注明: 好好学java Django进阶

     上一篇
    Django~Admin Django~Admin
    点击上方”python宝典”,关注获取python全套视频, 技术文章第一时间送达! admindjango amdin是django提供的一个后台管理页面,给管理页面提供完善的html和css,使得你在通过Model创建完数据库表之后,就
    2021-04-05
    下一篇 
    项目实战-后台管理系统(一) 项目实战-后台管理系统(一)
    点击上方”python宝典”,关注获取python全套视频, 技术文章第一时间送达! 项目需求 用户分为学生,老师,班级。 管理员登陆后可以对这些用户进行增删改查。 数据库设计分析 学生与班级——————-多对一 老师与班级——————-多
    2021-04-05