Django ContentType 及 corf跨域

Posted jassin-du

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django ContentType 及 corf跨域相关的知识,希望对你有一定的参考价值。

ContentType是什么?

Django ContentTypes是由Django框架提供的一个核心功能,它对当前项目中所有基于Django驱动的model提供了更高层次的抽象接口。

ContentTypes能做什么

当使用django-admin初始化一个django项目的时候,可以看到在默认的INSTALL_APPS已经包含了django.contrib.contenttypes:

INSTALLED_APPS = [
    django.contrib.admin,
    django.contrib.auth,
    django.contrib.contenttypes,
    django.contrib.sessions,
    django.contrib.messages,
    django.contrib.staticfiles,
    app01,
]

而且注意django.contrib.contenttypes是在django.contrib.auth之后,这是因为auth中的permission系统是根据contenttypes来实现的。

#  contrib放这项目里面所有的app
从from django.contrib.contenttypes.models import ContentType进去看ContentType的源码 @python_2_unicode_compatible class ContentType(models.Model): app_label = models.CharField(max_length=100) model = models.CharField(_(python model class name), max_length=100) objects = ContentTypeManager() class Meta: verbose_name = _(content type) verbose_name_plural = _(content types) db_table = django_content_type unique_together = ((app_label, model),) def __str__(self): return self.name

我们可以看到ContentType就是一个简单的django model,而且它在数据库中的表的名字为django_content_type

实例

课程有专题课(单纯的课程),学位课(带有更多增益性服务)、价格策略(分阶段标价格,如一个月9.9,两个月29.9,三个月59.9等)

问题一:表结构设计

技术分享图片

技术分享图片
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey,GenericRelation


class DegreeCourse(models.Model):
    name = models.CharField(max_length=32)

class Course(models.Model):
    name = models.CharField(max_length=32)

    # 数据库不生成,只用于链表查询
    policy_list = GenericRelation("PricePolicy")

