码迷,mamicode.com
首页 > 其他好文 > 详细

Summary of Django Framework Knowledge

时间:2020-04-28 16:54:19      阅读:41      评论:0      收藏:0      [点我收藏+]

标签:获取   数据模型   new   tar   分发   asc   template   mysql   pytho   

Preface

最近做蓝鲸SaaS开发课程的理论考试,感觉自己对Django的原理了解得不够深入,故作此文聊以总结。
主要参考资料是Django官方文档,蓝鲸SaaS开发课程为辅。

Project Architecture

安装好Django后,可以通过如下命令构建Django项目:

django-admin startproject [project_name]
cd [project_name]
python manage.py startapp [app_name]
python manage.py migrate # 初始化数据库

其他常用的指令如下:

python manage.py craetesuperuser # 创建管理员
python manage.py runserver {port} # 运行Django服务
python manage.py makemigrations # 创建数据配置文件,显示并记录所有数据的改动
python manage.py migrate # 将表结构的改动更新到数据库

关于django-adminmanage.py常见用法,可以看这篇帖子

Django Life Cycle

也叫请求处理流程,指的是用户从浏览器上输入URL到用户看到网页的这个时间段内,Django后台所发生的事情。流程如下:

  1. 用户(浏览器)发起一个请求。

  2. 请求经由uwsgi处理,转发到请求中间件(Request Middleware),请求中间件会对请求进行预处理(或直接返回请求)。

  3. 请求到达由settings.pyROOT_URLCONF指定的路由文件(默认为urls.py),通过URL匹配至对应的view。

  4. 请求到达视图中间件(View Middleware),视图中间件对请求做一些预处理(或直接返回请求)。

  5. 请求到达视图文件,调用对应的视图方法,进行逻辑处理。

  6. View中的方法可以用个Model访问持久层的数据。

  7. Model访问db的操作由managers进行控制。

  8. View从Model中获取数据后,生成上下文(Context)并给Template传递数据。

  9. Template获取Context后,使用Tags和Filters来渲染数据。

  10. 渲染完成后的Template被返回给View,View通过render函数生成一个HttpResponse对象,并把此对象发送给请求中间件。

  11. 请求中间件会对HttpResponse做一点处理后再返回给浏览器,呈现给用户。

Django Core Model Functions

settings.py

settings.py是项目的全局配置文件,比较常用的是DB配置。

# USE FOLLOWING SQL TO CREATE THE DATABASE
# SQL: CREATE DATABASE `[projectName]` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
DATABASES = {
    ‘default‘: {
        ‘ENGINE‘: ‘django.db.backends.mysql‘,
        ‘NAME‘: ‘projectName‘,
        ‘USER‘: ‘root‘,
        ‘PASSWORD‘: ‘password‘,
        ‘HOST‘: ‘localhost‘,
        ‘PORT‘: ‘3306‘,
    },
}

Django也支持一个项目使用多个数据库,配置方式如下:

  1. settings.py里的DATABASES配置多个DB配置。

  2. 编写一个路由文件以定义路由规则,给每个APP指定数据库,并在DATABASE_ROUTERS中配置路由文件。

此外,Django也支持手工在具体的CURD中指定数据库。

urls.py

path([expresstion], [mapping_function], [kwargs], [alias]) # 精准匹配
pre_path([regular_expresstion], [mapping_function]) # 使用正则表达式来实现模糊匹配

views.py

Django的views.py有两种模式:基于函数的视图(Function based view, FBV)和基于类的视图(Class based view, CBV)。

FBV

FBV即一条路由规则对应一个函数,通过一个函数去处理请求。一旦路由映射表的其中一条路由规则匹配成功,就执行view函数中对应的函数名。这里给一个完整的例子:

# urls.py

from app_name import views

urlpatterns = [
    path(‘‘, views.mainpage)
]

# views.py

from django.shortcuts import HttpResponse

