Django第三天

Django深入查询

#model.py

from django.db import models

# Create your models here.

#书表
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=6,decimal_places=2)
    create_time = models.DateField()
    memo = models.CharField(max_length=32,default="")

    publish = models.ForeignKey(to="Publish",default=1)
    author = models.ManyToManyField("Author")

    def __str__(self):
        return self.title

#出版社表
class Publish(models.Model):
    name = models.CharField(max_length=32)
    email = models.CharField(max_length=32)

#作者表
class Author(models.Model):
    name = models.CharField(max_length=32)
    def __str__(self):
        return self.name
    
#作者信息表
class AuthorDetail(models.Model):
    tel=models.CharField(max_length=32)
    email=models.EmailField()
    author=models.OneToOneField("Author")
    def __str__(self):
        return self.email

基于对象的查询(子查询)

1.首先我们要明白什么是正向查询和反向查询?
所谓正向查询就是:关联字段所在的表到被关联的表查询称为正向查询;反向查询:就是被关联表到关联字段表方向的查询。
例如:表关系一对多(出版社==>书)
因为关联字段建立在多的一方、所以此时出版社到书的方向查询称为反向查询、书到出版社方向的查询称为正向查询。
 
2.什么是子查询?
子查询就是将上一次的查询结果作为下一次查询的条件。
 
3.为什么要拆表?
原因大致有3点:
    1.业务信息量太大
    2.单表能描述的信息太少
    3.单表会涉及很多重复性的数据
我们就以博客系统中的图书表、作者表、出版社表为例。
一对多关系的查询
#1.查询id=8的书籍的出版社的名称(书==>出版社,正向查询,按照字段直接查询)
book = Book.objects.filter(id='9').first()    #first查到的是具体的对象。
print(book.publish.name)    #注意此时设计关联字段、所以不能直接查询publish_id,而是要查到这个出版对象,然后根据对象查到名字,得到的结果只有一个,因为一本书只有一个出版社。
sql:
SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price", "app01_book"."create_time", "app01_book"."memo", "app01_book"."publish_id" FROM "app01_book" WHERE "app01_book"."id" = 9 ORDER BY "app01_book"."id" ASC LIMIT 1; args=(9,)
SELECT "app01_publish"."id", "app01_publish"."name", "app01_publish"."email" FROM "app01_publish" WHERE "app01_publish"."id" = 2; args=(2,)


#2.查询工业出版社出版过的书籍名称(出版社==>书,反向查询,按表明小写_set:book_set)
publish = Publish.objects.filter(name='工业出版社').first()    #查询到出版社对象
for item in  publish.book_set.all():    #然后根据出版社.book_set固定格式查出所出版的书对象
    print(item)    #打印的是每一本书对象,会有多个值,因为一个出版社可以出版多本书。
sql:
SELECT "app01_publish"."id", "app01_publish"."name", "app01_publish"."email" FROM "app01_publish" WHERE "app01_publish"."name" = '工业出版社' ORDER BY "app01_publish"."id" ASC LIMIT 1; args=('工业出版社',)
SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price", "app01_book"."create_time", "app01_book"."memo", "app01_book"."publish_id" FROM "app01_book" WHERE "app01_book"."publish_id" = 2 LIMIT 21; args=(2,)
View Code
多对多的表关系查询
#1.查询书名为红楼梦的所有作者的名字(书==>作者,正向查询,按照字段查询)
book = Book.objects.filter(title='红楼梦').first()    #查到图书对象
print(book.author.all())    #多对多关系设计关联字段,所以不能直接查询author_id,而是查作者对象,因为一本书有多个作者所以需要查出所有。他的结果可能是多个或者一个。
sql:
SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price", "app01_book"."create_time", "app01_book"."memo", "app01_book"."publish_id" FROM "app01_book" WHERE "app01_book"."title" = '红楼梦' ORDER BY "app01_book"."id" ASC LIMIT 1; args=('红楼梦',)
SELECT "app01_author"."id", "app01_author"."name" FROM "app01_author" INNER JOIN "app01_book_author" ON ("app01_author"."id" = "app01_book_author"."author_id") WHERE "app01_book_author"."book_id" = 10 LIMIT 21; args=(10,)

#2.查询出吴承恩出版的书籍名称(作者==>图书,反向查询,按表明_set:book_set)
author = Author.objects.filter(name='吴承恩').first()    #查出作者对象
for n in author.book_set.all():    #根据作者对象.book_set固定格式查询出所有的书对象
    print(n.name)    #遍历queryset打印每一本书对象