class PricePolicy(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()

    # 不在数据库中生成,只用于帮助你做数据操作
    content_object = GenericForeignKey(content_type, object_id)

    period = models.CharField(max_length=32)
    price = models.FloatField()
models。py

问题2:为专题课1添加3个价格策略

PricePolicy.objecs。create(period=‘10’,price=9.9,object_id=1,content_type_id=8)关于content_type_id如何取值

技术分享图片

技术分享图片

 

 问题3:要显示所有价格策略,并将对应显示对应课程名

 技术分享图片

问题4:给你课程ID,获取课程信息+该课程的所有价格策略

加字段

技术分享图片

技术分享图片

技术分享图片
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey,GenericRelation


class DegreeCourse(models.Model):
    name = models.CharField(max_length=32)

class Course(models.Model):
    name = models.CharField(max_length=32)

    # 数据库不生成,只用于链表查询
    policy_list = GenericRelation("PricePolicy")

class PricePolicy(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()

    # 不在数据库中生成,只用于帮助你做数据操作
    content_object = GenericForeignKey(content_type, object_id)

    period = models.CharField(max_length=32)
    price = models.FloatField()

# PricePolicy.objects.create(period=‘10‘,price=9.9,object_id=1,content_type_id=8)
# course_obj = Course.objects.get(id=1)
# PricePolicy.objects.create(period=‘10‘,price=9.9,content_object=course_obj)
model。py

 

corf跨域

目标:由api解决跨域,本质添加响应头

1:简单请求

技术分享图片
def service(request):
    # if request.method == ‘OPTIONS‘:
    #     obj = HttpResponse()
    #     return obj
    # else:
        v1 = request.GET.get(v1)
        v2 = request.GET.get(v2)
        result = v1 + v2
        # obj =  HttpResponse(result)
        return HttpResponse(result)
服务端
技术分享图片
<!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</title>
</head>
<body>
    <input type="text" name="v1">
    <input type="text" name="v2">
    <input type="button" value="点我" onclick="getData()">
    <script src="jquery-3.2.1.min.js"></script>
    <script>
        function getData() {
            $.ajax({
                url:"http://127.0.0.1:8000/service/?v1=jassin&v2=666"
                type:GET,

                success:function (arg) {
                    alert(arg);
                }
            })
        }
    </script>
</body>
</html>
客户端

技术分享图片

在返回数据需要加上允许哪些域名通过

def service(request):
        v1 = request.GET.get(v1)
        v2 = request.GET.get(v2)
        result = v1 + v2
        obj =  HttpResponse(result)  # 返回的数据
        # obj["Access-Control-Allow-Origin"] = "*"   # 对域名不限制
        # 允许哪些域名通过
        obj["Access-Control-Allow-Origin"] = "http://localhost:63342"
        return obj:

 2:当用户自定义请求头将请求变成了复杂请求

服务端--->需要先预检自定义请求头,通过后,再发起数据相关请求

    <script>
        function getData() {
            $.ajax({
                url:"http://127.0.0.1:8000/service/?v1=jassin&v2=666",
                type:GET,
//              自定义了请求头
                headers:{
                    k1:v1
                },
                success:function (arg) {
                    alert(arg);
                }
            })
        }
    </script>

用户请求将变成:OPTIONS

技术分享图片

解决:

def service(request):
    if request.method == OPTIONS:
        # 进行预检
        obj = HttpResponse()
        obj["Access-Control-Allow-Headers"] = "k1"# 允许请求头为k1通过
        obj["Access-Control-Allow-Origin"] = "*"  # 允许所有域名访问
        return obj
    else:
        v1 = request.GET.get(v1)
        v2 = request.GET.get(v2)
        result = v1 + v2
        obj =  HttpResponse(result)  # 返回的数据
        # obj["Access-Control-Allow-Origin"] = "*"
        # 允许哪些域名通过
        obj["Access-Control-Allow-Origin"] = "http://localhost:63342"
        return obj

3:由于请求方式不是简单的get请求将请求方式变成复杂请求

当请求方式为PUT 
<script> function getData() { $.ajax({ url:"http://127.0.0.1:8000/service/?v1=jassin&v2=666", type:PUT, // 自定义了请求头 headers:{ k1:v1 }, success:function (arg) { alert(arg); } }) } </script>

技术分享图片

解决

def service(request):
    if request.method == OPTIONS:
        # 进行预检
        obj = HttpResponse()
        obj["Access-Control-Allow-Headers"] = "k1"# 允许请求头为k1通过
        obj["Access-Control-Allow-Origin"] = "*"  # 允许所有域名访问
        obj["Access-Control-Allow-Methods"] = "PUT" # 允许请求方式为put通过
        return obj
    else:
        v1 = request.GET.get(v1)
        v2 = request.GET.get(v2)
        result = v1 + v2
        obj =  HttpResponse(result)  # 返回的数据
        # obj["Access-Control-Allow-Origin"] = "*"
        # 允许哪些域名通过
        obj["Access-Control-Allow-Origin"] = "http://localhost:63342"
        return obj

简单请求和复杂请求

条件:
    1、请求方式:HEAD、GET、POST
    2、请求头信息:
        Accept
        Accept-Language
        Content-Language
        Last-Event-ID
        Content-Type 对应的值是以下三个中的任意一个
                                application/x-www-form-urlencoded
                                multipart/form-data
                                text/plain
 
注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求

 简单请求和非简单请求的区别?

 简单请求:一次请求

非简单请求:
两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。

关于“预检”

 请求方式:OPTIONS
- “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
- 如何“预检”
     => 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
        Access-Control-Request-Method
     => 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
        Access-Control-Request-Headers

注意:

只有域名,才有*,允许所有的域名通过的方式,别的都需单独添加

了解

基于cors实现AJAX请求:

a、支持跨域,简单请求

服务器设置响应头:Access-Control-Allow-Origin = ‘域名‘ 或 ‘*‘

技术分享图片
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <p>
        <input type="submit" onclick="XmlSendRequest();" />
    </p>

    <p>
        <input type="submit" onclick="JqSendRequest();" />
    </p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                }
            };
            xhr.open(GET, "http://c2.com:8000/test/", true);
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: GET,
                dataType: text,
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                }
            })
        }


    </script>
</body>
</html>

HTML
html
技术分享图片
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.set_header(Access-Control-Allow-Origin, "http://www.xxx.com")
        self.write({"status": true, "data": "seven"})
View Code

b、支持跨域,复杂请求

由于复杂请求时,首先会发送“预检”请求,如果“预检”成功,则发送真实数据。

  • “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
  • “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
  • “预检”缓存时间,服务器设置响应头:Access-Control-Max-Age
技术分享图片
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <p>
        <input type="submit" onclick="XmlSendRequest();" />
    </p>

    <p>
        <input type="submit" onclick="JqSendRequest();" />
    </p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                }
            };
            xhr.open(PUT, "http://c2.com:8000/test/", true);
            xhr.setRequestHeader(k1, v1);
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: PUT,
                dataType: text,
                headers: {k1: v1},
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                }
            })
        }


    </script>
</body>
</html>

