数据的查、改、删
功能:先将数据库中的数据全部展示到前端 然后给每个数据两个按钮 一个编辑 一个删除
查
'''
# 方式一
# data = models.User.objects.filter() 什么都不写默认就是全部 不过语义不明确
# print(data)
# 方式二
data2 = models.User.objects.all() 第二种语义明确
print(data2)
'''
编辑功能
点击编辑按钮朝后端发送编辑数据的请求
'''
如何告诉后端用户想要编辑哪条数据?
将编辑按钮所在那一行的主键值发送给后端
利用url问号后面携带参数的方式(get)
'''
<a href="/edit_user?username={{ user_obj.id }}" class="btn btn-primary btn-xs">编辑</a>
手动将 该条数据的id值放进a标签的链接里面 当成参数 只要点了编辑按钮
就会跳到/edit_user?username= 并且把数据传回去
改
# 修改数据方式1
models.User.objects.filter(id=edit_id).update(username=username, password=password)
# 修改数据方式2
edit_obj.username = username
edit_obj.password = password
edit_obj.save()
'''
上述方法 当字段多的时候 效率特别低
它会将你列出来的字段全部更新一遍 无论该字段是否被修改
'''
删
del_id = request.GET.get('username') # 获取a链接传回来的 参数 id值
del_obj = models.User.objects.filter(id=del_id)
del_obj.delete() # 这样是批量删除
return redirect('/userlist') # 删完后要重定向到展示页面
'''
真正的删除功能应该是有二次确认的 我们这里先不做 后面会讲
删除数据内部其实并不是真正的删除 我们会给数据添加一个标识用来表示当前数据是否被删除了, 如果数据被删除了仅仅只是将字段修改了一个状态
username password is_delete
jason 123 0
egon 123 1
'''
django orm中如何创建表关系
'''
表与表之间的关系
一对多
多对多
一对一
判断表关系的方法:换位思考
'''
图书馆
出版社
作者表
作者详情表
'''
图书和出版社是一对多的关系 外键字段建在多的那一方 book
图书和作者是多对多的关系 需要创建第三张表来专门存储
作者与作者详情表是一对一
=========================================
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name='标题')
price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='价格') # 小数总共八位 小数点后面占两位
'''
图书和出版社是一对多 并且书是多大的一方 所以外键建放在书表里面
'''
publish = models.ForeignKey('Publish', on_delete=models.CASCADE) # 默认就是与出版社的主键字段做关联
'''
图书和作者是多对多的关系 外键字段建在任意一方均可 但是推荐你建在查询频率较高的一方
'''
authors = models.ManyToManyField('Author') # authors是一个虚拟表 主要是告诉orm 书籍表和作者表是多对多的关系 让你的orm自动帮你创建第三张表
class Publish(models.Model):
name = models.CharField(max_length=32, verbose_name='出版社名称')
addr = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name='作者姓名')
age = models.IntegerField(verbose_name='年龄')
'''
作者与作者详情是一对一的表 推荐你建在查询频率较高的表
'''
author_detail = models.OneToOneField('AuthorDetail', on_delete=models.CASCADE)
'''
OneToOnField会给你要创的外键字段 自动加上_id后缀
所以你不要自作聪明的自己加上_id (就算加上 它也会帮你再加上)
'''
class AuthorDetail(models.Model):
phone = models.BigIntegerField() # 手机号有11位 所以要么用BigIntegerField() 要么用字符串
addr = models.CharField(max_length=32)
'''
orm中如何定义三种关系
publish = models.ForeignKey('Publish', on_delete=models.CASCADE)
authors = models.ManyToManyField('Author')
author_detail = models.OneToOneField('AuthorDetail', on_delete=models.CASCADE)
ForeignKey
OneToOneField
会自动在字段后面加_id 后缀
ManyToManyField
会自动创建第三张表
django 升级到2.0之后,表与表之间关联的时候,必须要写on_delete参数,否则会报异常: (ForeignKey、OneToOneField)需要加上这个属性 ManyToManyField不用
django请求生命周期流程图(必会)
扩展知识点
'''
缓存数据库
提前已经将你想要的数据准备好累 你来直接拿就可以
提高效率和降低响应时间
(就是在中间件那里判断要获取的数据 缓存数据库中有没有 如果有直接获取到然后返回给浏览器)
'''
路由层
路由匹配
url(r'test', views.test),
url(r'testadd', views.testadd)
'''
url方法第一个参数是正则表达式
只要第一个正则(就是url里面的路由地址test)匹配到了内容 那么就会立刻停止往下匹配
直接执行对应的视图函数
你在输入url的时候会默认加斜杠
django内部帮你做重定向
一次匹配不行
url后面加斜杠再来一次
'''
# 取消自动加斜杠
默认是True
APPEND_SLASH = False 一般都不会取消
且在urls.py 里面的路径 最好都要加上/ 例如 url(r'test/', views.test)
# 首页 什么都不写 (djagon2.x版本的情况) 打开就是匹配到这个路由
path('', views.home),
path('test/', views.test),
path('testadd/', views.testadd),
django2.0版本是path 不需要加r ^ $ 这些正则匹配了
无名分组有名分组是django1.xx版本的 2.版本可以向下兼容
或者导入 re_path 2.x版本的re_path == url
无名分组
'''
分组:就是给某一段正则表达式用小括号括起来
'''
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触发视图函数
# 先给路由与视图函数起一个别名
path('funcdsfsdfcc/', views.func, name='ooo')
反向解析
后端反向解析
from django.shortcuts import render,HttpResponse,reverse #需要导入 reverse
print(reverse('ooo')) 直接写reverse('') 里面写上反向解析的名字
前端反向解析
<a href="{% url 'ooo'%}">111</a> # 这样匹配 无论路由与视图的url怎么改 你都是通过name属性匹配的 都能匹配上
#
无名有名分组反向解析
# 无名分组的反向解析
re_path(r'^index/(\d+)/', views.index, name='xxx')
# 前端
<a href="{% url 'xxx' 123 %}">123</a>
# 后端
print(reverse('xxx', args=(1,)))
'''
这个数字写代码的时候应该放什么
数字一般情况下放的是数据的主键值 数据的编辑和删除
url(r'^edit/(\d+)', views.edit,name='xxx')
def edit(request, edit):
//可以获得到 那串匹配到的数字
//这个数字从哪来的 从前端a标签 反向解析需要带上一个符合正则表达的数据
//有什么用? 前端可以a标签内可以放字段的id值 通过前端的反向解析传到路由与视图函数那 后端再通过反向解析获取到 edit 也就是id值 就可以根据该id值进行数据库的增删改查操作了
{% for user_obj in user_queryset%}
<a href="{% url 'xxx' user_obj.id %}">编辑</a>
{%endfor%}
'''
# 有名分组反向解析
re_path(r'^func/(?P<year>\d+)/', views.func, name='ooo')
# 前端
<a href="{% url 'ooo' year=123 %}">111</a> 了解
<a href="{% url 'ooo' 123 %}">111</a> 掌握
# 后端
print(reverse('ooo', args=(111,))) 掌握
print(reverse('ooo', kwargs={'year': 111}))
路由分发
'''
django的每一个应用都可以有自己的templates文件夹 urls.py static 文件夹
正式基于上述特点 django能够非常好的做到分组开发(每个人只写自己的app)
作为组长 只需要将手下书写的app全部拷贝到一个新的django项目中 然后在配置文件里面注册所有的app 再利用路由分发的特点将所有的app整合起来
当一个django项目中的url特别多的时候 总路由urls.py代码非常冗余不好维护 这个时候也可以利用路由分发来减轻总路由的压力
'''
# 总路由
from app01 import urls as app01_urls
from app02 import urls as app02_urls
urlpatterns = [
path('admin/', admin.site.urls), # re_path == url
# 路由分发
re_path(r'app01/',include(app01_urls)),
re_path(r'app02/',include(app02_urls)),
# 第二种方式 就两行代码就行 (推荐使用)
# re_path(r'app01/',include('app01.urls')),
# re_path(r'app02/', include('app02.urls'))
]
# 子路由
# app01 urls.py
from app01 import views
urlpatterns = [
re_path(r'^reg/', views.reg)
]
# app02 urls.py
from app02 import views
urlpatterns = [
re_path(r'^reg/', views.reg)
]
'''这两个路由与视图函数 后续只要在对应的views视图函数写入对应的函数接口就行了'''
名称空间(了解)
# 当多个应用出现了相同的别名 我们研究反向解析会不会自动识别应用前缀
urlpatterns = [ //app01 的 urls.py
re_path(r'^reg/', views.reg, name="reg")
]
当他们的别名一致时 反向解析能否区分
urlpatterns = [ //app02 的 urls.py
re_path(r'^reg/', views.reg, name="reg")
]
print(reverse('reg')) // 经过测试是无法区分的
有两种解决方法
方法一:
在项目urls.py文件里加上命名空间
'''这是django2.0版本的命名空间操作 跟1.0版本有所不同'''
path(r'app01/', include((app01_urls,'app01'),namespace='app01')), # 只要url前缀是app01开头就交给 app01全权处理
path(r'app02/', include((app02_urls,'app02'),namespace='app02')), # 不同的app 创造不同的空间出来 即使有重复别名 可以通过不同空间的别名来区分
加上命名空间后 对应的app里面要反向解析的时候 也需要稍微改一下代码
print(reverse('app01:reg'))
print(reverse('app02:reg')) # 选择哪个空间下的别名 这样就能区分重复的别名
这样就能成功反向解析到不同别名对应的 路由了
方法二:
因为是多人项目 因此在工作前都会有任务规划 只要人为的创建别名的时候带上 应用名称前缀
例如:
urlpatterns = [
re_path(r'^reg/', views.reg, name="app01_reg")
]
urlpatterns = [
re_path(r'^reg/', views.reg, name="app02_reg")
]
注意: 一般都会认为的区分开来 别名
伪静态(了解)
'''
静态网页
数据是写死的 万年不变
伪静态
将一个动态网页伪装成静态网页
为什么要伪装呢?
https://www.cnblogs.com/Dominic-Ji/p/9234099.html
伪装的目的在于增大网站的seo查询力度
并且增加搜索引擎收藏本网站的概率
搜索引擎本质上就是一个巨大的爬虫程序
总结:
无论你怎么优化 怎么处理
始终干不过RMB玩家
'''
要想变成伪静态 只需要将路由改一下就好了
urlpatterns = [
url(r'^reg.html', views.reg, name='app02_reg')
]
虚拟环境
做一个项目的时候最好就只放这个项目用到的模块
用不到的模块 最好不要放入 这样能提示服务器加载速度
所以在创建项目的时候 可以选择
后续 差不多的项目的 就可以用这个环境
django版本区别
'''
1.
django1.x路由层使用的是url方法
而在django2.x和3.x版本中路由层使用的是path方法
url() 第一个参数支持正则
path() 第一个参数是不支持正则
若是还是想用正则 可以导入re_path 模块
from django.urls import path, re_path
re_path == url
2. path 和 url path不支持正则 却有五种转换器
3. 模型车里面1.x外键默认都是级联更新删除的
但是到了2.x和3.x中需要你自己手动配置参数
models.ForeignKey(to='Publish')
models.ForeignKey(to='Publish', on_delete= models.CASCAE...)
'''