#方法2
author = Author.objects.filter(name='吴承恩').first()
res=author.book_set.all().values("title")    #直接取出每本书的名称
for n in res:    
    print(n)    #遍历打印,结果为出了多少本书,就有多少结果,打印的是{'title': '红楼梦'}格式的字典
View Code
一对一关系表的查询
#1.查询罗贯中的手机号码(作者==>作者信息,反向查询,因为关联字段创建在作者信息表中,按照小写表明查询)
auth = Author.objects.filter(name='罗贯中').first()    #查出作者对象
print(auth.authordetail.tel)    #根据作者对象然后.authordetail查出作者的所有信息,最后查出手机号码
sql:
SELECT "app01_author"."id", "app01_author"."name" FROM "app01_author" WHERE "app01_author"."name" = '罗贯中' ORDER BY "app01_author"."id" ASC LIMIT 1; args=('罗贯中',)
SELECT "app01_authordetail"."id", "app01_authordetail"."tel", "app01_authordetail"."email", "app01_authordetail"."author_id" FROM "app01_authordetail" WHERE "app01_authordetail"."author_id" = 3; args=(3,)

#2.查出手机号为223的作者名称(信息==>作者,正向查询,直接按照字段查询)
auth_info = AuthorDetail.objects.filter(tel='223').first()    #首先查出该手机号对象
print(auth_info.author.name)    #然后根据手机号对象.author(作者对象).name 查询作者的name

sql:
SELECT "app01_authordetail"."id", "app01_authordetail"."tel", "app01_authordetail"."email", "app01_authordetail"."author_id" FROM "app01_authordetail" WHERE "app01_authordetail"."tel" = '223' ORDER BY "app01_authordetail"."id" ASC LIMIT 1; args=('223',)
SELECT "app01_author"."id", "app01_author"."name" FROM "app01_author" WHERE "app01_author"."id" = 4; args=(4,)

#一对一的查询结果只有一个
View Code

基于queryset的查询

我们就以博客系统中的图书表、作者表、出版社表为例。
一对多关系的查询
#1.查询价格等于111元的书籍的版社名称(书籍==>出版社,正向查询,按照字段)
book = Book.objects.filter(price='111')    #首先根据价格查出所有的符合的对象,可能有多个。
for n in book:    
    print(n.title,n.publish.name)    #遍历根据对象查询取出相关字段
#方法2
book = Book.objects.filter(price='111').values("title","publish__name")    #根据价格符合的对象直接取value,但是明确分辨什么的是什么的?,publish__name就是取的publish表中的name字段,title是book表自己的tiele
for item in book:
    print(item)    #最后的格式为queryset {'title':xxx,'publish__name:xxx'},结果可能有多个值
sql:
SELECT "app01_book"."title", "app01_publish"."name" FROM "app01_book" INNER JOIN "app01_publish" ON ("app01_book"."publish_id" = "app01_publish"."id") WHERE "app01_book"."price" = '111'; args=(Decimal('111'),)

介绍下values的原理:
for book in Book.objects.filter(price=100):
    temp.append({
         "title":book.title,
         "publish__name":book.publish.name,
    })

    
#2.查询工业出版社出版过的书籍名称(出版社==>书,反向查询,按表名小写)
publist = Publish.objects.filter(name='工业出版社').values("book__title")    #首先查找出工业出版社对象,然后取value,book__name==>书籍的名称,这是queryset查询的语法
for n in publist:    #结果为queryset,有多个值
    print(n)    #字典格式{'book__title': 'python'}
sql:
SELECT "app01_book"."title" FROM "app01_publish" LEFT OUTER JOIN "app01_book" ON ("app01_publish"."id" = "app01_book"."publish_id") WHERE "app01_publish"."name" = '工业出版社'; args=('工业出版社',)
View Code
多对多关系表查询
#1.查询出吴承恩出版的书籍名称(作者==>书,反向查询,按表名小写)
author = Author.objects.filter(name='吴承恩').values("book__title")    #根据作者查询书籍名称
print(author)    #得到的是queryset对象
sql:
SELECT "app01_book"."title" FROM "app01_author" LEFT OUTER JOIN "app01_book_author" ON ("app01_author"."id" = "app01_book_author"."author_id") LEFT OUTER JOIN "app01_book" ON ("app01_book_author"."book_id" = "app01_book"."id") WHERE "app01_author"."name" = '吴承恩' LIMIT 21; args=('吴承恩',)

