目录
一、ORM关系建立
(一)ForeignKey(一对多)
- 外键字段建在多的那一方(多次引用)
- 外键字段在同步时,会自动在字段加_id后缀,不需要手动加
from django.db import models
class Publish(models.Model):
title = models.CharField(max_length=32)
email = models.EmailField()
class Book(models.Model):
title = models.CharField(max_length=32)
email = models.DecimalField(max_digits=8,decimal_places=2) # 数字总共8位,小数两位
# 书和出版社是一对多,并且书是多的一方,所以外键字段在书表中
publish = models.ForeignKey(to = 'Publish') # to用来指代和哪张表有关系,默认关联主键字段
(二)ManyToManyField(多对多)
- 被当做外键的表必须先创建,因此多对多的外键关系需要建立第三张表来专门处理
- 多对多的外键字段建在任意一方都可以,推荐建在查询速率高的一方
- 多对多的外键字段只是一个虚拟字段,不会再表中展示出来,只是起到一个高速ORM创建第三张表的关系的作用
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
# 书跟作者是多对多的关系 外键字段建在任意一方都可以 但是建议你建在查询频率较高的那一方
author = models.ManyToManyField(to='Author') # django orm会自动帮你创建书籍和作者的第三张关系表
# author这个字段是一个虚拟字段 不能在表中展示出来 仅仅只是起到一个高速orm 建第三章表的关系的作用
(三)OneToOneField(一对一)
- 一对一的表关系,外键字段建在任意一方都可以,推荐建在查询频率较高的一方
- 外键字段也不用添加_id
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
# 一对一的表关系 外键字段建在任意一方都可以,推荐建在查询频率较高的一方
author_detail = models.OneToOneField(to='Author_detail') # fk + unique
class Author_detail(models.Model):
phone = models.BigIntegerField()
addr = models.CharField(max_length=32)
二、django请求生命周期流程图
三、urls.py 路由层
(一)路由匹配
路由即请求地址和视图函数的映射关系
(1)URLconf配置
- 正则表达式:一个正则表达式字符串
- views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
- 参数:可选的要传递给视图函数的默认参数(字典形式)
- 别名:可选的name参数
from django.conf.urls import url
urlpatterns = [
url(正则表达式, views视图函数,参数,别名),
]
(2)正则表达式详解
- 正则匹配一旦匹配成功则不再继续,因此可加
^
和$
进行精确配置 ^
:以···开头,控制路由后缀前面部分$
:以···结尾,控制路由后缀后面部分/
:用来控制防止路由后缀前缀相同,比如,r'test'
和r'testadd'
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'test/', views.test), # 路由后缀为qqqtest/qqq仍可访问
url(r'^test/', views.test), # 路由后缀为test/qqq仍可访问
url(r'test/$', views.test), # 路由后缀为qqqtest/仍可访问
url(r'^test/$', views.test), # 路由后缀为test/才可访问
]
(3)APPEND_SLASH
- settings.py文件中,没有此参数,但是默认参数APPEND_SLASH=True
- 作用:在浏览器发送请求时,检测到没有后缀
/
时,自动加上/
并重定向到该网址 - 可在settings.py文件中,最后一行,配置
APPEND_SLASH=False
来关掉此功能
(二)分组匹配
- 无名分组:将分组内正则表达式匹配到的内容以位置参数传给视图函数,
(pattern)
- 有名分组:将分组内正则匹配式匹配到的内容以关键字参数传给视图函数,
(?P<name>pattern)
- 无名和有名分组不能混用,但是同种分组可以使用多次
- 正则表达式匹配出的参数永远都是字符串
url(r'^test/([0-9]{4})/', views.test) # 无名分组
url(r'^testadd/(?P<year>\d+)/', views.testadd) # 有名分组
url(r'^index/(\d+)/(?P<year>\d+)/', views.index) # 不能混合使用,会报错
url(r'^index/(\d+)/(\d+)/', views.index), # 可以使用多次无名分组
url(r'^index/(?P<args>\d+)/(?P<year>\d+)/', views.index), # 可以使用多次有名分组
(三)反向解析
根据一个别名,动态解析出一个结果,该结果可以直接访问对应url
(1)正常匹配
url(r'^home/', views.home,name='xxx'), # 路由和函数起别名
前端反向解析(url)
<p><a href="{% url 'xxx' %}">111</a></p>
后端反向解析(reverse)
from django.shortcuts import render,HttpResponse,redirect,reverse url = reverse('xxx')
(2)无名分组匹配
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> <p><a href="{% url 'xxx' 14324 %}">111</a></p> <p><a href="{% url 'xxx' 1234 %}">111</a></p>
后端反向解析
手动传入的参数 只需要满足能够被正则表达式匹配到即可
url = reverse('xxx',args=(1,)) url1 = reverse('xxx',args=(3213,)) url2 = reverse('xxx',args=(2132131,))
(3)有名分组匹配
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})
(四)路由分发(include)
- 在django中,所有的app都可以有自己独立的urls,templates,static,因此,用django开发项目就可以完全做到多人分组开发,互相不干扰,每个人只开发自己的app
- 路由分发可以让总路由只做任务分发,具体的应用视图函数由应用的路由去做映射,从而解决项目的总路由匹配关系过多的问题
- 总路由分发时推荐使用
include('应用名.urls')
# 子路由1.py
from django.conf.urls import url
from app01 import views
urlpatterns = [
url('^reg/',views.reg)
]
# 子路由2.py
from django.conf.urls import url
from app02 import views
urlpatterns = [
url('^reg/',views.reg)
]
# 总路由.py
######## 第一种写法
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)),
]
######## 第二种写法(推荐写法)
urlpatterns = [
url(r'^app01/',include('app01.urls')),
url(r'^app02/',include('app02.urls'))
]
(五)别名冲突
当多个app中出现了别名冲突时,,会出现访问错乱的问题
(1)名称空间
路由分发的时候可以给每一个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>
(2)应用名前缀
起别名的时候统一加上应用名前缀
urlpatterns = [
url(r'^reg/',views.reg,name='app02_reg')
]
urlpatterns = [
url('^reg/',views.reg,name='app01_reg')
]
四、伪静态
将一个动态网页伪装成一个静态网页,以此来提升搜索引擎SEO查询频率和搜藏力度
urlpatterns = [
url('^reg.html',views.reg)
]
五、dangjo版本区别
(一)re_path
Django2.0中的re_path与django1.0的url一样,传入的第一个参数都是正则表达式
from django.urls import re_path # django2.0中的re_path
from django.conf.urls import url # 在django2.0中同样可以导入1.0中的url
urlpatterns = [
# 用法完全一致
url(r'^app01/', include(('app01.urls','app01'))),
re_path(r'^app02/', include(('app02.urls','app02'))),
]
(二)path
- Django2.0中新增了一个path功能,传入的第一个参数不是正则表达式
- 用来解决:数据类型转换问题与正则表达式冗余问题
(三)转换器
(1)内置转换器
- str:匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
- int:匹配正整数,包含0。
- slug,匹配字母、数字以及横杠、下划线组成的字符串。
- uuid:匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
- path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
path('articles/<int:year>/<int:month>/<slug:other>/', views.article_detail)
# 针对路径http://127.0.0.1:8000/articles/2009/123/hello/,path会匹配出参数year=2009,month=123,other='hello'传递给函数article_detail
(2)自定义转换器
可以自定义参数转换的精度或长度
在app01下新建文件path_ converters.py,文件名可以随意命名
class MonthConverter: regex='\d{2}' # 属性名必须为regex def to_python(self, value): return int(value) def to_url(self, value): return value # 匹配的regex是两个数字,返回的结果也必须是两个数字
在urls.py中,使用
register_converter
将其注册到URL配置中:from django.urls import path,register_converter from app01.path_converts import MonthConverter register_converter(MonthConverter,'mon') from app01 import views urlpatterns = [ path('articles/<int:year>/<mon:month>/<slug:other>/', views.article_detail,name='aaa'), ]