标签:获取 数据模型 new tar 分发 asc template mysql pytho
最近做蓝鲸SaaS开发课程的理论考试,感觉自己对Django的原理了解得不够深入,故作此文聊以总结。
主要参考资料是Django官方文档,蓝鲸SaaS开发课程为辅。
安装好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-admin
和manage.py
常见用法,可以看这篇帖子。
也叫请求处理流程,指的是用户从浏览器上输入URL到用户看到网页的这个时间段内,Django后台所发生的事情。流程如下:
用户(浏览器)发起一个请求。
请求经由uwsgi处理,转发到请求中间件(Request Middleware),请求中间件会对请求进行预处理(或直接返回请求)。
请求到达由settings.py
中ROOT_URLCONF
指定的路由文件(默认为urls.py
),通过URL匹配至对应的view。
请求到达视图中间件(View Middleware),视图中间件对请求做一些预处理(或直接返回请求)。
请求到达视图文件,调用对应的视图方法,进行逻辑处理。
View中的方法可以用个Model访问持久层的数据。
Model访问db的操作由managers进行控制。
View从Model中获取数据后,生成上下文(Context)并给Template传递数据。
Template获取Context后,使用Tags和Filters来渲染数据。
渲染完成后的Template被返回给View,View通过render函数生成一个HttpResponse对象,并把此对象发送给请求中间件。
请求中间件会对HttpResponse做一点处理后再返回给浏览器,呈现给用户。
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也支持一个项目使用多个数据库,配置方式如下:
在settings.py
里的DATABASES
配置多个DB配置。
编写一个路由文件以定义路由规则,给每个APP指定数据库,并在DATABASE_ROUTERS中配置路由文件。
此外,Django也支持手工在具体的CURD中指定数据库。
path([expresstion], [mapping_function], [kwargs], [alias]) # 精准匹配
pre_path([regular_expresstion], [mapping_function]) # 使用正则表达式来实现模糊匹配
Django的views.py
有两种模式:基于函数的视图(Function based view, FBV)和基于类的视图(Class based view, CBV)。
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!‘)
这里再特别解释下HttpRequest
和HttpResponse
:
HttpRequest.xxx:
body: 请求报文的主体
path: 请求的路径
method: 请求的http方法
encoding: 提交数据的编码方式
GET: 包含HTTP GET的所有参数
POST: 包含HTTP POST的所有参数
META: HTTP首部信息
HttpResponse.xxx:
content: 响应内容
charset: 响应内容的编码
status_code: 响应的状态码
即一条路由规则对应一个类。用户发给服务器的请求包含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()
方法将请求分发到对应的函数去处理。
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脚本中的内容做对比,生成“差异脚本”。
从总体上看,Django框架分为三个模块:Model(模型)、Template(模板)和View(视图),与传统的MVC架构区别不大。其中:
Model用于建立数据模型,存储数据。
Template用于提供静态页面并渲染从后端获取的数据,位于/template
目录下。
View用于控制业务逻辑,通过调用Model和Template存取或展现数据。一般来说,业务逻辑会存放view.py
文件中,通过urls.py
中定义的路由规则将页面请求分发给view.py
进行处理。
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的每一个字段都应该是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来指定属性的详细名称。
关系模型一直以来都是关系型数据库的重点,在Django中也有与之相关的属性。Django提供了三种常见关系类型:多对一、多对多和一对一。
要定义一个多对一关系,可以使用ForeignKey(django.db.models.ForeignKey)。ForeignKey要求一个位置参数,指定与哪一个Model关联。
在定义ForeignKey和一对一关系时,需要加上on_delete选项。此参数是为了避免两个表里的数据不一致的问题,不然会报错。on_delete有CASCADE/ PROTECT/ SET_NULL/ SET_DEFAULT/ 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来给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