#2.查询Go的所有作者(书==>作者,正向查询,按照字段)
book = Book.objects.filter(title='GO').values("author__name")    
print(book)    #返回queryset对象,返回的值是每本书绑定的作者的和

sql:
SELECT "app01_author"."name" FROM "app01_book" LEFT OUTER JOIN "app01_book_author" ON ("app01_book"."id" = "app01_book_author"."book_id") LEFT OUTER JOIN "app01_author" ON ("app01_book_author"."author_id" = "app01_author"."id") WHERE "app01_book"."title" = 'GO' LIMIT 21; args=('GO',)
View Code
一对一关系变查询
#1.查找手机号为223的作者名字(信息==>作者,正向查询,直接按字段)
info = AuthorDetail.objects.filter(tel='223').values("author__name")    
print(info)    #查询的结果是唯一一个
sql:
SELECT "app01_author"."name" FROM "app01_authordetail" INNER JOIN "app01_author" ON ("app01_authordetail"."author_id" = "app01_author"."id") WHERE "app01_authordetail"."tel" = '223' LIMIT 21; args=('223',)

#2.查询曹雪晴的手机号码(作者==>信息,反向查询,表明小写)
author = Author.objects.filter(name='曹雪晴').values("authordetail__tel")
print(author)    #查询结果为唯一值

#3.查询手机号码以1结尾的作者名字
author = AuthorDetail.objects.filter(tel__endswith='1').values("author__name")    #tel__endswith表示结尾
print(author)    #返回唯一的对象
View Code

基于聚合和分组的查询

我们就以博客系统中的图书表、作者表、出版社表为例。
在使用聚合时需要导入模块
from django.db.models import Avg,Count,Max,Min
#1.统计所有书籍的平均价格
res = Book.objects.all().aggregate(price=Avg("price"))    #使用aggregate函数,计算聚合
print(res)    #返回的结果为字典,{'price': 115.0}
sql:
SELECT AVG("app01_book"."price") AS "price" FROM "app01_book"; args=()

#2.查询每个出版社出版的书的个数
count = Publish.objects.all().annotate(count=Count("book")).values("name","count")    #annotate表示分组
print(count)    #得到的结果为queryset对象,[{'name': '人民出版社', 'count': 1}, {'name': '工业出版社', 'count': 2}],结果为多少个出版社就有多少个结果.
sql:
SELECT "app01_publish"."name", COUNT("app01_book"."id") AS "count" FROM "app01_publish" LEFT OUTER JOIN "app01_book" ON ("app01_publish"."id" = "app01_book"."publish_id") GROUP BY "app01_publish"."id", "app01_publish"."name", "app01_publish"."email" LIMIT 21; args=()


#3.查询每一个作者出版的书籍的平均价格
res = Author.objects.all().annotate(price=Avg("book__price")).values("name","price")    #这里首先要搞明白是每一个作者出的书,不是出版社出的书,
print(res)    #返回个数为作者的个数,[{'name': '曹雪晴', 'price': 111.0}, {'name': '吴承恩', 'price': 117.0}, {'name': '罗贯中', 'price': None}, {'name': '施耐奄', 'price': 111.0}]
sql:
SELECT "app01_author"."name", AVG("app01_book"."price") AS "price" FROM "app01_author" LEFT OUTER JOIN "app01_book_author" ON ("app01_author"."id" = "app01_book_author"."author_id") LEFT OUTER JOIN "app01_book" ON ("app01_book_author"."book_id" = "app01_book"."id") GROUP BY "app01_author"."id", "app01_author"."name" LIMIT 21; args=()

#4.查询每一本书籍名称以及作者的个数
res = Book.objects.all().annotate(count=Count("author")).values("title","count")    
print(res)    #返回queryset对象
sql:
SELECT "app01_book"."title", COUNT("app01_book_author"."author_id") AS "count" FROM "app01_book" LEFT OUTER JOIN "app01_book_author" ON ("app01_book"."id" = "app01_book_author"."book_id") GROUP BY "app01_book"."id", "app01_book"."title", "app01_book"."price", "app01_book"."create_time", "app01_book"."memo", "app01_book"."publish_id" LIMIT 21; args=()

