orm多表匹配和django的路由层
orm表关系建立
首先,我们需要知道表与表的关系有哪些
- 多对多
- 一对多
- 一对一
那么怎么用django的orm去建立这些表的关系?
首先对于一对多的关系,我们需要知道的是,外键的关键字是需要建立在多的一方,比如学生表和班级表,一个班级可以有多个学生,一个学生只能有一个班级,所以学生表和班级表是一对多的关系,在这两张表中,多的一方是学生,所以要把外键建立在学生表的模型类中
# models.py
from django.db import models
class Students(models.Model):
# django可以帮你自动建立id字段的主键
s_name = models.CharField(max_length=32) # 字符类型一定要指定长度
gender = models.CharField(max_length=10)
classroom = models.Foreignkey(to='Classroom') # 指定外键的语法
class Classroom(models.Model):
c_name = models.CharField(max_length=32)
在指定外键时,需要注意的一点:django会自动帮你的外键所在的字段添加一个_id 后缀,所以我们在给外键字段定义变量名时就不需要在后面添加_id后缀
在一对一的关系下,外键字段的关键字可以放在任意一方,但是建议把关键字写在查询用的多的那一张表中,比如学生表和学生具体信息表,这两张表是一对一的关系,但是对学生表的查询次数一定是比较多的,所以推荐把关键字写在这张表中,会增加查询效率
class Student(models.Model):
s_name = models.CharField(max_length=32)
age = models.IntegerField() # 整型可以不指定长度
stu_msg = models.OneToOneField(to='StuMsg') # 定义一对一关系的语法
class StuMsg(models.Model):
addr = models.CharField(max_length=32)
phone = models.BigField()
与指定外键一样,也是不要再字段后面添加_id后缀
多对多的关系稍微有些复杂,因为在建表的时候需要先键被外键关联的那张表,但是多对多的关系需要互相关联外键,所以需要通过第三张表个来表示多对多的关系,但是在django中,你只需要定义外键就行了,它会自动帮你创建第三张表格。在定义外键时,也是推荐把关键字加在查询次数较多的一张表中
这里以书表和作者表为例,因为一本书可以有多个作者,一个作者也可以写多本书,所以是多对多的关系
class Book(models.Model):
title = models.CharField(max_length=32)
# 小数总共八位 小数占两位
price = models.DecimalField(max_digits=8,decimal_places=2)
author = models.ManyToManyField(to='Author')
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
django请求声明周期图
这里直接放图,是具体学习django框架的一个大致的方向
urls路由层
urls路由层就是django中的urls.py文件,urls.py文件的本质就是一个标准的python文件,这个文件的作用就是在url请求和处理请求的视图函数之间的对应关系
urls.py的工作流程
- 浏览器发送请url
- 服务端根据请求的url,在项目所有的应用(包括根目录)的urls配置文件中进行查找,如果能匹配到url,就会将该url交给其对应的视图函数进行处理
- 负责处理的视图函数,会搜集一些业务数据,然后返回给前端页面
路由匹配
在urls的列表中,url的第一个参数是一个正则表达式,只要该正则表达式能够匹配到后面的内容,就会执行后面的视图函数,如果没匹配到,就不再往下执行
urlpatterns = [
url(r'^admin/', admin.site.urls),
]
可以看到上面的正则表达式是带有一个/
的,但是为什么我在输入url的时候不写这个/
也能访问你的到?
这个其实是django提供的匹配方法:
- 不加
/
先匹配一次式式,如果匹配不上,会让浏览器重定向 - 加上
/
再次匹配,如果匹配不上,就会报错
我们也可以通过在settings里面配置APPEND_SLASH = False
来取消
而且,路由匹配值匹配ur部分,不会匹配get请求?
后面携带的参数
无名分组
将分组内正则表达式匹配到的内容当作位置参数传入给视图函数
# urls.py
url(r'^test/([0-9]{4})/', views.test)
# views.py
def test(request,分组内正则表达式匹配到的内容)
# 如果不写匹配后面一个一个参数就会报一个错误
# test() takes 1 positional argument but 2 were given
有名分组
会将分组内的正则表达式匹配到的内容当做关键字参数传递给视图函数
url(r'^testadd/(?P<year>\d+)/', views.testadd),
# testadd() got an unexpected keyword argument 'year'
有名分组和无名分组是不能混合使用的,但是同一种分组的情况下,可以多次使用
反向解析
根据一个别名,动态解析出一个结果,该结果可以直接访问对应的url
有三种情况:
-
第一种情况
路由中没有正则表达式 直接是写死的
url(r'^home/', views.home,name='xxx'), # 给路由与视图函数对应关系起别名
前端反向解析
{% url 'xxx' %}
后端反向解析
from django.shortcuts import render,HttpResponse,redirect,reverse url = reverse('xxx')
-
第二种情况
无名分组的反向解析 在解析的时候 你需要手动指定正则匹配的内容是什么
url(r'^home/(\d+)/', views.home,name='xxx'), # 给路由与视图函数对应关系起别名
前端反向解析
<p><a href="{% url 'xxx' 12 %}">111</a></p> <p><a href="{% url 'xxx' 1324 %}">111</a></p>
后端反向解析
url = reverse('xxx',args=(1,)) # 这里要传一个元组 url1 = reverse('xxx',args=(3213,)) url2 = reverse('xxx',args=(2132131,))
-
第三种情况
有名分组的反向解析 在解析的时候 你需要手动指定正则匹配的内容是什么
有名分组的反向解析可以跟无名分组一样
但是有一种最正规的写法
url(r'^home/(?P<year>\d+)/', views.home,name='xxx'), # 指定别名
前端
# 可以直接用无名分组的情况 <p><a href="{% url 'xxx' 12 %}">111</a></p> # 你也可以规范写法 <p><a href="{% url 'xxx' year=1232 %}">111</a></p>
后端
# 可以直接用无名分组的情况 url = reverse('xxx',args=(1,) # 你也可以规范写法 url = reverse('xxx',kwargs={'year':213123})
路由分发
路由分发的前提
在django中所有的app都可以有独立的urls.py ,templates,static,正是由于这些特点,所以django项目可以做到多人开发,每个人只开发自己的app,最后是需要把所有的app整合到一个空的django项目里面
通过这种方法,我们可以使用路由进行分发任务,分发给各个app,然后app中的urls再进行分发给相应的视图函数执行。
from app01 import urls as app01_urls
from app02 import urls as app02_urls
urlpatterns = [
url(r'^admin/', admin.site.urls), # url第一个参数是一个正则表达式
# 路由分发
url(r'^app01/',include(app01_urls)), # 路由分发需要注意的实现 就是总路由里面不能以$结尾
url(r'^app02/',include(app02_urls)),
]
# 子路由
from django.conf.urls import url
from app01 import views
urlpatterns = [
url('^reg/',views.reg)
]
from django.conf.urls import url
from app02 import views
urlpatterns = [
url('^reg/',views.reg)
]
最省事的写法(******)
url(r'^app01/',include('app01.urls')),
url(r'^app02/',include('app02.urls'))
名称空间
当多个app中出现了起别名冲突的情况 你在做路由分发的时候 可以给每一个app创建一个名称空间
然后在反向解析的时候 可以选择到底去哪个名称空间中查找别名
url(r'^app01/',include('app01.urls',namespace='app01')),
url(r'^app02/',include('app02.urls',namespace='app02'))
# 后端
print(reverse('app01:reg'))
print(reverse('app02:reg'))
# 前端
<a href="{% url 'app01:reg' %}"></a>
<a href="{% url 'app02:reg' %}"></a>
但是我们还可以通过一种更简单的方法去解决这个问题
就是再起别名的时候在前面加上应用名前缀
urlpatterns = [ url('^reg/',views.reg,name='app01_reg')
]
伪静态
伪静态就是把一个动态的网页伪装成一个静态的网页,以此方式来提高搜索引擎查询的频率和搜索的力度,但是就算你伪装的再好,也还是比不过给钱的
虚拟环境
给每一个项目 装备该项目所需要的模块 不需要的模块一概不装
每创建一个虚拟环境就类似于你重新下载了一个纯净python解释器
之后该项目用到上面 你就装什么(虚拟环境一台机器上可以有N多个)
要注意的是:不要在你的机器上无限制创建虚拟环境,也会消耗跟多硬盘资源
django版本版本的区别
# 区别 django2.X里面path第一个参数不是正则也不支持正则 写什么就匹配什么
# 虽然path不支持正则 但是django2.X还有一个re_path的方法 该方法就是你django1.X里面url
# 虽然path不支持正则 但是它提供了五种转换器 能够将匹配到的数据自动转黄成对应的类型
# 除了有默认五种转换器之外 还支持你自定义转换器