一、orm模型表
1. 如何建立模型表
1. 确定表与表对应关系
-
通过换位思考,先站在一张表上分析,然后再在另一张表分析
-
确定多对多、一对多,一对一
2. 建立外键
- 一对多:外键字段建在多的一方
- 多对多:外键关系需要建立第三张表来专门处理,外键字段建立在任意一方都可以,但是建议建在查询频率较高的一方
- 一对一:外键字段建立在任意一方都可以,但是建议建在查询频率较高的一方
2. Django项目中创建外键
- Django中,创建的外键字段时,对于一对一和一对多的关系,定义的外键字段变量在真正的数据表中,该字段名会被Django默认追加上
_主键字段名
- 在多对多的关系表中,本来的专门的第三个表也由Django创建,该表名由原来的两个表名以
_
连接形成。
1. 实例演示:
- 如当前有3张表:图书表,出版社表(规定1本书只能被一个出版社出版),作者表
- 步骤:
- 先不考虑外键关系,先创建基表
- 添加外键关系
(1)步骤一:
书籍表:
class Book(models.Model):
title = models.CharField(max_length=32)
# 小数总共八位 小数占两位
price = models.DecimalField(max_digits=8,decimal_places=2)
出版社表:
class Publish(models.Model):
title = models.CharField(max_length=32)
email = models.EmailField()
作者表:
class Author_detail(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
phone = models.BigIntegerField()
addr = models.CharField(max_length=32)
(2)步骤二:
书籍表:
class Book(models.Model):
title = models.CharField(max_length=32)
# 小数总共八位 小数占两位
price = models.DecimalField(max_digits=8,decimal_places=2)
外键一:
# 书跟出版社是一对多 并且书是多的一方 所以外键字段健在书表中
publish_id = models.ForeignKey(to='Publish') # to用来指代跟哪张表有关系 默认关联的就是表的主键字段
"""
一对多外键字段 创建的时候 同步到数据中 表字段会自动加_id后缀
如果你自己加了_id 我orm头铁 再在后面加一个_id
所以你在写一对多外键字段的时候 不要自作聪明的加_id
"""
外键二:
# 书跟作者是多对多的关系 外键字段建在任意一方都可以 但是建议你建在查询频率较高的那一方
author = models.ManyToManyField(to='Author') # django orm会自动帮你创建书籍和作者的第三张关系表
# author这个字段是一个虚拟字段 不能在实际的表中展示出来 仅仅只是起到一个告诉orm建第三章表的关系的作用
出版社表:
class Publish(models.Model):
title = models.CharField(max_length=32)
email = models.EmailField()
作者表:
class Author_detail(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
phone = models.BigIntegerField()
addr = models.CharField(max_length=32)
外键:
# 一对一的表关系 外键字段建在任意一方都可以 但是建议你建在查询频率较高的那一方
author_detail = models.OneToOneField(to='Author_detail') # fk + unique
"""
一对一外键字段 创建的时候 同步到数据中 表字段会自动加_id后缀
如果你自己加了_id 我orm头铁 再在后面加一个_id
所以你在写一对一外键字段的时候 不要自作聪明的加_id
"""
二、Django路由层
1. Django项目的urls.py文件
-
urls.py文件中的url方法的括号中的第一个参数其实是一个正则表达式,客户端发送的链接地址相当于一个大的字符串,该正则表达式就会在这个字符串中匹配,只要该正则表达式能够匹配到内容,就会立刻执行后面的视图函数,而不再往下继续匹配了。
-
urlpatterns = [ url(r'^admin/', admin.site.urls), # url第一个参数是一个正则表达式 url(r'^test/$', views.test), # 一旦正则表达式能够匹配到内容 会立刻结束匹配关系 直接执行后面对应的函数 url(r'^testadd/$', views.testadd), ]
2. Django项目的路由匹配规律:
-
本来浏览器会直接按照用户输入的地址到后端匹配,如果匹配不上,就会报404错误,但是Django项目中,Django会让浏览器把原来的地址的后面追加一个
/
,再去后端匹配一次,这次若在匹配不到就会报404错误。 -
取消Django自动让浏览器追加斜杠的功能
- 在settings文件中,添加语句:
APPEND_SLASH = False
, 该参数默认是True。
- 在settings文件中,添加语句:
-
路由匹配只匹配前端地址中的url部分,不匹配?后面的get携带的参数
3. url方法参数中的无名分组和有名分组
(1)无名分组
-
url方法的第一个参数中即正则中含有无名分组后,在路由匹配成功之后调用视图函数的时候,会将括号内正则表达式匹配到的内容当做位置参数传递给视图函数,所以视图函数除了默认接收的request参数(request也是一个位置参数),还要添加一个位置参数
url(r'^test/([0-9]{4})/', views.test) def test(request , 位置参数2) # 位置参数2的名字任意
(2)有名分组
-
url方法的第一个参数即正则中含有有名分组后,在路由匹配成功之后调用视图函数的时候,会将括号内正则表达式匹配到的内容当做关键字参数传递给视图函数,所以视图函数除了默认接收的request参数(request也是一个位置参数),还要添加一个分组名当做位置参数
url(r'^testadd/(?P<year>d+)/', views.testadd), def test(request , year)
(3)无名分组和有名分组的作用和注意
-
作用:
- 利用有名和无名分组,我们就可以在调用视图函数的时候,给函数传递额外的参数。
-
注意:
- 无名和有名分组不能混合使用,但是同一种分组可以同时使用多次
4. 反向解析
(1)什么是反向解析
- 根据别名 动态解析出一个结果 该结果可以直接访问到别名所对应的url
(2)第一种反向解析
-
第一种反向解析:urls.py文件的url方法的第一个参数中的正则是精确正则,即匹配的是一条具体不变的内容。
url(r'^home/', views.home,name='xxx'), # 给路由与视图函数对应关系起别名为xxx
-
前端反向解析
{% url 'xxx' %} # 解析出的就是 home/
-
后端反向解析
from django.shortcuts import render,HttpResponse,redirect,reverse url = reverse('xxx') # url 就是 home/
-
(3)第二种反向解析
- 第二种反向解析:urls.py文件的url方法的第一个参数中的正则是模糊正则,即匹配的是一条可以改变的内容。
1. 无名分组的反向解析
-
在解析的时候 你需要手动指定正则匹配的内容是什么
url(r'^home/(d+)/', views.home,name='xxx'), # 给路由与视图函数对应关系起别名
1. 前端反向解析
```html
<p><a href="{% url 'xxx' 12 %}">111</a></p>
<p><a href="{% url 'xxx' user.id %}">111</a></p>
-
后端反向解析
url = reverse('xxx',args=(数字,)) url1 = reverse('xxx',args=(3213,)) url2 = reverse('xxx',args=(2132131,)) # 手动传入的参数 只需要满足能够被正则表达式匹配到即可
2. 有名分组的反向解析
-
在解析的时候 你需要手动指定正则匹配的内容是什么
-
有名分组的反向解析和无名分组一样,但是最正规的写法是:
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=12 %}">111</a></p> # 了解即可
-
后端反向解析
# 可以直接用无名分组的情况 url = reverse('xxx',args=(1,)) # 你也可以规范写法 url = reverse('xxx',kwargs={'year':1}) # 了解即可
3. 第二种反向解析实例
- 以编辑功能为例
# 路由:
url(r'^edit_user/(d+)/',views.edit_user,name='edit')
def edit_user(request,edit_id):
# edit_id就是用户想要编辑数据主键值
pass
# 前端反向解析
{% for user_obj in user_list %}
<a href='/edit_user/{{user_obj.id}}/'>编辑</a>
<a href='{% url 'edit' user_obj.id %}'>编辑</a>
{% endfor %}
5. 路由分发(*********)
(1)路由分发简介和使用
-
前提:在django中所有的app都可以有自己独立的urls.py templates static文件夹。
正是由于上面的特点,你用django开发项目就能够完全做到多人分组开发 互相不干扰
每个人只开发自己的app
小组长只需要将所有人开发的app整合到一个空的django项目里面,然后在settings配置文件注册 再利用路由分发将多个app整合到一起即可完成大项目的拼接 -
路由分发解决的就是项目的总路由匹配关系过多的情况。
-
路由分发关键字:
include
-
使用路由分发 总路由不再直接做路由与视图函数对应关系了,而是仅仅做一个分发、转发的功能(请求来了之后,只询问你要访问哪个app的功能 然后将请求转发给对应的app去处理)
-
好处:更加的解耦合 更加好维护
-
实例:
# 总路由写法一:项目总路由urls文件中: from django.conf.urls import url , include # 一定要导入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第一个参数是一个正则表达式 # 路由分发 url(r'^app01/',include(app01_urls)), # 路由分发需要注意的实现 就是总路由里面不能以$结尾 url(r'^app02/',include(app02_urls)), ] # 总路由写法二:项目总路由urls文件中:这也是最简便的写法 from django.conf.urls import url , include # 一定要导入include方法 from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^app01/', include('app01.urls')), # 直接app01.urls url(r'^app01/', include('app02.urls')), # 直接app02.urls ] # 子路由 # app01文件中的urls文件: from django.conf.urls import url from app01 import views urlpatterns = [ url('^reg/',views.reg) ] # app02文件中的urls文件: from django.conf.urls import url from app02 import views urlpatterns = [ url('^reg/',views.reg) ]
(2)名称空间
- 当多个app中出现了起别名冲突的情况 ,在反向解析的时候,并不能直接识别到是哪个应用下的。这时可以给每一个app创建一个名称空间,然后在反向解析的时候 可以选择到底去哪个名称空间中查找别名
#总路由
url(r'^app01/',include('app01.urls',namespace='app01')),
url(r'^app02/',include('app02.urls',namespace='app02'))
# 后端
reverse('应用名1:相同的别名')
reverse('应用名2:相同的别名')
print(reverse('app01:reg'))
print(reverse('app02:reg'))
# 前端
{% url '应用名1:相同的别名' %}
{% url '应用名2:相同的别名' %}
<a href="{% url 'app01:reg' %}"></a>
<a href="{% url 'app02:reg' %}"></a>
-
其实上面的名称空间知识点可以完全不用 你只需要保证起别名的时候 在整个django项目中不冲突即可。
-
参考建议:
起别名的时候统一加上应用名前缀 urlpatterns = [ url(r'^reg/',views.reg,name='app02_reg') ] urlpatterns = [ url('^reg/',views.reg,name='app01_reg') ]
-
6.伪静态
- 将一个动态网页伪装成一个静态网页 以此来挺好搜索引擎SEO查询频率和收藏力度(收藏后的网站会被优先搜索出来,即越能首行搜索后得到内容)
- 以
.html
结尾的网址,一般就是静态网页。 - 所谓的搜索引擎其实就是一个也别巨大的爬虫程序
- 优化的再厉害还是抵不过RMB玩家
7. 虚拟环境
-
用处:
- 给每一个项目提供一个专门属于该项目自己的所需模块
-
每创建一个虚拟环境就类似于你重新下载了一个纯净python解释器
-
注意:
- 虚拟环境一台机器上可以有N多个
- 不要在你的机器上无限制创建虚拟环境
8. Django版本的区别
(1)django.1.xxx和django.2.xxx
-
urls.py中路由匹配的方法有区别
# django.2.xxx版本用的是path urlpatterns = [ path('admin/', admin.site.urls), ] # django1.X用的是url urlpatterns = [ url(r'^reg.html',views.reg,name='app02_reg') ] # 区别 django2.X里面path第一个参数不是正则也不支持正则 写什么就匹配什么 # 虽然path不支持正则,感觉也好用 django2.X还有一个re_path的方法 该方法就是你django1.X里面url 。 使用方法就是直接在导包的那行代码,在path后面在加一个re_path # 虽然path不支持支持正则,但是它提供了五种转换器,能够将匹配到的数据自动转换成对应的类型 # 除了有默认五种转换器之外, 还支持你自定义转换器
9. form表单上传文件
(1)前端
- form表达传文件需要注意的事项:
- method必须改成post
- enctype改成formdata格式
(2)后端
-
前期你在使用post朝后端发请求的时候 需要去settings配置文件中注释掉一个中间件csrf
-
使用
file_obj = request.FILES.get(前端标签中的name的值)
if request.method == "POST": print(request.FILES) # django会将文件类型的数据自动放入request.FILES里面 file_obj = request.FILES.get('myfile') # 文件对象 # print(file_obj) # print(file_obj.name) with open(file_obj.name,'wb') as f: for line in file_obj: f.write(line) 等价于: with open(file_obj.name,'wb') as f: for chunk in file_obj.chunks(): f.write(chunk)