HTML
html
技术分享图片
class MainHandler(tornado.web.RequestHandler):
    
    def put(self):
        self.set_header(Access-Control-Allow-Origin, "http://www.xxx.com")
        self.write({"status": true, "data": "seven"})

    def options(self, *args, **kwargs):
        self.set_header(Access-Control-Allow-Origin, "http://www.xxx.com")
        self.set_header(Access-Control-Allow-Headers, "k1,k2")
        self.set_header(Access-Control-Allow-Methods, "PUT,DELETE")
        self.set_header(Access-Control-Max-Age, 10)

Tornado
view

c、跨域获取响应头

默认获取到的所有响应头只有基本信息,如果想要获取自定义的响应头,则需要再服务器端设置Access-Control-Expose-Headers。

技术分享图片
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <p>
        <input type="submit" onclick="XmlSendRequest();" />
    </p>

    <p>
        <input type="submit" onclick="JqSendRequest();" />
    </p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                    // 获取响应头
                    console.log(xhr.getAllResponseHeaders());
                }
            };
            xhr.open(PUT, "http://c2.com:8000/test/", true);
            xhr.setRequestHeader(k1, v1);
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: PUT,
                dataType: text,
                headers: {k1: v1},
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                    // 获取响应头
                    console.log(xmlHttpRequest.getAllResponseHeaders());
                }
            })
        }


    </script>
</body>
</html>

HTML
HTML
技术分享图片
class MainHandler(tornado.web.RequestHandler):
    
    def put(self):
        self.set_header(‘Access-Control-Allow-Origin‘, "http://www.xxx.com")

        self.set_header(‘xxoo‘, "seven")
        self.set_header(‘bili‘, "daobidao")

        self.set_header(‘Access-Control-Expose-Headers‘, "xxoo,bili")


        self.write(‘{"status": true, "data": "seven"}‘)

    def options(self, *args, **kwargs):
        self.set_header(‘Access-Control-Allow-Origin‘, "http://www.xxx.com")
        self.set_header(‘Access-Control-Allow-Headers‘, "k1,k2")
        self.set_header(‘Access-Control-Allow-Methods‘, "PUT,DELETE")
        self.set_header(‘Access-Control-Max-Age‘, 10)

Tornado
View

d、跨域传输cookie

在跨域请求中,默认情况下,HTTP Authentication信息,Cookie头以及用户的SSL证书无论在预检请求中或是在实际请求都是不会被发送。

如果想要发送:

  • 浏览器端:XMLHttpRequest的withCredentials为true
  • 服务器端:Access-Control-Allow-Credentials为true
  • 注意:服务器端响应的 Access-Control-Allow-Origin 不能是通配符 *
技术分享图片
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>

    <p>
        <input type="submit" onclick="XmlSendRequest();" />
    </p>

    <p>
        <input type="submit" onclick="JqSendRequest();" />
    </p>

    <script type="text/javascript" src="jquery-1.12.4.js"></script>
    <script>
        function XmlSendRequest(){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(xhr.readyState == 4) {
                    var result = xhr.responseText;
                    console.log(result);
                }
            };

            xhr.withCredentials = true;

            xhr.open(PUT, "http://c2.com:8000/test/", true);
            xhr.setRequestHeader(k1, v1);
            xhr.send();
        }

        function JqSendRequest(){
            $.ajax({
                url: "http://c2.com:8000/test/",
                type: PUT,
                dataType: text,
                headers: {k1: v1},
                xhrFields:{withCredentials: true},
                success: function(data, statusText, xmlHttpRequest){
                    console.log(data);
                }
            })
        }


    </script>
</body>
</html>

HTML
HTML
技术分享图片
class MainHandler(tornado.web.RequestHandler):
    
    def put(self):
        self.set_header(Access-Control-Allow-Origin, "http://www.xxx.com")
        self.set_header(Access-Control-Allow-Credentials, "true")
        
        self.set_header(xxoo, "seven")
        self.set_header(bili, "daobidao")
        self.set_header(Access-Control-Expose-Headers, "xxoo,bili")

        self.set_cookie(kkkkk, vvvvv);

        self.write({"status": true, "data": "seven"})

    def options(self, *args, **kwargs):
        self.set_header(Access-Control-Allow-Origin, "http://www.xxx.com")
        self.set_header(Access-Control-Allow-Headers, "k1,k2")
        self.set_header(Access-Control-Allow-Methods, "PUT,DELETE")
        self.set_header(Access-Control-Max-Age, 10)

Tornado
VIEW

 



以上是关于Django ContentType 及 corf跨域的主要内容,如果未能解决你的问题,请参考以下文章

Django ContentType组件 需求

Django ContentType组件

Django框架(二十七)—— ContentType组件

Django的ContentType应用

Django学习之django自带的contentType表

Django contentType