Django ORM中创建表关系
"""表与表之间的关系一对多多对多一对一没有关系判断表关系的方法:换位思考"""
我们以图书表,出版社表,作者表,以及作者详情表为例:
# 图书表# 出版社表# 作者表# 作者详情表"""图书和出版社是一对多的关系,外键字段建在多的一方,图书是多的一方图书和作者是多对多的关系,要建一个中间表book2author记录图书和作者的关系作者表和作者详情表是一对一"""
Django连接数据库
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 pymysqlpymysql.install_as_MySQLdb()
创建模型类:ps:django1.11.11中orm创建的外键字段默认就是级联更新、级联删除的
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自动创建的
app01_author:作者表
app01_authordetail:作者详情表
app01_book:图书表
# 图书表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)
app01_book_authors:这是django自动帮我们创建的图示表与作者表之间的中间表
app01_publish:出版社表
orm表与表关系创建总结
# orm中如何定义三种关系publish = models.ForeignKey(to='Publish') # 一对多,默认就是与出版社表的主键字段做外键关联,也可以使用to_field="id"指定authors = models.ManyToManyField(to='Author') # 多对多表关系author_detail = models.OneToOneField(to='AuthorDetail') # 一对一表关系# ps:ForeignKeyOneToOneField会自动在字段后面加_id后缀
补充:
# 在django1.X版本中外键默认都是级联更新删除的# 多对多的表关系可以有好几种创建方式 这里暂且先介绍一种
补充2:
"""一对多models.ForeignKey(to='关联表名') 常用models.ForeignKey(to=关联表名) 关联表名必须出现在上方(了解即可)1.在django1.X版本中外键默认就是级联更新删除的2.会自动给字段加_id后缀 无论你有没有加(自己不要自作聪明的加上)3.一对多 外键字段建在多的一方一对一models.OneToOneField(to='关联表名')1.在django1.X版本中外键默认就是级联更新删除的2.会自动给字段加_id后缀 无论你有没有加(自己不要自作聪明的加上)3.外键建在任意一方均可 但是推荐你建在查询频率较高的表中(orm查询方便)多对多models.ManyToManyField(to='关联表名')1.在django1.X版本中外键默认就是级联更新删除的2.该字段是一个虚拟字段不会真正的在表中展示出来 而是用来告诉Django orm当前表和关联表是多对多的外键关系 需要自动创建第三张关系表3.在Django orm中多对多的表关系有好几种(三种)创建方式4.外键建在任意一方均可 但是推荐你建在查询频率较高的表中(orm查询方便)判断表关系的方式:换位思考"""
Django请求周期流程图(必会)