#5.查询价格大于200的每一本书籍名称以及作者的个数
res = Book.objects.filter(price__gt='200').annotate(count=Count("author")).values("title","count") #首先查出价格大于200的书籍
print(res)    #返回queryset对象
sql:
SELECT "app01_book"."title", COUNT("app01_book_author"."author_id") AS "count" FROM "app01_book" LEFT OUTER JOIN "app01_book_author" ON ("app01_book"."id" = "app01_book_author"."book_id") WHERE "app01_book"."price" > CAST('200' AS NUMERIC) GROUP BY "app01_book"."id", "app01_book"."title", "app01_book"."price", "app01_book"."create_time", "app01_book"."memo", "app01_book"."publish_id" LIMIT 21; args=(Decimal('200'),)
View Code

基于F与Q的查询

在使用F和Q查询前需要导入:from django.db.models import F,Q
#1.对ID为1的书的价格增加100元
res = Book.objects.filter(id='1').update(price=F("price")+100)
print(res)   

#2.查询所有书籍中,评论数大于点赞数的书
ret=Book.objects.filter(comment_num__gt=F("poll_num"))    
print(ret)

#3.查询所有书籍评论数大于阅读数的书
ret=Book.objects.filter(comment_num__gt=F("read_num")*10)
print(ret)

#Q

#1.查询书名结尾是O、而且价格大于100的书
res = Book.objects.filter(title__endswith='O',price__gt=100)
print(res)    #返回queryset对象
sql:
SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price", "app01_book"."create_time", "app01_book"."memo", "app01_book"."publish_id" FROM "app01_book" WHERE ("app01_book"."title" LIKE '%O' ESCAPE '\' AND "app01_book"."price" > CAST('100' AS NUMERIC)) LIMIT 21; args=('%O', Decimal('100'))

#2.查询书名以O结尾,或者价格不大于200元
res = Book.objects.filter(Q(title__endswith='O')|~Q(price__gt=200))
print(res)    #返回queryset对象
sql:
SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price", "app01_book"."create_time", "app01_book"."memo", "app01_book"."publish_id" FROM "app01_book" WHERE ("app01_book"."title" LIKE '%O' ESCAPE '\' OR NOT ("app01_book"."price" > CAST('200' AS NUMERIC))) LIMIT 21; args=('%O', Decimal('200'))

#3.查询书以O结尾,或者价价格小于200且不是2014年创建的书籍
res = Book.objects.filter(Q(title__endswith='O')|~Q(price__gt=200,create_time__year=2014))
print(res)    #返回queryset对象
View Code

注意:Q只能写在,(点)的前面,写在后面会报错

#正确的写法
res = Book.objects.filter(Q(price__gt=100),title__endswith='O')
print(res)
#错误的写法
res = Book.objects.filter(title__endswith='O',Q(price__gt=100))
print(res)

Django之Ajax

首先我们要知道什么是Json?
JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。
它基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

Ajax简介

AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。