def mainpage:
    return HttpResponse(‘Hello and welcome!‘)

这里再特别解释下HttpRequestHttpResponse:

HttpRequest.xxx:

body: 请求报文的主体
path: 请求的路径
method: 请求的http方法
encoding: 提交数据的编码方式
GET: 包含HTTP GET的所有参数
POST: 包含HTTP POST的所有参数
META: HTTP首部信息

HttpResponse.xxx:

content: 响应内容
charset: 响应内容的编码
status_code: 响应的状态码

CBV

即一条路由规则对应一个类。用户发给服务器的请求包含URL和method(均为str类型),然后服务器通过URL或者method去匹配类中的方法来处理请求。

服务器通过路由映射表匹配成功后会自动去找dispatch方法,然后Django会通过dispatch反射的方式找到类中对应的方法,并执行之。类中的方法执行完毕之后,会把客户端想要的数据返回给dispatch方法,由dispatch方法把数据返回给客户端。

仍然举一个完整的例子:

# urls.py

from app_name import views

urlpatterns = [
    path(‘demo/‘, views.Demos.as_view())
]

# views.py

from django.views import View
from django.shortcuts import HttpResponse

class Demo(View):
    """
    a simple CBV class
    """

    # 处理GET请求
    def get(self, request):
        return HttpResponse(‘GET method!‘)

    # 处理POST请求
    def post(self, request):
        return HttpResponse(‘POST method!‘)

注意到路由配置中,调用了views.Demo类的as_view()方法,且views.py中的Demo类继承了View类。as_view()方法是基类View中定义的一个classonlymethod方法,每个请求都要经过这个方法进行处理,然后通过其定义的dispatch()方法将请求分发到对应的函数去处理。

models.py

Model负责与db打交道,我们可以在Model中定义db的表结构,通过两行指令同步到db。Django还为我们提供了Model的版本管理,可以方便地追溯每一次db表结构的变更。依然是举一个完整的例子:

# models.py

from django.db import models

class Book(models.Model):
    """
    Information of book
    """

    AUTHOR_CHOICE = [
        (‘author1‘, ‘Tom‘),
        (‘author2‘, ‘Bob‘),
        (‘author3‘, ‘Jack‘)
    ]
    book_name = models.CharField(maxlength=64, unique=True)
    author = models.CharField(maxlength=64, null=True, blank=True, choices=AUTHOR_CHOICE)
    create_time = models.DateTimeField(auto_now_add=True)
    update_time = models.DateTimeField(auto_now=True, null=True, blank=True)

    class Meta:
        app_label = ‘app_name‘ # 定义model所属app
        db_table = ‘table_name‘ # 定义表名
        ordering = [‘-id‘] # 默认排序方式
        indexes = [
            models.Index(fields=[‘id‘, ‘id‘])
        ]

至此,可以通过以下两行指令将表结构同步到db:

python manage.py makemigrations [app_name] # 创建脚本
python manage.py migrate [app_name] # 数据迁移

执行makemigrations将在app下自动创建一个migrations目录,并在此目录下创建一个0001_initial.py文件,文件中是即将被执行的脚本内容。

执行migrate会去读取db中django_migrations表(这张表在初始化数据库中就已经被创建)中执行migrations脚本的记录,将未执行的migration脚本都执行一遍,并将记录记入django_migrations表。

此后,每次更改models.py后,执行python manage.py makemigrations [app_name]时,Django都会将models.py和最近一次生成的migrations脚本中的内容做对比,生成“差异脚本”。

MTV Framework

从总体上看,Django框架分为三个模块:Model(模型)、Template(模板)和View(视图),与传统的MVC架构区别不大。其中:

  • Model用于建立数据模型,存储数据。

  • Template用于提供静态页面并渲染从后端获取的数据,位于/template目录下。

  • View用于控制业务逻辑,通过调用Model和Template存取或展现数据。一般来说,业务逻辑会存放view.py文件中,通过urls.py中定义的路由规则将页面请求分发给view.py进行处理。