# 扩展知识点"""缓存数据库提前已经将你想要的数据准备好了 你来直接拿就可以提高效率和响应时间当你在修改你的数据的时候 你会发现数据并不是立刻修改完成的而是需要经过一段时间才会修改博客园了解即可"""
Django 每个部分详解
路由层
from django.conf.urls import urlurlpatterns = [url(正则表达式, views视图函数,参数,别名),]
示例:
from django.conf.urls import urlurlpatterns = [url("", views.index,{"name":"lqz"}), # 这样在视图层index函数就能接收到传的{"name":"lqz"}]# 视图层def index(request,name):print(name)return HttpResponse("ok")
路由匹配
注意事项
1、惰性匹配
url(r'test',views.test),url(r'testadd',views.testadd)"""url方法第一个参数是正则表达式只要第一个参数正则表达式能够匹配到内容 那么就会立刻停止往下匹配直接执行对应的视图函数"""
示例:
urls.py
from django.conf.urls import urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [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 urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [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")views.py
浏览器输入: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 urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [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 urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [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 urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [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,reversereverse('ooo')# 前端反向解析<a href="{% url 'ooo' %}">111</a>
不包含分组的反向解析
前端反向解析示例:
无论urls.py里面的匹配正则参数怎么改,通过别名ooo。html的a标签都能访问到func
urls.py:注意别名不能出现冲突
from django.conf.urls import urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [url(r'^admin/', admin.site.urls),# 反向解析url(r'^func', views.func,name="ooo") # 先给路由与视图函数关系起一个别名]
views.py
from django.shortcuts import render,HttpResponse,redirect# Create your views here.# 反向解析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>
后端反向解析示例(views.py需要导入reverse)
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")
无名、有名分组的反向解析
无名分组反向解析
urls.py
from django.conf.urls import urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [url(r'^admin/', admin.site.urls),# 首页url(r'^$', views.home),# 无名分组反向解析url(r'^index/(\d+)/', views.index,name="ooo"),]
views.py
from django.shortcuts import render,HttpResponse,redirect,reverse# Create your views here.# indexdef index(request,args):print(args)return HttpResponse("index")def home(request):print(reverse("ooo",args=(1,))) # 后端写法,这个打印的是url路径,如果想跳转得url = reverse("ooo",args=(1,))然后return redirect(url)return render(request,"home.html")
home.html:前端书写
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><!--无名分组反向解析前端写法--><a href="{% url "ooo" 123 %}">123</a></body></html>
补充:
# 关于url模板语法中123,是依据路由层分组匹配规则而写的# 无名分组反向解析url(r'^index/(\d+)/', views.index,name="ooo"),"""这个数字写代码的时候应该放什么数字一般情况下放的是数据的主键值 数据的编辑和删除"""# 可以将url中的123换成模板语法的变量(不过变量不需要{{}},直接写就好了)# 例如:{%for user_obj in user_queryset%}<a href="{% url 'ooo' user_obj.id %}">编辑</a>{%endfor%}
有名分组反向解析
urls.py
from django.conf.urls import urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [url(r'^admin/', admin.site.urls),# 首页url(r'^$', views.home), # 有名分组反向解析url(r'^func/(?P<year>\d+)/', views.func,name="xxx"),]
views.py
from django.shortcuts import render,HttpResponse,redirect,reverse# Create your views here.# 有名分组def func(request,year):print(year)return HttpResponse("func")def home(request):# 有名分组反向解析后端写法1,和无名分组一样,提供一个满足匹配规则的数字print(reverse("xxx",args=(1,))) #推荐写法# 有名分组反向解析后端写法2:# print(reverse("xxx",kwargs={"year":123})) #正规写法return render(request,"home.html")
home.html
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><!--前端有名分组反向解析--><!--正规写法-->{#<a href="{% url "xxx" year=123 %}">123</a>#}<!--推荐写法,因为这个写法和无名分组一样,好记--><a href="{% url "xxx" 123 %}">123</a></body></html>
路由分发
"""django的每一个应用都可以有自己的templates文件夹 urls.py static文件夹正是基于上述的特点 django能够非常好的做到分组开发(每个人只写自己的app)作为组长 只需要将手下书写的app全部拷贝到一个新的django项目中 然后在配置文件里面注册所有的app再利用路由分发的特点将所有的app整合起来当一个django项目中的url特别多的时候 总路由urls.py代码非常冗余不好维护这个时候也可以利用路由分发来减轻总路由的压力利用路由分发之后 总路由不再干路由与视图函数的直接对应关系而是做一个分发处理识别当前url是属于哪个应用下的 直接分发给对应的应用去处理"""
环境简述:

项目中有两个应用(app01,app02),现在通过在项目的urls.py中配置路由分发到每个应用的urls.py
ps:
应用中的urls.py文件是开发这个应用的自己写的,默认没有的,需要自己建
第一种实现:
day62\day62\urls.py:总路由
注意事项:
总路由的第一个参数不要加符就不再往后面匹配了,例如:url(r’^app01/$’,include(app01_urls)),
from django.conf.urls import url,includefrom django.contrib import adminfrom app01 import urls as app01_urlsfrom app02 import urls as app02_urlsurlpatterns = [url(r'^admin/', admin.site.urls),# 总路由中,路由分发,注意,需要导入一个include方法url(r'^app01/',include(app01_urls)), # 只要url前缀是app01开头,全部交给app01处理url(r'^app02/',include(app02_urls)), # 只要url前缀是app02开头,全部交给app02处理 # 注意事项:总路由里面的url千万不能加$符结尾]
app01\urls.py
from django.conf.urls import urlfrom app01 import viewsurlpatterns = [url(r'^reg/', views.reg),]
app02\urls.py
from django.conf.urls import urlfrom app02 import viewsurlpatterns = [url(r'^reg/', views.reg),]
app01\views.py
from django.shortcuts import render,HttpResponse,redirect# Create your views here.def reg(request):return HttpResponse("app01:reg")
app02\views.py
from django.shortcuts import render,redirect,HttpResponse# Create your views here.def reg(request):return HttpResponse("app02:reg")
浏览器访问:http://127.0.0.1:8000/app01/reg/


第二种实现:终极写法,推荐使用
day62\day62\urls.py:总路由
from django.conf.urls import url,includefrom django.contrib import adminurlpatterns = [url(r'^admin/', admin.site.urls),# 总路由中,路由分发,注意,需要导入一个include方法url(r'^app01/',include("app01.urls")),url(r'^app02/',include("app02.urls")),]
app01\urls.py
from django.conf.urls import urlfrom app01 import viewsurlpatterns = [url(r'^reg/', views.reg),]
app02\urls.py
from django.conf.urls import urlfrom app02 import viewsurlpatterns = [url(r'^reg/', views.reg),]
app01\views.py
from django.shortcuts import render,HttpResponse,redirect# Create your views here.def reg(request):return HttpResponse("app01:reg")
app02\views.py
from django.shortcuts import render,redirect,HttpResponse# Create your views here.def reg(request):return HttpResponse("app02:reg")
路由分发的本质
urls.py
# 路由分发本质 include 可以无限制的嵌套N多层url(r'^index/',([],None,None))# 示例:from django.conf.urls import urlfrom django.contrib import adminfrom app01 import viewsurlpatterns = [url(r'^admin/', admin.site.urls),url(r'^index/',([url(r'^index_1/',([url(r'^index_1_1',views.index),url(r'^index_1_2',views.index),url(r'^index_1_3',views.index),],None,None)),url(r'^index_2/',views.index),url(r'^index_3/',views.index),],None,None)),]
views.py
from django.shortcuts import render, HttpResponse,redirectdef index(request):return HttpResponse("ok")
浏览器访问

名称空间
# 当多个应用出现了相同的别名 反向解析不会自动识别应用前缀
环境:
接着上面路由分发的环境,有两个应用,考虑到两个应用中urls.py里面起别名冲突的情况,想正常使用反向解析的解决方案(就可以用名称空间)
应用别名冲突情况下:
day62\day62\urls.py:总路由
from django.conf.urls import url,includefrom django.contrib import adminurlpatterns = [url(r'^admin/', admin.site.urls),# 总路由中,路由分发,注意,需要导入一个include方法url(r'^app01/',include("app01.urls",namespace="app01")),url(r'^app02/',include("app02.urls",namespace="app02")),]
app01\urls.py
from django.conf.urls import urlfrom app01 import viewsurlpatterns = [url(r'^reg/', views.reg,name="reg"), # 别名和app02冲突]
app02\urls.py
from django.conf.urls import urlfrom app02 import viewsurlpatterns = [url(r'^reg/', views.reg,name="reg"),]
app01\views.py
from django.shortcuts import render,HttpResponse,redirect,reverse# Create your views here.def reg(request):# 此时冲突的情况下后端使用反向解析,使用名称空间解析print(reverse("app01:reg")) # /app01/reg/return HttpResponse("app01:reg")
app02\views.py
from django.shortcuts import render,redirect,HttpResponse,reverse# Create your views here.def reg(request):# 此时反向解析,使用名称空间解析print(reverse("app02:reg")) # /app02/reg/return HttpResponse("app02:reg")
此时前端使用反向解析示例:
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body>{% url "app01:reg" %}{% url "app02:reg" %}</body></html>
总结:为什么要用名称空间,就是因为应用别名冲突了,所以,我们如果起别名的时候保证不冲突就不用使用名称空间了
"""一般情况下 有多个app的时候我们在起别名的时候会加上app的前缀这样的话就能够确保多个app之间名字不冲突的问题"""
day62\day62\urls.py:总路由
from django.conf.urls import url,includefrom django.contrib import adminurlpatterns = [url(r'^admin/', admin.site.urls),# 总路由中,路由分发,注意,需要导入一个include方法url(r'^app01/',include("app01.urls")),url(r'^app02/',include("app02.urls")),]
app01\urls.py
from django.conf.urls import urlfrom app01 import viewsurlpatterns = [url(r'^reg/', views.reg,name="app01_reg"),]
app02\urls.py
from django.conf.urls import urlfrom app02 import viewsurlpatterns = [url(r'^reg/', views.reg,name="app02_reg"),]
app01\views.py
from django.shortcuts import render,HttpResponse,redirect,reverse# Create your views here.def reg(request):# 此时反向解析,使用名称空间解析print(reverse("app01_reg")) # /app01/reg/return HttpResponse("app01:reg")
app02\views.py
from django.shortcuts import render,redirect,HttpResponse,reverse# Create your views here.def reg(request):# 此时反向解析,使用名称空间解析print(reverse("app02_reg")) # /app02/reg/return HttpResponse("app02:reg")
不冲突情况下前端正常使用反向解析:
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body>{% url "app01_reg" %}{% url "app02_reg" %}</body></html>
伪静态
"""静态网页数据是写死的 万年不变伪静态将一个动态网页伪装成静态网页为什么要伪装呢?https://www.cnblogs.com/Dominic-Ji/p/9234099.html伪装的目的在于增大本网站的seo查询力度并且增加搜索引擎收藏本网上的概率搜索引擎本质上就是一个巨大的爬虫程序总结:无论你怎么优化 怎么处理始终还是干不过RMB玩家"""
Django怎么实现伪静态:
例如在app01中如下配置:
from django.conf.urls import urlfrom app01 import viewsurlpatterns = [url(r'^reg.html', views.reg),]
app01\views.py
from django.shortcuts import render,HttpResponse,redirect# Create your views here.def reg(request):return HttpResponse("app01:reg")
在浏览器访问

虚拟环境
"""在正常开发中 我们会给每一个项目配备一个该项目独有的解释器环境该环境内只有该项目用到的模块 用不到一概不装linux:缺什么才装什么虚拟环境你每创建一个虚拟环境就类似于重新下载了一个纯净的python解释器但是虚拟环境不要创建太多,是需要消耗硬盘空间的扩展:每一个项目都需要用到很多模块 并且每个模块版本可能还不一样那我该如何安装呢? 一个个看一个个装???开发当中我们会给每一个项目配备一个requirements.txt文件里面书写了该项目所有的模块即版本你只需要直接输入一条命令即可一键安装所有模块即版本ps:requirements.txt使用# pip3 install -r requirements.txt #安装requirements.txt依赖# 生成requirements.txt文件 (在项目根目录下执行)# pip3 freeze > requirements.txt# 使用# pip install -r requirements.txt"""
创建虚拟环境步骤:
1、pycharm-file-New Project

2、创建完成(标志venv文件夹)

Django1.x和2.x版本区别
"""1.django1.X路由层使用的是url方法而在django2.X和3.X版本中路由层使用的是path方法url()第一个参数支持正则path()第一个参数是不支持正则的 写什么就匹配什么如果你习惯使用path那么也给你提供了另外一个方法re_path就和url一样,django2.x和django3.x中还是支持url的不过不推荐使用(也不合理)from django.urls import path, re_path # django2.x和3.x正确使用方法from django.conf.urls import url # url能够使用,但不推荐(容易让人版本混淆)re_path(r'^index/',index),url(r'^login/',login)2.X和3.X里面的re_path就等价于1.X里面的url2.虽然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,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)3.除了有默认的五个转换器之外 还支持自定义转换器(了解)# ================自定义转换器==================================# app01.path_converts中class MonthConverter:regex='\d{2}' # 属性名必须为regexdef to_python(self, value):return int(value)def to_url(self, value):return value # 匹配的regex是两个数字,返回的结果也必须是两个数字# urls.py中注册转换器from django.urls import path,register_converterfrom app01.path_converts import MonthConverterfrom app01 import viewsregister_converter(MonthConverter,'mon')urlpatterns = [path('articles/<int:year>/<mon:month>/<slug:other>/', views.article_detail, name='aaa'),]4.模型层里面1.X外键默认都是级联更新删除的models.ForeignKey(to='Publish')但是到了2.X和3.X中需要你自己手动配置参数models.ForeignKey(to='Publish',on_delete=models.CASCADE)on_delete其他选项CASCADE:删除作者信息一并删除作者名下的所有书的信息;PROTECT:删除作者的信息时,采取保护机制,抛出错误:即不删除Books的内容;SET_NULL:只有当null=True才将关联的内容置空;SET_DEFAULT:设置为默认值;SET( ):括号里可以是函数,设置为自己定义的东西;DO_NOTHING:啥也不干"""
视图层:
三板斧:
"""HttpResponse返回字符串类型render返回html页面 并且在返回给浏览器之前还可以给html文件传值redirect重定向"""# 视图函数必须要返回一个HttpResponse对象 正确 研究三者的源码即可得处结论The view app01.views.index didn't return an HttpResponse object. It returned None instead.# render简单内部原理from django.template import Template,Contextres = Template('<h1>{{ user }}</h1>')con = Context({'user':{'username':'jason','password':123}})ret = res.render(con)print(ret)return HttpResponse(ret)
JsonResponse对象
"""json格式的数据有什么用?前后端数据交互需要使用到json作为过渡 实现跨语言传输数据前端序列化JSON.stringify() json.dumps()JSON.parse() json.loads()"""
JsonResponese使用示例:传字典
项目urls.py
from django.conf.urls import url,includefrom django.contrib import adminurlpatterns = [url(r'^admin/', admin.site.urls),# 总路由中,路由分发,注意,需要导入一个include方法url(r'^app01/',include("app01.urls")),url(r'^app02/',include("app02.urls")),]
app01\urls.py
from django.conf.urls import urlfrom app01 import viewsurlpatterns = [url(r'^reg.html', views.reg,name="app01_reg"),url(r'^ab_json/', views.ab_json),]
app01/views.py
from django.shortcuts import render,HttpResponse,redirect,reversefrom django.http import JsonResponse # 使用JsonRespone时需要导入JsonResponse模块def ab_json(request):# 使用JsonRespone时需要导入JsonResponse模块user_dict = {"username":"王xx","password":"123","hobby":"girl"}return JsonResponse(user_dict,json_dumps_params={"ensure_ascii":False})
浏览器访问:

JsonResponese使用示例:传列表
注意:默认只能序列化字典,序列化非字典的对象时,要将safe选项改为False
项目urls.py
from django.conf.urls import url,includefrom django.contrib import adminurlpatterns = [url(r'^admin/', admin.site.urls),# 总路由中,路由分发,注意,需要导入一个include方法url(r'^app01/',include("app01.urls")),url(r'^app02/',include("app02.urls")),]
app01\urls.py
from django.conf.urls import urlfrom app01 import viewsurlpatterns = [url(r'^reg.html', views.reg,name="app01_reg"),url(r'^ab_json/', views.ab_json),]
app01/views.py
from django.shortcuts import render,HttpResponse,redirect,reversefrom django.http import JsonResponse # 使用JsonRespone时需要导入JsonResponse模块def ab_json(request):# 使用JsonRespone时需要导入JsonResponse模块l = [111,333,444,222,"爱我中华"]return JsonResponse(l,json_dumps_params={"ensure_ascii":False},safe=False)
浏览器访问:

form表单上传文件及后端获取
"""form表单上传文件类型的数据1.method必须指定成post2.enctype必须换成multipart/form-data"""
项目urls.py
from django.conf.urls import url,includefrom django.contrib import adminurlpatterns = [url(r'^admin/', admin.site.urls),# 总路由中,路由分发,注意,需要导入一个include方法url(r'^app01/',include("app01.urls")),url(r'^app02/',include("app02.urls")),]
app01\urls.py
from django.conf.urls import urlfrom app01 import viewsurlpatterns = [url(r'^reg.html', views.reg,name="app01_reg"),url(r'^ab_json/', views.ab_json),# 上传文件url(r'^ab_file/', views.ab_file),]
app01/views.py
from django.shortcuts import render,HttpResponse,redirect,reversefrom django.http import JsonResponse # 使用JsonRespone时需要导入JsonResponse模块# Create your views here.def reg(request):# 此时反向解析,使用名称空间解析print(reverse("app01_reg")) # /app01/reg/return HttpResponse("app01:reg")def ab_json(request):# 使用JsonRespone时需要导入JsonResponse模块l = [111,333,444,222,"爱我中华"]return JsonResponse(l,json_dumps_params={"ensure_ascii":False},safe=False)# 上传文件def ab_file(request):if request.method == "POST":# print(request.POST) # 只能获取普通的键值对数据,不包含文件print(request.FILES) # 获取文件数据# <MultiValueDict: {'file': [<InMemoryUploadedFile: 下载.jpg (image/jpeg)>]}># 获得文件方法和POST、GET一样使用.get()方法file_obj = request.FILES.get("file") # 文件对象print(file_obj.name) # 获取上传文件的文件名 eg:下载.jpg# 保存文件with open(file_obj.name,'wb') as f:for line in file_obj: # 类似与一行行的读取文件,官方推荐使用for line in file_obj.chunks()然后写文件f.write(line)return render(request,"form.html")
总结:request对象方法
"""request.methodrequest.POSTrequest.GET: http://127.0.0.1:8000/index/123?name=lqz&age=18 name=lqz&age=18会被转成字典,放到GET中request.FILESrequest.body # 原生的浏览器发过来的二进制数据 后面详细的讲request.META:HTTP请求的其他东西,放在里面,入客户端ip地址:REMOTE_ADDRrequest.pathrequest.path_inforequest.get_full_path() 能过获取完整的url及问号后面的参数request.FILES:上传的文件request.session:用的session"""print(request.path) # /app01/ab_file/print(request.path_info) # /app01/ab_file/print(request.get_full_path()) # /app01/ab_file/?username=jason
参考链接:
https://www.cnblogs.com/liuqingzheng/articles/9509801.html#_label1
FBV与CBV
视图函数既可以是函数也可以是类
我们之前在views.py写的函数就是FBV
def index(request):return HttpResponse('index')
CBV就是用类来写视图函数
CBV示例:
项目urls.py
from django.conf.urls import url,includefrom django.contrib import adminurlpatterns = [url(r'^admin/', admin.site.urls),# 总路由中,路由分发,注意,需要导入一个include方法url(r'^app01/',include("app01.urls")),url(r'^app02/',include("app02.urls")),]
app01\urls.py
from django.conf.urls import urlfrom app01 import viewsurlpatterns = [# CBV路由url(r'^login/', views.MyLogin.as_view()), # 注意as_view一定要加括号]
app01\views.py
from django.shortcuts import render,HttpResponse,redirect,reversefrom django.views import View # 使用CBV需要导入View模块,让类继承# Create your views here.class MyLogin(View): # 要继承导入的View模块def get(self,request):return HttpResponse("get方法")def post(self,request):return HttpResponse("post方法")
浏览器访问

总结:
"""FBV和CBV各有千秋CBV特点能够直接根据请求方式的不同直接匹配到对应的方法执行"""
CBV源码刨析
# 你自己不要修改源码 除了bug很难找# 突破口在urls.pyurl(r'^login/',views.MyLogin.as_view())# url(r'^login/',views.view) FBV一模一样# CBV与FBV在路由匹配上本质是一样的 都是路由 对应 函数内存地址"""函数名/方法名 加括号执行优先级最高猜测as_view()要么是被@staicmethod修饰的静态方法要么是被@classmethod修饰的类方法 正确@classonlymethoddef as_view(cls, **initkwargs):pass"""@classonlymethoddef as_view(cls, **initkwargs):"""cls就是我们自己写的类 MyCBVMain entry point for a request-response process."""def view(request, *args, **kwargs):self = cls(**initkwargs) # cls是我们自己写的类# self = MyLogin(**initkwargs) 产生一个我们自己写的类的对象return self.dispatch(request, *args, **kwargs)"""以后你们会经常需要看源码 但是在看python源码的时候 一定要时刻提醒自己面向对象属性方法查找顺序先从对象自己找再去产生对象的类里面找之后再去父类找...总结:看源码只要看到了self点一个东西 一定要问你自己当前这个self到底是谁"""return view# CBV的精髓def dispatch(self, request, *args, **kwargs):# 获取当前请求的小写格式 然后比对当前请求方式是否合法# get请求为例# post请求if request.method.lower() in self.http_method_names:handler = getattr(self, request.method.lower(), self.http_method_not_allowed)"""反射:通过字符串来操作对象的属性或者方法handler = getattr(自己写的类产生的对象,'get',当找不到get属性或者方法的时候就会用第三个参数)handler = 我们自己写的类里面的get方法"""else:handler = self.http_method_not_allowedreturn handler(request, *args, **kwargs)"""自动调用get方法"""# 要求掌握到不看源码也能够描述出CBV的内部执行流程(******)
