django orm中如何创建表关系
""" 表与表之间的关系: 一对多 多对多 一对一 没有关系 判断表关系的方法:换位思考 """ 图书模型类(Book表) 出版社模型类(Publish表) 作者模型类(Author表) 作者详情模型类(AuthorDetail表) """ 图书和出版社是一对多的关系 外键字段建在多的那一方 book 图书和作者是多对多的关系 需要创建第三张表来专门存储 作者与作者详情表是一对一 """
在项目中的models.py文件中创建表关系,前提是要将数据库类型换成mysql:
from django.db import models # Create your models here. # 创建表关系 先将基表创建出来 然后再添加外键字段 # 图书模型类(Book表) class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) # 总共八位 小数点后面占两位 """ 图书和出版社是一对多 并且书是多的一方 所以外键字段放在书表里面 """ publish = models.ForeignKey(to='Publish') # 默认就是与出版社表的主键字段做外键关联 """ 如果字段对应的是ForeignKey 那么会orm会自动在字段的后面加_id """ """ 图书和作者是多对多的关系 外键字段建在任意一方均可 但是推荐你建在查询频率较高的一方 """ authors = models.ManyToManyField(to='Author') """ authors是一个虚拟字段 主要是用来告诉orm 书籍表和作者表是多对多关系 让orm自动帮你创建第三张关系表 """ # 出版社模型类(Publish表) class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=32) # 作者模型类(Author表) class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() """ 作者与作者详情是一对一的关系 外键字段建在任意一方都可以 但是推荐你建在查询频率较高的表中 """ author_detail = models.OneToOneField(to='AuthorDetail') """ OneToOneField也会自动给字段加_id后缀 所以你也不要自作聪明的自己加_id """ # 作者详情模型类(AuthorDetail表) class AuthorDetail(models.Model): phone = models.BigIntegerField() # 或者直接字符类型 addr = models.CharField(max_length=32) """ orm中如何定义三种关系 1、publish = models.ForeignKey(to='Publish') # 默认就是与出版社表的主键字段做外键关联 2、authors = models.ManyToManyField(to='Author') 3、author_detail = models.OneToOneField(to='AuthorDetail') ForeignKey、OneToOneField(会自动在字段后面加_id后缀) """ # 在django1.X版本中外键默认都是级联更新删除的 # 多对多的表关系可以有好几种创建方式 这里暂且先介绍一种 # 针对外键字段里面的其他参数 暂时不要考虑 如果感兴趣自己可以百度试试看
django请求生命流程图(重点)
这个图是后期复习django最好的一个梳理方式
图来自:https://www.cnblogs.com/guanxiying/p/12966067.html
路由层
路由匹配
url(r'test/',views.test), url(r'^$',views.testadd) """ url方法第一个参数是正则表达式 只要第一个参数正则表达式能够匹配到内容 那么就会立刻停止往下匹配 直接执行对应的视图函数 在输入url的时候会默认加斜杠 django内部帮你做到重定向 一次匹配不行 url后面加斜杠再来一次 """ # 取消自动加斜杠匹配 APPEND_SLASH = False/True # 默认是自动加斜杠的(True) urlpatterns = [ url(r'^admin/', admin.site.urls), # 首页 url(r'^$',views.home), # 路由匹配 url(r'^test/$',views.test), url(r'^testadd/$',views.testadd), # 尾页(了解) url(r'',views.error), ]
无名分组
""" 分组:就是给某一段正则表达式用小括号扩起来 """ url(r'^test/(d+)/',views.test) def test(request,xx): print(xx) return HttpResponse('test') # 无名分组就是将括号内正则表达式匹配到的内容当作位置参数传递给后面的视图函数
有名分组
""" 可以给正则表达式起一个别名 """ url(r'^testadd/(?P<year>d+)',views.testadd) def testadd(request,year): print(year) return HttpResponse('testadd') # 有名分组就是将括号内正则表达式匹配到的内容当作关键字参数传递给后面的视图函数
单个分组的多次使用
'''注意:无名分组与又名分组不能同时混合使用''' # 单个分组可以使用多次 url(r'^index/(d+)/(d+)/(d+)/...', views.index), url(r'^index/(?P<year>d+)/(?P<month>d+)/(?P<day>d+)/...', views.index),
反向解析
# 通过一些方法得到一个结果 该结果可以直接访问对应的url触发视图函数 # 先给路由与视图函数起一个别名 url(r'^func_kkk/',views.func,name='ooo') # 反向解析 # 后端反向解析 from django.shortcuts import render,HttpResponse,redirect,reverse reverse('ooo') # 前端反向解析 <a href="{% url 'ooo' %}">111</a>
无名有名分组反向解析
无名分组反向解析
# 反向解析的本质:通过一些方法得到一个结果,该结果可以访问到对应的url从而触发视图函数的运行 # 无名分组反向解析 # 路由层 url(r'index/(d+)/', views.index,name='xxx') # 前端 # {% url 'xxx' %} 同样会报相同的错误 {% url 'xxx' 123 %} # 后端 # reverse('xxx') 直接写会报错,必须要手动指定一个参数能够被d+匹配到 reverse('xxx', args=(1, ))
有名分组反向解析
# 有名分组反向解析 # 路由层 url(r'^func/(?P<year>d+)/',views.func,name='ooo') # 前端 <a href="{% url 'ooo' year=123 %}">111</a> # 了解 <a href="{% url 'ooo' 123 %}">222</a> # 记忆 # 后端 # 正规写法 了解 print(reverse('ooo',kwargs={'year':123})) # 简便的写法 记忆 print(reverse('ooo',args=(111,)))
数字代码具体使用
# 数字一般情况下放的是数据的主键值 方便数据的编辑和删除 url(r'^edit/(d+)/',views.edit,name='xxx') def edit(request,edit_id): reverse('xxx',args=(edit_id,)) {%for user_obj in user_queryset%} <a href="{% url 'xxx' user_obj.id %}">编辑</a> {%endfor%}
路由分发
路由分发:能够实现一个人写一个功能应用,最后直接通过路由分发来将功能应用整合到一起,只需要访问不同的url前缀就能够访问对应功能应用下的资源
django的每一个应用都可以有自己的templates文件夹、urls.py 、static文件夹 正是基于上述的特点 django能够非常好的做到分组开发(每个人只写自己的app)
''' 路由分发的优点: 1、一个人写一个功能应用,整合时只需要将对应的app的路由加到总路由中即可(项目多人开发) 2、当一个django项目中url特别多的时候,为了减轻总路由的压力,便于维护,也可以使用路由分发 3、路由分发之后,总路由不再与视图函数有直接对应关系,所有的资源访问请求都转交给对应的app来处理 ''' # 总路由 # 方式一: from django.conf.urls import url,include from django.contrib import admin from app01 import urls as app01_urls from app02 import urls as app02_urls urlpatterns = [ url(r'^admin/', admin.site.urls), # 路由分发 url(r'^app01/', include(app01_urls)), # 只要url前缀是app01开头,全都交给app01处理 url(r'^app02/', include(app02_urls)), # 只要url前缀是app02开头,全都交给app02处理 ] # 方式二: from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), '''注意:总路由的url千万不要加$结尾'''(推荐使用) url(r'^app01/', include('app01.urls')), url(r'^app02/', include('app02.urls')), ] # 子路由 app01 urls.py from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^reg/', views.reg) ] # 子路由 app02 urls.py from django.conf.urls import url from app02 import views urlpatterns = [ url(r'^reg/', views.reg) ]
名称空间(了解)
当多个应用出现相同别名时,正常情况下反向解析无法自动始别前缀,可以利用名称空间来解析
# 名称空间 # 总路由 url(r'^app01/', include('app01.urls',namespace='app01')), url(r'^app02/', include('app02.urls',namespace='app02')), # 解析的时候 # app01 urlpatterns = [ url(r'^reg/',views.reg,name='reg') ] # app02 urlpatterns = [ url(r'^reg/',views.reg,name='reg') ] # 视图函数使用:reverse('app01:reg')、reverse('app02:reg') # 前端页面使用:{% url 'app01:reg' %}、{% url 'app02:reg' %} # 只要保证名字不冲突就没有必要使用名称空间 ''' 一般情况下,有多个app时在起别名时会加上app的前缀,这样就能够保证多个app之间名字不冲突 ''' # 子路由下: urlpatterns = [ url(r'^reg/',views.reg,name='app01_reg') ] urlpatterns = [ url(r'^reg/',views.reg,name='app02_reg') ] # 视图函数直接使用别名即可
伪静态(了解)
''' 静态网页:数据是写死的 伪静态:将一个动态网页伪装成静态网页 伪装的目的:增大网站的seo查询力度,增加了搜索引擎收藏网站的概率 搜索引擎本质上就是一个巨大的爬虫程序 ''' urlpatterns = [ url(r'reg.html/', views.reg, name='app02_reg') ]
虚拟环境
''' 正常开发中,我们会给每个项目配备独有的解释器环境用来安装只有该项目内使用的模块,用不到的一概不装 虚拟环境就是单独的python解释器环境,每创建一个虚拟环境就相当于重新下载了一个全新的python解释器 扩展: 如何批量安装模块 开发当中我们会给每一个项目配备一个requirements.txt文件 里面书写了该项目所有的模块即版本 只需要直接输入一条命令即可一键安装所有模块即版本 '''
django版本区别
1、路由层使用方法 django1:url(),第一个参数支持正则 django2、django3:path(),第一个参数不支持正则,写什么就匹配什么 re_path()支持正则,就类似django1的url() 2、django2、django3的path()提供了五种转换器以及能够自定义转换器 3、级联删除更新 django1:默认自动级联删除更新 django2、django3:需要自己手动设置参数来实现级联删除更新 on_update=models.CASCADE on_delete=models.CASCADE
路由层的方法使用不同
# django1.X路由层使用的是url方法 url()第一个参数支持正则 # django2.X、3.X版本中路由层使用的是path方法 path()第一个参数是不支持正则的 写什么就匹配什么 re_path()就等价于1.X中的url from django.urls import path, re_path from django.conf.urls import url re_path(r'^index/',index), url(r'^login/',login) # 2.X和3.X里面的re_path就等价于1.X里面的url
path内部的转换器
虽然path不支持正则 但是它的内部支持五种转换器 path('index/<int:id>/',index) # 将第二个路由里面的内容先转成整型然后以关键字的形式传递给后面的视图函数 def index(request,id): print(id,type(id)) return HttpResponse('index') ''' str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式 int,匹配正整数,包含0。 slug,匹配字母、数字以及横杠、下划线组成的字符串。 uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。 path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?) '''
自定义转换器
class MonthConverter: # 固定写法 regex='d{2}' # 属性名必须为regex def to_python(self, value): return int(value) def to_url(self, value): return value # 匹配的regex是两个数字,返回的结果也必须是两个数字 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'), ]
模型层中
1.X外键默认都是级联更新删除的
models.ForeignKey(to='Publish')
2.X和3.X中需要你自己手动配置参数
models.ForeignKey(to='Publish')
models.ForeignKey(to='Publish',on_delete=models.CASCADE...)