Model

Django对数据库的表做了一层抽象,Model存储着数据及其对应行为。在model.py文件里,一个类对应着数据库的一张表。

Model有以下三个特点:

  • 每个类都是django.db.models.Model的派生类。

  • 每个类的属性代表了一个数据字段。

  • Django提供了自动生成的数据库调用API。

注意:

  • 表名是自动从模型元数据派生出来的,但可以被覆盖。

  • 每张表自带一个非空id字段,且为主键。如果你不希望使用id作为主键,可以把其他字段设置为primary_key=True,Django不会添加id字段到表中。

  • Model对应哪个数据库的SQL语法,取决于settings.py里选择了哪个数据库。

一旦决定使用某个APP的Model,就应当往settings.py的INSTALLED_APPS添加APP_NAME。

Model Fields

通常来说,这一部分没什么好讲的,用到再查文档就可以了。但是有些东西值得注意一下。

Model的每一个字段都应该是Field类的一个实例,Django使用字段类来决定以下属性:

  • 列类型,展示当前列元素的类型。

  • 呈现表单字段时,默认使用的HTML部件。

  • 最低的验证要求。这一功能用于Django管理员和自动生成的表单中。

字段选项根据Model Fields来决定,比如CharField就需要设定max_length这一属性。关于字段选项,可以看这里

一个比较特殊的选项是choices,它由一系列的二元组组成。如果设定这一属性,则默认的表单组件会从文本字段变成选择框。这里给出一个例子:

# models.py

from django.db import models

class Person(models.Model):
    SHIRT_SIZES = (
        (‘S‘, ‘Small‘),
        (‘M‘, ‘Medium‘),
        (‘L‘, ‘Large‘)
    )
    name = models.CharField(max_length=60)
    shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)

每个tuple的第一个元素会存储在数据库中,第二个元素则被表单组件显示。第二个元素可以通过如下途径得到:

>>> p = Person(name="Tom", shirt_size="L")
>>> p.save() # 保存p这一对象
>>> p.shirt_size
‘L‘
>>> p.get_shirt_size_display() ## 通过调用instance_name.get_FOO_display()方法得到
‘Large‘

另一个值得一谈的选项是primary_key。如果在创建Model时没有指定任何主键,则Django会自动添加一项名为id的IntergerField属性,作为该表的主键。主键字段是只读的。

此外,还可以使用verbose_name来指定属性的详细名称。

Model Relationship

关系模型一直以来都是关系型数据库的重点,在Django中也有与之相关的属性。Django提供了三种常见关系类型:多对一、多对多和一对一。

要定义一个多对一关系,可以使用ForeignKey(django.db.models.ForeignKey)。ForeignKey要求一个位置参数,指定与哪一个Model关联。

在定义ForeignKey和一对一关系时,需要加上on_delete选项。此参数是为了避免两个表里的数据不一致的问题,不然会报错。on_delete有CASCADE/ PROTECT/ SET_NULL/ SET_DEFAULT/ SET()五个可选择的值,含义如下:

  • CASCADE: 级联删除
  • PROTECT: 报完整性错误
  • SET_NULL: 在ForeignKey允许的情况下将其设置为空
  • SET_DEFAULT: 设置为ForeignKey的默认值
  • SET(): 调用外面的值

考察下面这个例子。每一辆车都有其对应的制造商(Manufacturer),每一个制造商可以生产多种不同的汽车:

from django.db import models

class Manufacturer(models.Model):
    pass

class Car(models.Model):
    manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)

Django官方文档提出一个建议:ForeignKey名称应该为所依赖Model名称的小写(就像上面Car类的manufacturer那样写)。

要定义一个多对多关系,可以使用ManyToManyField。和ForeignKey一样,ManyToManyField也要求一个未知参数,指定与哪一个Model关联。

考察下面这个例子。一个披萨需要很多配料(Topping),一种配料可以用于制作很多披萨:

