Python Day18 Django

发布时间:2019-07-19 09:56:49编辑:auto阅读(1370)

    Cookies参数

    (1)获取cookie

    request.COOKIE

    (2)设置cookie

    response.set_cookie("","",)

    (3)cookie参数

    def set_cookie(self, key, value='', max_age=None, expires=None, path='/',
                       domain=None, secure=False, httponly=False):

    max_age过期时间(秒)
    expires过期时间(接收一个日期对象)
    path 设置这个cookie在哪些路径下有效 '/'代表在所有路径下有效
    domain 设置这个cookie在哪些域下有效

    day12

    session

    设置session

    request.session["user_id"]=user.pk
    request.session["username"]=user.user

    设置session方法及原理

    第一步:
    如果获取到sessionid的值,则更新
    if request.COOKIE.get("sessionid"):
    
    第二步:
    如果获取不到,就创建一个字符串                  
    {"user_id":1,"username":"alex"}
    
    1. 生成随机字符串: vwerascxh24asdasdasdsd(session-key)
    2. 在django-sesion表生成一条记录:
        session-key                    session-data
      vwerascxh24asdasdasdsd       {"user_id":1,"username":"alex"}
    
    3. 设置Cookie
        obj.set_cookie("sessionid",vwerascxh24asdasdasdsd) 

    这样,下次再访问时通过获取cookie中的"sessionid"的值就可以得到所对应的session-data

    django-sesion表中session记录示例:

    Python Day18 Django 04

    获取session方法及原理

    获取语句

    request.session.get("user_id")

    大概流程

    1. 根据网页所携带的cookie获取"sessionid"的值
    request.COOKIE.get("sessionid"):vwerascxh24asdasdasdsd
    
    2. 根据"sessionid"的值在django-sesion表查询一条记录:
    session-key=vwerascxh24asdasdasdsd
    
    3. 获取session-data中的数据
    session-data({"user_id":1,"username":"alex"}).get("user_id")

    示例:

    def login(request):
        if request.method == "POST":
            user = request.POST.get("name")
            pwd = request.POST.get("pwd")
            user = Userinfo.objects.filter(user=user, pwd=pwd).first()
            res = {"msg": False}
            if user:
                res["msg"] = True
                import json
                obj = HttpResponse(json.dumps(res))
                request.session["user_id"] = user.pk     #设置session
                request.session["username"] = user.user  #设置session
                return obj
    
        return render(request, "login.html")
    def index(request):
        if not request.session.get("user_id"):   #判断是否能获取到session
            return redirect("/login/")
    
        username = request.session.get("username")  #获取session中"username"的值
    
        return render(request, "index.html", locals())  #把上面获取到的username的值传给模板

    注销session

    def logout(request):
    
        request.session.flush()
    
        return redirect("/login/")

    Django自带分页器

    批量导入数据

    在urls.py中创建一个url

    url(r'^books/$', views.books)

    在models中创建数据表

    class Book(models.Model):
        title = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=8, decimal_places=2)

    在视图中,方法1:

    from django.shortcuts import render, HttpResponse
    
    # Create your views here.
    from app01.models import Book
    
    def books(request):
        book_list = []
        for i in range(100):
            book_obj = Book(title="Book_%s" %i, price=i*i)
            book_list.append(book_obj)
    
        #会将上面的实例化对象一次插入到表中
        Book.objects.bulk_create(book_list)
    
        return HttpResponse("OK")

    在视图中,方法2:

    #批量创建数据
    objs = [models.Book(title="沙河{}".format(i)) for i in range(100)]
    
    #在数据库中批量创建,10次一提交
    models.Book.objects.bulk_create(objs, 10)

    访问:
    http://127.0.0.1:8000/books/

    分页器的使用

    print("count:", paginator.count) # 数据总数
    print("num_pages", paginator.num_pages) # 总页数
    print("page_range", paginator.page_range) # 页码的列表 返回一个range

    page = paginator.page(2) #第2页的page对象

    print(page.object_list) #第2页的所有数据
    结果:

    <QuerySet[ < Book: title_12 >, < Book: title_13 >, < Book: title_14 >...

    for i in page: #遍历第1页的所有数据对象
    print(i)

    结果:
    title_12
    title_13
    title_14
    title_15

    print(page.has_next()) # 是否有下一页
    print(page.next_page_number()) # 下一页的页码
    print(page.has_previous()) # 是否有上一页
    print(page.previous_page_number()) # 上一页的页码

    抛错
    page=paginator.page(12) # error:EmptyPage
    page=paginator.page("z") # error:PageNotAnInteger

    views

    from django.shortcuts import render, HttpResponse
    
    from .models import Book
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger        
    def index(request):
        # 分页器的使用
        try:
            book_list = Book.objects.all()
    
            paginator = Paginator(book_list, 12)  # 获得一个总的分页器对象
    
            # 从url获取page值,如果没有获取就默认1
            c_page = request.GET.get("page", 1)
            # 转换为int类型,不然template识别不了
            currentPage = int(c_page) # 转换为int类型,不然template识别不了
            # 获取page对象
            page = paginator.page(c_page)
    
        except EmptyPage:
            page = paginator.page(1)
    
        return render(request, "index.html", locals())

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>分页器</title>
        <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    </head>
    <body>
    
    <ul>
        {% for book in page.object_list %}
            <p>{{ book.title }}:{{ book.price }}</p>
        {% endfor %}
    </ul>
    
    <nav aria-label="Page navigation">
      <ul class="pagination">
      {% if page.has_previous %}
          <li><a href="?page={{ c_page|add:-1 }}" aria-label="Previous">上一页</a></li>
      {% else %}
          <li class="disabled"><a href="?page={{ c_page|add:-1 }}" aria-label="Previous">上一页</a></li>
      {% endif %}
    
          {% for num in paginator.page_range %}
              {% if currentPage == num %}
                  <li class="active"><a href="?page={{ num }}">{{ num }}</a></li>
              {% else %}
                  <li><a href="?page={{ num }}">{{ num }}</a></li>
              {% endif %}
          {% endfor %}
    
      {% if page.has_next %}
          <li><a href="?page={{ c_page|add:+1 }}" aria-label="Next">下一页</a></li>
      {% else %}
          <li class="disabled"><a href="?page={{ c_page|add:+1 }}" aria-label="Next">下一页</a></li>
      {% endif %}
    
      </ul>
    </nav>
    
    </body>
    </html>

    显示限定页码数

    如果页数过多怎么办?这里保持只显示10个页码
    将template中的paginator.page_range(总页数的列表)修改为下面的pageRange,
    因为显示页数过多,我们这里指定返还给template的页码数列表(range)

    def index(request):

    book_list=Book.objects.all()
    
    paginator = Paginator(book_list, 2)
    page = request.GET.get('page',1)
    currentPage=int(page)
    
    #如果总页数大于30
    if paginator.num_pages>30:
        #如果当前页面page的值-5还小于1
        if currentPage-5<1:
            #页码的列表为1-10(pageRange返回给模板)
            pageRange=range(1,11)
        #如果当前页面page的值+5大于总页数
        elif currentPage+5>paginator.num_pages:
            #计算最大页数-10页的页码
            min_page = (paginator.num_pages + 1) - 10
            #计算当前页面所需要减去的页码数
            page_num = currentPage - min_page
            #页码的列表为“当前所在页数-上面计算的页数 至 总页数+1”,正好凑齐10页(pageRange返回给模板)
            pageRange=range(currentPage-page_num,paginator.num_pages+1)
    
        else:
            #页码的列表为“当前所在页数-5,到当前所在页数+5”(pageRange返回给模板)
            pageRange=range(currentPage-5,currentPage+5)
    
    else:
        #如果总页数小于30,返回给模板实际的页码的列表
        pageRange=paginator.page_range
    
    try:
        #获取当前页面对象
        book_list = paginator.page(page)
    except PageNotAnInteger:
        book_list = paginator.page(1)
    except EmptyPage:
        book_list = paginator.page(paginator.num_pages)
    
    return render(request,"index.html",locals())

    Python Day18 Django 04

    中间件

    Python Day18 Django 04

    中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。
    因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。

    如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。

    自定义中间件

    中间件中一共有四个方法:

    process_request

    process_view

    process_exception

    process_response

    process_request,process_response

    当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求时process_request,最后到达views的函数中,
    views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者

    Python Day18 Django 04

    上述截图中的中间件都是django中的,我们也可以自己定义一个中间件,我们可以自己写一个类,但是必须继承MiddlewareMixin

    settings
    自定义中间件放在哪都可以

    MIDDLEWARE = [
        '...Django默认的Middleware...'
        'app01.utils.mymiddlewares.M1',  #注意,不要忘了逗号
        'app01.utils.mymiddlewares.M2'
    ]

    in views:

    from django.shortcuts import render, HttpResponse
    
    def index(request):
        print("index")
        return HttpResponse("OK")

    in Mymiddlewares.py:

    from django.utils.deprecation import MiddlewareMixin
    
    from django.shortcuts import HttpResponse
    
    class M1(MiddlewareMixin):   #注意继承MiddlewareMixin类
        def process_request(self, request):
            print("M1 process_request")
    
        def process_response(self, request, response):
            print("M1 process_response")
            return response      #process_response要返回一个response
    
    class M2(MiddlewareMixin):
        def process_request(self, request):
            print("M2 process_request")
    
        def process_response(self, request, response):
            print("M2 process_response")
            return response

    结果

    M1 process_request
    M2 process_request
    index
    M2 process_response
    M1 process_response

    注意,process_request带有return的情况下会在满足条件时原路返回,等于从中间拦截了,不再往下走。
    如果 process_response的return不返回response而且是它的,同样也会产生偷梁换柱的效果,返回给客户端的结果将不会是 views中定义的结果

    Django-form表单

    数据校验

    首先在模板中创建一个简单的表单,以获得用户名、邮箱、手机号等

    <form action="" method="post" novalidate>
        {% csrf_token %}
        <p>用户名 <input type="text" name="user"></p>
        <p>邮箱 <input type="email" name="email"></p>
        <p>手机号 <input type="text" name="tel"></p>
        <input type="submit">
    </form>

    此时我们要将用户在网页上填写的内容在视图中拿出来,并做判断
    之前我们是使用if request.POST.get取出后进行判断的,这里换成form表单,
    方法就是在views新建一个Form类(需要继承forms.Form)
    views:

    from django import forms
    
    class UserForm(forms.Form):
        user=forms.CharField(min_length=5)  #最少5位
        tel=forms.CharField(max_length=8)   #最长不超过8位
        email=forms.EmailField()            #判断是否是邮箱地址类型
    
    #我们通过上面这个类帮助我们进行数据校验,从而实现功能的分离和复用
    def reg(request):
    
        if request.method == "POST":
            form = UserForm(request.POST) #绑定数据至表单
            if form.is_valid(): 如果form.is_valid()为Ture
                return HttpResponse('OK')
            else:
                return render(request, 'reg.html', {"form": form})
    
        return render(request, 'reg.html')

    表单的is_valid()方法,如果被校验的字段有一个错误,那么就会返回False

    备注:

    在表单中输入内容,看print(request.POST)能打印出什么
    <QueryDict: {
     'csrfmiddlewaretoken': ['Mhzbi6hiHnxVAKG9GEChEzscCo5GUnkuBnH3xmVOQGYfXxCTQUcoCiu9hGIiqRRT'],
     'user': ['dzm'],
     'email': ['335@qq.com'],
     'tel': ['1118']
     }>

    form表单数据校验原理

    会生成两个字典

    form.is_valid():
        # 校验成功的字段
        form.cleaned_data={"user":"alex999","tel":'123'}
    
        # 校验失败的字段
        form.errors={"email":["..........","......."]} #列表中是错误信息,不再保留key原本的值

    可以将他们打印出来
    print("====>",form.cleaned_data)
    print("====>",form.errors)
    其它
    print("---->", type(form.errors["user"])) #实际是个字典
    print("---->", form.errors["user"][0]) #这样可以取出具体的错误,然后返回给模板通过{{ form.errors.user.0 }}显示出来

    渲染标签

    form除了做校验用还可以做标签用(先拿到一个未绑定数据的form),生成的每个input标签就是form类中字段的名字
    views:

    class UserForm(forms.Form):
        user = forms.CharField(       
            label="用户名",   #自定义form表单显示到网页的名字
            min_length=5,
            error_messages={"required": "不能为空", "min_length": "最小长度不能小于5"},  #自定义错误提示信息
            widget=widgets.TextInput(attrs={"class":"form-clontrol"})  #自定义属性,添加一个Bootstrap样式
        )
    
        tel=forms.CharField(label="手机号", max_length=8, widget=widgets.TextInput(attrs={"class": "form-control"}))
        email=forms.EmailField(label="邮箱", widget=widgets.TextInput(attrs={"class": "form-control"}))
    

    Widgets

    每个表单字段都有一个对应的Widget 类,它对应一个HTML 表单Widget,例如<input type="text">。

    在大部分情况下,字段都具有一个合理的默认Widget。例如,默认情况下,CharField 具有一个TextInput Widget,它在HTML 中生成一个<input type="text">

    表单渲染的选项

    对于<label>/<input> 对,还有几个输出选项:

    {{ form.as_table }} 以表格的形式将它们渲染在<tr> 标签中
    {{ form.as_p }} 将它们渲染在<p> 标签中
    {{ form.as_ul }} 将它们渲染在<li> 标签中
    注意,你必须自己提供<table> 或<ul> 元素。

    模板:

    {#方案1#}

    {#<form action="" method="post" novalidate>#}
    {#    {% csrf_token %}#}
    {#    {{ form.as_p }}#}
    {##}
    {#    <input type="submit">#}
    {#</form>#}

    {#方案2#}

    {#<form action="" method="post" novalidate>#}
    {#    {% csrf_token %}#}
    {#    <div>#}
    {#        用户名#}
    {#        {{ form.user }}#}
    {#    </div>#}
    {##}
    {#    <div>#}
    {#        邮箱#}
    {#        {{ form.email }}#}
    {#    </div>#}
    {#      <div>#}
    {#        手机号#}
    {#        {{ form.tel }}#}
    {#    </div>#}
    {#    #}
    {#    <input type="submit">#}
    {#</form>#}

    方案3

    <div class="container">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <form action="" method="post" novalidate>
                    {% csrf_token %}
                    {% for filed in form %}
                    <div>
                        <label for="">{{ filed.label }}</label>
                        {{ filed }}
                    </div>
                    {% endfor %}
                    <input type="submit">
                </form>
            </div>
        </div>
    </div>
    </body>
    </html>

    更多内容:http://www.cnblogs.com/yuanchenqi/articles/7614921.html

    用户认证

    用户认证基于session,
    用户信息存储在auth_user表中,
    在命令行新建超级用户:(manage.py)
    createsuperuser

    用户登录

    def login(request):
    
        if request.method == "POST":
            user = request.POST.get("user")
            pwd = request.POST.get("pwd")
    
            #校验,将获取到的用户名和密码与auth_user表中的记录做比对,此时会将password转换成加密信息再比对
            user = auth.authenticate(username=user, password=pwd) 
            #如果比对成功会返回一个User对象,失败user会得到一个None
    
            if user:
                #可以获得一个request.user对象,这个对象可以取到当前user对象所代表的用户的所有信息
                auth.login(request, user)
                #此函数使用django的session框架给某个已认证的用户附加上session id等信息。
    
                return redirect("/index/")  
            else:
                return redirect("/login/")
    
        return render(request, "login.html")

    状态保存验证

    def index(request):
        if not request.user:
            return redirect("/login/")
    
        #使用request.user获取用户名
        name = request.user.username
        return render(request, "index.html", {"name":name})
    
    ## 注销
    def logout(request):
        #这句话的本质还是调用request.session.flush()
        auth.logout(request)
        #当调用该函数时,当前请求的session信息会全部清除
    
        return redirect("/login/")

    注册(创建用户)

    def reg(request):
        if request.method == "POST":
            user = request.POST.get("user")
            pwd = request.POST.get("pwd")
    
            #create_user创建一个普通用户,
            User.objects.create_user(username=user, password=pwd)
            return redirect("/login/")
    
        return render(request, "reg.html")

关键字