""" 表与表之间的关系 一对多 多对多 一对一 没有关系 判断表关系的方法:换位思考 """
我们以图书表,出版社表,作者表,以及作者详情表为例:
# 图书表 # 出版社表 # 作者表 # 作者详情表 """ 图书和出版社是一对多的关系,外键字段建在多的一方,图书是多的一方 图书和作者是多对多的关系,要建一个中间表book2author记录图书和作者的关系 作者表和作者详情表是一对一 """
settings.py,注释原有数据库配置
# 连接mysql数据库 DATABASES = { ‘default‘: { ‘ENGINE‘: ‘django.db.backends.mysql‘, ‘NAME‘: ‘day61‘, # name对应数据库的名字 ‘USER‘: ‘root‘, ‘PASSWORD‘: ‘123456‘, ‘HOST‘: ‘127.0.0.1‘, ‘PORT‘: 3306, ‘CHARSET‘: ‘utf8‘ } }
在项目或应用下的__init__.py中添加
import pymysql pymysql.install_as_MySQLdb()
models.py
from django.db import models # Create your models here. # 创建表关系 先将基表创建出来,然后再添加外键字段 # 图书表 class Book(models.Model): title = models.CharField(max_length=32,verbose_name="图书名") price = models.DecimalField(max_digits=8,decimal_places=2,verbose_name="价格") # max_digits=8,decimal_places=2:小数总共八位,小数点后面占两位 """ 图书和出版社是一对多关系,并且图书是多的一方,所以外键字段放在图书表里 """ publish = models.ForeignKey(to="Publish") #一对多表关系 #publish是和Publish表关联的外键字段,默认是和Publish表的主键id字段关联,也可以使用to_field="id"指定 """ 图书和作者是多对多关系,在ORM中不用手动创建中间表了,ORM会自动帮我们创建中间表,ORM中外键字段建在任意一方均可,但是推荐建在查询频率较高的一方
ps:
如果字段对应的是ForeignKey 那么orm会自动在字段后面加上_id后缀
如果你自己加上了_id那么orm还是会再自动在字段后面加上_id后缀
后面在定义ForeignKey的时候就不要自己加_id了 """ authors = models.ManyToManyField(to="Author") # 多对多表关系 """ authors 是一个虚拟字段,主要用来告诉ORM 图书表和作者表是多对多的关系 让ORM自动帮你创建第三方中间表 """ # 出版社 class Publish(models.Model): name = models.CharField(max_length=32,verbose_name="出版社名称") addr = models.CharField(max_length=32,verbose_name="出版社地址") # 作者 class Author(models.Model): name = models.CharField(max_length=32,verbose_name="姓名") age = models.IntegerField(verbose_name="年龄") """ 作者和作者详情是一对一关系,外键字段建在任意一方都可以,推荐建在查询频率较高的一方,这里外键建在作者表中 """ author_detail = models.OneToOneField(to="AuthorDetail") #一对一表关系
# OneToOneField也会自动给字段加_id后缀
#作者详情表 class AuthorDetail(models.Model): phone = models.BigIntegerField(verbose_name="手机号") addr = models.CharField(max_length=32,verbose_name="作者地址")
执行数据库迁移命令
# python3 manage.py makemigrations # python3 manage.py migrate
解释:
圈红圈的忽略:django自动创建的
# 图书表 class Book(models.Model): title = models.CharField(max_length=32,verbose_name="图书名") price = models.DecimalField(max_digits=8,decimal_places=2,verbose_name="价格") # max_digits=8,decimal_places=2:小数总共八位,小数点后面占两位 """ 图书和出版社是一对多关系,并且图书是多的一方,所以外键字段放在图书表里 """ publish = models.ForeignKey(to="Publish") #一对多表关系 #publish是和Publish表关联的外键字段,默认是和Publish表的主键id字段关联,也可以使用to_field="id"指定 """ 图书和作者是多对多关系,在ORM中不用手动创建中间表了,ORM会自动帮我们创建中间表,ORM中外键字段建在任意一方均可,但是推荐建在查询频率较高的一方 """ authors = models.ManyToManyField(to="Author") # 多对多表关系 """ authors 是一个虚拟字段,主要用来告诉ORM 图书表和作者表是多对多的关系 让ORM自动帮你创建第三方中间表 """
我们发现代码中加上id主键应该有五个字段(id、title、price、publish、authors)
但是在数据库表中只有(id、title、price、publish_id)
现在来解释:
为什么代码里写的外键名是publish,但是在数据库中是publish_id?
#ForeignKey 一对多外键 # OneToOneField 一对一外键 # 会自动在字段后面加_id后缀
为什么只有四个字段?
# 因为代码中authors是虚拟字段,主要用来告诉ORM 图书表和作者表是多对多的关系,让ORM自动帮你创建第三方中间表(就是多出来的表app01_book_authors)
# orm中如何定义三种关系 publish = models.ForeignKey(to=‘Publish‘) # 一对多,默认就是与出版社表的主键字段做外键关联,也可以使用to_field="id"指定 authors = models.ManyToManyField(to=‘Author‘) # 多对多表关系 author_detail = models.OneToOneField(to=‘AuthorDetail‘) # 一对一表关系 # ps: ForeignKey OneToOneField 会自动在字段后面加_id后缀
补充:
# 在django1.X版本中外键默认都是级联更新删除的 # 多对多的表关系可以有好几种创建方式 这里暂且先介绍一种
# 扩展知识点 """ 缓存数据库 提前已经将你想要的数据准备好了 你来直接拿就可以 提高效率和响应时间 当你在修改你的数据的时候 你会发现数据并不是立刻修改完成的 而是需要经过一段时间才会修改 博客园 了解即可 """
注意事项
1、惰性匹配
url(r‘test‘,views.test), url(r‘testadd‘,views.testadd) """ url方法第一个参数是正则表达式 只要第一个参数正则表达式能够匹配到内容 那么就会立刻停止往下匹配 直接执行对应的视图函数 """
示例:
urls.py
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r‘^admin/‘, admin.site.urls), # 路由匹配 url(r‘test‘, views.test), url(r‘testadd‘, views.testadd), ]
views.py
from django.shortcuts import render,HttpResponse,redirect # Create your views here. def test(request): return HttpResponse("test") def testadd(request): return HttpResponse("testadd")
浏览器访问时,输入的包含test就可访问
2、自动加斜杠
url(r‘test/‘, views.test), url(r‘testadd/‘, views.testadd), """ 你在输入url的时候会默认加斜杠 django内部帮你做到重定向 一次匹配不行 url后面加斜杠再来一次 """
urls.py
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r‘^admin/‘, admin.site.urls), # 路由匹配 url(r‘test/‘, views.test), url(r‘testadd/‘, views.testadd), ]
views.py
from django.shortcuts import render,HttpResponse,redirect # Create your views here. def test(request): return HttpResponse("test") def testadd(request): return HttpResponse("testadd")
浏览器输入:http://127.0.0.1:8000/testadd访问时
你也可以在settings.py配置文件中取消django自动加斜杠/的机制
在settings.py中添加下面代码即可:
# 取消自动加斜杠 APPEND_SLASH = False # True是开启
补充1:
url(r‘test/‘, views.test), url(r‘testadd/‘, views.testadd),
浏览器输入http://127.0.0.1:8000/dfsjfdjksjtest/也能访问test,因为正则可以匹配
解决:加^匹配开头...
url(r‘^test/‘, views.test), url(r‘^testadd/‘, views.testadd),
补充2、基于补充1
在浏览器输入http://127.0.0.1:8000/test/fafdsdfsfds还是能访问test
解决:加上$匹配结尾
url(r‘^test/$‘, views.test), url(r‘^testadd/$‘, views.testadd),
urls.py
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r‘^admin/‘, admin.site.urls), # 首页 url(r‘^$‘,views.home), # 推荐写法 ]
views.py
from django.shortcuts import render,HttpResponse,redirect # Create your views here. # 首页 def home(request): return HttpResponse("home")
浏览器访问:http://127.0.0.1:8000/
""" 分组:就是给某一段正则表达式用小括号扩起来 """
urls.py
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r‘^admin/‘, admin.site.urls), # 首页 url(r‘^$‘,views.home), # 分组 url(r‘^test/(\d+)‘, views.test), ]
views.py
from django.shortcuts import render,HttpResponse,redirect # Create your views here. # 首页 def home(request): return HttpResponse("home") def test(request): return HttpResponse("test")
此时浏览器访问
我们接收一下这个参数看看是什么
views.py
from django.shortcuts import render,HttpResponse,redirect # Create your views here. # 首页 def home(request): return HttpResponse("home") def test(request,xxx): print(xxx) return HttpResponse("test")
此时浏览器访问:http://127.0.0.1:8000/test/123
在后端查看打印信息:
因此我们发现:
# 无名分组 url(r‘^test/(\d+)‘, views.test), # 无名分组就是将括号内正则表达式匹配到的内容当作位置参数传递给后面的视图函数 # 视图函数 def test(request,xx): print(xx) return HttpResponse(‘test‘)
""" 可以给正则表达式起一个别名 """
urls.py
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r‘^admin/‘, admin.site.urls), # 首页 url(r‘^$‘,views.home), # 无名分组 url(r‘^test/(\d+)‘, views.test), # 有名分组 url(r‘^testadd/(?P<year>\d+)‘, views.testadd), # 给\d+这个表达式起了个别名year,这个year会传给视图函数testadd ]
views.py
from django.shortcuts import render,HttpResponse,redirect # Create your views here. # 首页 def home(request): return HttpResponse("home") def test(request,xxx): print(xxx) return HttpResponse("test") def testadd(request): return HttpResponse("testadd")
浏览器访问一下,看一下报错信息(testadd视图函数缺少一个关键字参数year)
我们给testadd视图函数加上year关键字参数year
views.py
from django.shortcuts import render,HttpResponse,redirect # Create your views here. # 首页 def home(request): return HttpResponse("home") def test(request,xxx): print(xxx) return HttpResponse("test") def testadd(request,year): print(year) return HttpResponse("testadd")
浏览器访问并在后端查看这个year关键字参数打印
因此我们发现:
url(r‘^testadd/(?P<year>\d+)‘,views.testadd) # 有名分组就是将括号内正则表达式匹配到的内容当作关键字参数传递给后面的视图函数 def testadd(request,year): print(year) return HttpResponse(‘testadd‘)
""" 两者不能混用 但是同一个分组可以使用N多次 """ # 单个的分组可以使用多次 url(r‘^index/(\d+)/(\d+)/(\d+)/‘,views.index), url(r‘^index/(?P<year>\d+)/(?P<age>\d+)/(?P<month>\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>
无论urls.py里面的匹配正则参数怎么改,通过home。html的a标签都能访问到func
urls.py
"""day61 URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.11/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r‘^$‘, views.home, name=‘home‘) Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r‘^$‘, Home.as_view(), name=‘home‘) Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r‘^blog/‘, include(‘blog.urls‘)) """ from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r‘^admin/‘, admin.site.urls), # 首页 url(r‘^$‘,views.home), # 无名分组 url(r‘^test/(\d+)‘, views.test), # 有名分组 url(r‘^testadd/(?P<year>\d+)‘, views.testadd), # 给\d+这个表达式起了个别名year,这个year会传给视图函数testadd # 反向解析 url(r‘^func‘, views.func,name="ooo") # 先给路由与视图函数关系起一个别名 ]
views.py
from django.shortcuts import render,HttpResponse,redirect # Create your views here. # 首页 def home(request): return render(request,"home.html") def test(request,xxx): print(xxx) return HttpResponse("test") def testadd(request,year): print(year) return HttpResponse("testadd") # 反向解析 def func(request): return HttpResponse("func")
home.html
html文件通过模板语法{% url "urls.py中设置的别名" %}
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <a href="{% url "ooo" %}">111</a> <a href="{% url "ooo" %}">222</a> <a href="{% url "ooo" %}">333</a> <a href="{% url "ooo" %}">444</a> <a href="{% url "ooo" %}">555</a> <a href="{% url "ooo" %}">666</a> <a href="{% url "ooo" %}">777</a> </body> </html>
from django.shortcuts import render,HttpResponse,redirect,reverse # Create your views here. # 首页 def home(request): # urls.py中的正则匹配怎么改这边都能通过别名接收到,注意要导入reverse模块 print(reverse("ooo")) # reverse("urls.py中设置的反向解析的名字") return render(request,"home.html")
原文:https://www.cnblogs.com/baicai37/p/12968649.html