同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
AJAX除了异步的特点外,还有一个就是:浏览器页面局部刷新;(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>compute</title>
    <script src="/static/jquery-3.3.1.min.js"></script> <!--请使用网络地址-->
</head>
<body>
 {% csrf_token %}

    <p><input id="n1" type="text">+<input id="n2" type="text">=<input id="res" type="text" value=""></p>
    <p><button id="button" value="提交">提交</button></p>
    <script>
        $("#button").click(function () {
            $.ajax({
                url:"/app01/ajax/",
                type:"post",
                data:{
                    'csrfmiddlewaretoken':$("[name='csrfmiddlewaretoken']").val(),
                    n1:$("#n1").val(),
                    n2:$("#n2").val()
                },
                success:function (data) {
                    var date = JSON.parse(data);
                    $("#res").val(date.msg)
                }
            })
        })
    </script>
</body>
</html>

#ajax的工作过程
1.整个过程中页面没有刷新,只是刷新页面中的局部位置而已!
2.当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应!
例子:计算器
ajax的优点
1.AJAX使用Javascript技术向服务器发送异步请求;
2.AJAX无须刷新整个页面;
3.因为服务器响应内容不再是整个页面,而是页面中的局部,所以AJAX性能高;
ajax的参数
#1.请求参数
数据部分:

data: 当前ajax请求要携带的数据,是一个json的object对象,ajax方法就会默认地把它编码成某种格式
    (urlencoded:?a=1&b=2)发送给服务端;此外,ajax默认以get方式发送请求。
    function testData() {
        $.ajax("/test",{     //此时的data是一个json形式的对象
           data:{ a:1, b:2}
      });       
        
processData:
processData:声明当前的data数据是否进行转码或预处理,默认为true,即预处理;if为false, 那么对data:{a:1,b:2}会调用json对象的toString()方法,即{a:1,b:2}.toString() ,最后得到一个[object,Object]形式的结果。
        
contentType:
contentType:默认值: "application/x-www-form-urlencoded"。发送信息至服务器时内容编码类型。用来指明当前请求的数据编码格式;urlencoded:?a=1&b=2;如果想以其他方式提交数据,比如contentType:"application/json",即向服务器发送一个json字符串:
        $.ajax("/ajax_get",{
            data:JSON.stringify({
                a:22,
                b:33}),
            contentType:"application/json",
            type:"POST",
        });      //{a: 22, b: 33}    
 
注意:contentType:"application/json"一旦设定,data必须是json字符串,不能是json对象
后台views.py:   json.loads(request.body.decode("utf8"))

traditional:
 traditional:一般是我们的data数据有数组时会用到 :data:{a:22,b:33,c:["x","y"]},  traditional为false会对数据进行深层次迭代 。      
        
 #2.响应参数
dataType:  预期服务器返回的数据类型,服务器端返回的数据会根据这个值解析后,传递给回调函数。 默认不需要显性指定这个属性,ajax会根据服务器返回的content Type来进行转换;比如我们的服务器响应的content Type为json格式,这时ajax方法就会对响应的内容进行一个json格式的转换,if转换成功,我们在success的回调函数里就会得到一个json格式的对象;转换失败就会触发error这个回调函数。如果我们明确地指定目标类型,就可以使用data Type。dataType的可用值:html|xml|json|text|script
见下dataType实例.  
View Code
csrf跨域的问题
#解决方法1
$.ajaxSetup({
    data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
});

#解决方法2
<form>
{% csrf_token %}
</form><br><br><br>$.ajax(
    data:{ "csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val()
         }
#解决方法3
<script src="{% static 'js/jquery.cookie.js' %}"></script>
$.ajax({
headers:{"X-CSRFToken":$.cookie('csrftoken')},
})
View Code

例子:当我们注册用户的时候、我们输入完成鼠标离开输入框之后,ajax会发起请求,校验用户是否存在。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>compute</title>
    <script src="/static/jquery-3.3.1.min.js"></script>
</head>
<body>
{% csrf_token %}

<p>user:<input id="user" type="text"><span id="sp"></span></p>
<p>passwd:<input id="passwd" type="text"></p>
<p>
    <button id="button" value="提交">提交</button>
</p>
<script>
    $("#user").blur(function () {
        $.ajax({
            url: "/app01/ajax/",
            type: "post",
            data: {
                'csrfmiddlewaretoken': $("[name='csrfmiddlewaretoken']").val(),
                user: $("#user").val(),
                passwd: $("#passwd").val()
            },
            success: function (data) {
                var date = JSON.parse(data);
                if (date.status === 404) {
                    $("#sp").html(date.msg).css("color", "red");
                }
            }
        })
    });
    $("#button").click(function () {
        $.ajax({
            url: "/app01/ajax/",
            type: "post",
            data: {
                'csrfmiddlewaretoken': $("[name='csrfmiddlewaretoken']").val(),
                user: $("#user").val(),
                passwd: $("#passwd").val()
            },
            success: function (data) {
                var date = JSON.parse(data);
                if (date.status === 200) {
                    alert(date.msg)
                }else {
                    $("#sp").html(date.msg).css("color", "red");
                }
            }
        })
    })
</script>
</body>
</html>

#后端:view.py
def ajax(request):
    if request.method == 'POST':
        user = request.POST.get('user')
        passwd = request.POST.get('passwd')
        if Author.objects.filter(name=user):
            msg = {"status": 404, "msg": "用户已存在"}
        else:
            if  passwd == '123':
                msg = {"status": 200, "msg": "登陆成功"}
            else:
                msg = {"status": 500, "msg": "密码错误"}
        return HttpResponse(json.dumps(msg))
    return render(request,'compute.html')
View Code

浏览器的cookie

概念
 http协议的特点:
  •         基于请求响应
  •         短连接
  •         无状态保存
cookie不属于http协议范围,由于http协议无法保持状态,但实际情况,我们却又需要“保持状态”,因此cookie就是在这样一个场景下诞生。
cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上cookie,这样服务器就能通过cookie的内容来判断这个是“谁”了。
cookie虽然在一定程度上解决了“保持状态”的需求,但是由于cookie本身最大支持4096字节,以及cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是session,后面我们会讲述session技术。
由于http协议是无状态的,所以服务器根本不知道访问者是谁,那么上述的cookie就起到了桥接作用,我们为每个客户端分配一个不同的cookie-id,在服务器上保存一端时间,如用户的账号密码信息等。
cookie弥补了http无状态的不足,让服务器知道来的人是“谁”;但是cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过cookie识别不同的用户,对应的在session里保存私密的信息以及超过4096字节的文本。
基于Django实现的cookie
#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 = redirect()
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐',...) 
cookie的参数
def set_cookie(self, key,                 键
             value='',            值
             max_age=None,        超长时间
             expires=None,        超长时间
             path='/',           Cookie生效的路径,
                                         浏览器只会把cookie回传给带有该路径的页面,这样可以避免将
                                         cookie传给站点中的其他的应用。
                                         / 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
             
                     domain=None,         Cookie生效的域名
                                        
                                          你可用这个参数来构造一个跨站cookie。
                                          如, domain=".example.com"
                                          所构造的cookie对下面这些站点都是可读的:
                                          www.example.com 、 www2.example.com 
                         和an.other.sub.domain.example.com 。
                                          如果该参数设置为 None ,cookie只能由设置它的站点读取。

             secure=False,        如果设置为 True ,浏览器将通过HTTPS来回传cookie。
             httponly=False       只能http协议传输,无法被JavaScript获取
                                         (不是绝对,底层抓包可以获取到也可以被覆盖)
          ): pass
View Code

由于cookie保存在客户端,所以使用js也可以操控cookie

<script src='/static/js/jquery.cookie.js'>
</script> $.cookie("key", value,{ path: '/' });
删除cookie
response.delete_cookie("cookie_key",path="/",domain=name)

cookie存储到客户端
优点:
数据存在在客户端,减轻服务器端的压力,提高网站的性能。
缺点:
安全性不高:在客户端机很容易被查看或破解用户会话信息
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>compute</title>
    <script src="/static/jquery-3.3.1.min.js"></script>
</head>
<body>
{% csrf_token %}

<p>user:<input id="user" type="text"><span id="sp"></span></p>
<p>passwd:<input id="passwd" type="text"></p>
<p>
    <button id="button" value="提交">提交</button>
</p>
<script>
    $("#user").blur(function () {
        $.ajax({
            url: "/app01/ajax/",
            type: "post",
            data: {
                'csrfmiddlewaretoken': $("[name='csrfmiddlewaretoken']").val(),
                user: $("#user").val(),
                passwd: $("#passwd").val()
            },
            success: function (data) {
                var date = JSON.parse(data);
                if (date.status === 404) {
                    $("#sp").html(date.msg).css("color", "red");
                }
            }
        })
    });
    $("#button").click(function () {
        $.ajax({
            url: "/app01/ajax/",
            type: "post",
            data: {
                'csrfmiddlewaretoken': $("[name='csrfmiddlewaretoken']").val(),
                user: $("#user").val(),
                passwd: $("#passwd").val()
            },
            success: function (data) {
                var date = JSON.parse(data);
                if (date.status === 200) {
                    alert(date.msg)
                }else {
                    $("#sp").html(date.msg).css("color", "red");
                }
            }
        })
    })
</script>
</body>
</html>

#views.py

def ajax(request):
    if request.method == 'POST':
        user = request.POST.get('user')
        passwd = request.POST.get('passwd')
        if Author.objects.filter(name=user).first():
            msg = {"status": 404, "msg": "用户已存在"}
            res = HttpResponse(json.dumps(msg))
        else:
            if  passwd == '123':
                msg = {"status": 200, "msg": "登陆成功"}
                res = HttpResponse(json.dumps(msg))    
                res.set_cookie("login",hash(user))    #对登陆成功的用户设置cookie

            else:
                msg = {"status": 500, "msg": "密码错误"}
                res = HttpResponse(json.dumps(msg))
        return res
    return render(request,'compute.html')

#查看所有的图书
def books(request):
    res = request.COOKIES    #如果获取不到cookie则302到登录页,只有带了cookie才让访问
    if res:
        #获取数据图书对象
        book_obj = Book.objects.all()
        if request.method == 'GET':
            return render(request,'books.html',locals())
        else:
            return HttpResponse("{'code':'500','msg':'error'}")
    else:
        return redirect('/app01/ajax/')
关于cookie的登陆实例

 

posted @ 2018-04-22 18:39  健林  阅读(101)  评论(0)    收藏  举报