from django.db import models

class Topping(models.Model):
    pass

class Pizza(models.Model):
    toppings = models.ManyToManyFields(Topping)

对于Pizza和Topping这两个Model来说,谁拥有ManyToManyFields字段并不是很重要,但有一点必须要保证:只能把该字段放到其中一个Model中。虽然我们认为谁拥有ManyToManyFields字段并不重要,但一般来说,把ManyToManyFields字段放到表单要编辑的Model中会更加自然。考虑上面的例子,一般我们会认为“披萨对应很多配料”而不是“配料对应很多披萨”。

当我们只需要处理一个简单的多对多关系时,一个ManyToManyFields就已经够用了。但当我们把数据与两个Model的关系关联起来时,情况就变得复杂起来。考虑如下例子:一个APP用于跟踪音乐家所属音乐团体的情况。“音乐家”与“音乐团体”之间存在多对多关系,可以使用ManyToManyFields字段。但我们可能还需要其他数据,比如某个音乐家何时加入了某个音乐团体。对于这种需求,Django允许指定Model来管理多对多关系,然后把额外的属性绑定到该Model中。代码片段如下:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __str__(self):
        return self.name


class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through=‘Membership‘)

    def __str__(self):
        return self.name


class Membership(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

当设置类似上面Membership这样的中介模型时,需要为多对多关系中设计的模型明确指定ForeignKey,该显式声明定义了两个模型之间的关系。

对于中介模型,有如下限制:

  • 中介模型必须有且仅有一个到源模型的ForeignKey,或者使用ManyToManyField.through_fields明确指定Django用于关系的ForeignKey。如果有多个ForeignKey且未指定through_fields,将引发验证错误。类似的限制适用于目标模型的ForeignKey(比如上面的Person类)。

  • 对于通过中介模型且与自身有多对多关系的模型,允许使用同一模型的两个ForeignKey,但它们被视为多对多关系的两个不同方面的东西,也需要指定through_fields,否则也会引发验证错误。

对于上面的例子,可以用如下操作来验证其正确性:

>>> ringo = Person.objects.create(name="Ringo Starr")
>>> paul = Person.objects.create(name="Paul McCartney")
>>> beatles = Group.objects.create(name="The Beatles")
>>> m1 = Membership(person=ringo, group=beatles,
...     date_joined=date(1962, 8, 16),
...     invite_reason="Needed a new drummer.")
>>> m1.save()
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>]>
>>> ringo.group_set.all()
<QuerySet [<Group: The Beatles>]>
>>> m2 = Membership.objects.create(person=paul, group=beatles,
...     date_joined=date(1960, 8, 1),
...     invite_reason="Wanted to form a band.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>

要定义一对一关系,使用OneToOneField这一字段。同样地,也需要给定一个Model名称来指定与哪一个Model关联。这一关系在某个对象“拓展”到另一对象时最为有用。OneToOneField曾经用于自动生成Model的主键,现在已经不再使用这种方法。因此,可以在单个Model中放置多个OneToOneField类型的字段。

考察如下例子:建立了一个名为places的数据库,并在其中存储地址、电话号码等。但如果希望在places的基础上建立restaurant数据库,则没有必要再把已有的数据复制一遍,只需要在原有的数据库中加入一个OneToOneField即可。

Model Meta options

可以通过在Model中声明内部类Meta来给Model赋予元信息,比如:

from django.db import models

class Ox(models.Model):
    horn_length = models.IntegerField()

    class Meta:
        ordering = [‘horn_length‘]
        verbost_name_plural = ‘oxen‘

Model元信息是“不在字段里的数据”,比如排序选项、数据库表名、数据库表详细名称。没有一项是必需的。

Summary of Django Framework Knowledge

标签:获取   数据模型   new   tar   分发   asc   template   mysql   pytho   

原文地址:https://www.cnblogs.com/JHSeng/p/12792339.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!