【2020Python修炼记】web框架之 Django框架功能速览
【目录】 day60-61
一、Django三把斧——传值方式
(以登录功能为例-二~七)
二、
三、request对象方法初识
四、pycharm链接数据库(MySQL)
五、django链接数据库(MySQL)
六、Django ORM简介
一、Django三把斧——传值方式
1、三把斧
from django.shortcuts import HttpResponse,render,redirect"""
HttpResponse
返回字符串类型的数据(内部传入一个字符串参数,返回给浏览器。)return HttpResponse('字符串')
render
除request参数外还接受一个待渲染的模板文件和一个保存具体数据的字典参数。
将数据填充进模板文件,最后把结果返回给浏览器。(类似于 jinja2 )
return render(request, "目标页面的html文件名", 存有数据的字典参数)
def index(request): # 业务逻辑代码 return render(request, "index.html", {"name": "mili", "hobby": ["读书", "运动"]})redirect
重定向——接受一个URL参数,表示跳转到指定的URL (注意:url 一定要用 ' ' 括起来)。return redirect('url')
return redirect('https://www.mzitu.com/')
return redirect('/home/')
"""
2、以render 为例,传值方式初探
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), # render 如何传值 url(r'^ab_render/', views.ab_render) ]
from django.shortcuts import render # Create your views here. # render 如何传值 def ab_render(request): # 视图函数 必须要接收一个形参 request user_dict = {'username': 'cc', 'age': 23} # 第一种传值方式_加一个字典 {'data': user_dict} 将 user_dict 里的值传给 01 ab_render.html页面,页面通过'data'就能拿到字典里的数据 # return render(request, '01 ab_render.html', {'data': user_dict,'date':520}) # 第二种传值方式 _当需要传多个值的时候 ''' locals 会将所在的名称空间中 所有的名字(全局/局部)全部传给页面 ''' return render(request, '01 ab_render.html', locals())
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>user_info</title> </head> <body> {#第一种传值方式,通过 data 将数据传给页面#} {# {{ data }}#} {# {{ date }}#} {#第二种传值方式 ,将名称空间里的全部名字传给页面 #} {{ request }} {{ user_dict }} </body> </html>
(以登录功能为例,先从整体上 大致掌握django框架的功能)
二、
https://www.cnblogs.com/olivertian/p/10968158.html
https://zhuanlan.zhihu.com/p/151855280
https://code.ziqiangxuetang.com/django/django-static-files.html
# 登陆功能 """ 我们将html文件默认都放在templates文件夹下 我们将网站所使用的静态文件默认都放在static文件夹下 静态文件 前端已经写好了的 能够直接调用使用的文件 网站写好的js文件 网站写好的css文件 网站用到的图片文件 第三方前端框架 ... 拿来就可以直接使用的 """ # django默认是不会自动帮你创建 static文件夹 需要你自己手动创建。然后在html文件中,添加本地保存的第三方前端框架的文件路径链接即可
一般情况下我们在static文件夹内还会做进一步的划分处理 -static --js --css --img 其他第三方文件 """ 在浏览器中输入url能够看到对应的资源 是因为后端提前开设了该资源的接口 如果访问不到资源 说明后端没有开设该资源的接口 http://127.0.0.1:8000/static/bootstrap-3.3.7-dist/css/bootstrap.min.css
如下图,就算 html 文件中已经添加了 相关的样式静态文件的链接,但是显示的内容并没有继承我们给定的样式,
因为浏览器无法访问到该资源(原因是后端没有开设该资源的接口,因此需要通过静态文件的配置 解决这个问题)
1、静态文件配置 (在 settings.py文件的最后面,加上以下代码) STATICFILES_DIRS = [ os.path.join(BASE_DIR,'static') ]
2、修改 login.html 的 样式文件链接(去掉 .. )
<link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
<script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
再次运行项目,打开login.html
"""
# 静态文件配置 (配置文件里的每个部分的变量名 需要大写格式) """ **************************************************************** 当你在写django项目的时候 可能会出现后端代码修改了但是前端页面没有变化的情况 1.你在同一个端口开了好几个django项目 一直在跑的其实是第一个django项目 2.浏览器缓存的问题——如何清除浏览器缓存,保证每次打开都是最新页面
在网页中--右击鼠标--【检查】/【审查元素】--- settings network disable cache 勾选上
勾选如图选项
***************************************************************** """
#1 令牌 STATIC_URL = '/static/' # 类似于访问静态文件的令牌
(不一定要以 “static”为令牌名,也可以自定义。令牌修改了,html文件里的静态文件路径的开头(令牌)也要修改成和配置文件里的一样)
"""如果你想要访问静态文件 文件链接路径就必须以static开头(因为 令牌是 /static/)"""
""" /static/bootstrap-3.3.7-dist/js/bootstrap.min.js /static/令牌 取列表里面从上往下依次查找 bootstrap-3.3.7-dist/js/bootstrap.min.js 都没有才会报错 """
#2 静态文件路径 # 静态文件配置 (可以配置多个静态文件夹) STATICFILES_DIRS = [ os.path.join(BASE_DIR,'static'), os.path.join(BASE_DIR,'static1'), os.path.join(BASE_DIR,'static2'), ]
访问 静态文件资源,必须要有 “令牌”+“静态文件夹名”
——————————————————————— # 静态文件动态解析
修改 html文件的静态文件链接 {% load static %} <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}"> <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
——————————————————————————————————————————————————————————————————
# form表单默认是get请求数据 http://127.0.0.1:8000/login/?username=jason&password=123 """ form表单action参数 1.不写 默认朝当前所在的url提交数据 2.全写 指名道姓 3.只写后缀 /login/ """
<div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> {# action参数形式有三种,只写后缀 action="/login/" #} {# 每提交一次,都会触发两次GET请求,第一次是login,第二次则根据 action 的参数来决定,不写还有写login是触发login。。(见下图)#} <form action="" method="post"> <p>username:<input type="text" name="username" class="form-control"></p> <p>password:<input type="password" name="password" class="form-control"></p> <input type="submit" class="btn btn-success btn-block"> {# 以上三行代码,实现的是简单的登录信息界面,#} {# 但是有个缺点,就是信息输入完提交后,用户信息会在url的末尾显示,因为form表单默认的提交方式,是GET请求,将其改为POST请求 #} </form> </div> </div>
# 每提交一次,都会触发两次GET请求……:
# 修改了提交方式为 post之后( <form action="" method="post">),
进入登录界面,输入信息提交后,会出现“禁止访问(没有访问权限,访问不符合条件…)”的界面 ,解决方法见下方:
#错误403 --- 解决方法如下:
# 在前期我们使用django提交post请求的时候 需要去settings.py配置文件中的【中间件 MIDDLEWARE】注释掉一行代码 (为啥这样处理,原因暂时不解释,后期揭晓) MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
# 成功提交数据后,仍是触发两次请求,第一次为GET,第二次是POST:
三、request对象方法初识
GET 请求和 POST 请求,应该有不同的处理机制。如何判断 GET 请求和 POST 请求 ,使用request 对象(内含很多对象方法),可以解决这个问题
request.method # 返回请求方式 并且是全大写的字符串形式 <class 'str'>
request.POST # 获取用户post请求提交的普通数据不包含文件 request.POST.get() # 只获取列表最后一个元素 request.POST.getlist() # 直接将列表取出 request.GET # 获取用户提交的get请求数据 request.GET.get() # 只获取列表最后一个元素 request.GET.getlist() # 直接将列表取出 """ get请求携带的数据是有大小限制的 大概好像只有4KB左右 而post请求则没有限制 """ def login(request): # 返回一个登陆界面 """ get请求和post请求应该有不同的处理机制 :param request: 请求相关的数据对象 里面有很多简易的方法 :return: """
# print(type(request.method)) # 返回请求方式 并且是全大写的字符串形式 <class 'str'>
# 判断请求方式(基础版)
# if request.method == 'GET': # print('来了 老弟') # return render(request,'login.html') # elif request.method == 'POST': # return HttpResponse("收到了 宝贝")
# 判断请求方式 (精简版) if request.method == 'POST': return HttpResponse("收到了 宝贝") return render(request, 'login.html')
四、pycharm链接数据库(MySQL)
""" 三个位置查找数据库相关 右侧上方 database 左下方 database 配置里面的 plugins插件 搜索安装 ====再没有卸载pycharm重新装===== pycharm可以充当很多款数据库软件的客户端 参考截图和视频操作即可 需要提前创建好库 """
添加数据库——例如 添加MySQL,首先需要下载相关driver files,如下图
如果链接数据库时,链接不上,那可以切换驱动:
表数据的编辑操作:
五、django链接数据库(MySQL)
# 默认用的是sqkite3 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # django链接MySQL 1.第一步 settings 配置文件中配置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'day60', # 填写 数据库名 'USER':'root', 'PASSWORD':'123', 'HOST':'127.0.0.1', 'PORT':3306, 'CHARSET':'utf8' } }
2.代码声明 django默认用的是mysqldb模块链接MySQL 但是该模块的兼容性不好 需要手动改为用pymysql链接 你需要告诉django不要用默认的mysqldb 而是用pymysql(事先需要 安装 pymysql 模块) # 在项目名下的 __init__.py 或者任意的应用名下的 __init__.py 文件中书写以下代码都可以
import pymysql pymysql.install_as_MySQLdb()
【注意咯注意咯】—— 不用代码声明的方法
六、Django ORM (Object/Relation Mapping)简介
*************************# 2 数据库迁移命令*************************
python3 manage.py makemigrations 将操作记录记录到小本本上(migrations文件夹) python3 manage.py migrate 将操作真正的同步到数据库中
# 只要你修改了models.py中跟数据库相关的代码 就必须重新执行上述的两条命令# 查看迁移记录(可能有未同步到数据库的操作):python3 manage.py showmigrations
******************************************************************
""" ORM. 对象/关系映射 # 作用:能够让一个不用sql语句的小白也能够通过python 面向对象的代码简单快捷的操作数据库 # 不足之处:封装程度太高 有时候sql语句的效率偏低 需要你自己写SQL语句 类 表 对象 记录 对象属性 记录某个字段对应的值 # 操作对象:应用下面的 models.py 文件 """ # 1 先去models.py中书写一个类 class User(models.Model): # id int primary_key auto_increment id = models.AutoField(primary_key=True) # username varchar(32) username = models.CharField(max_length=32) # password int password = models.IntegerField() *************************# 2 数据库迁移命令************************* python3 manage.py makemigrations 将操作记录记录到小本本上(migrations文件夹) python3 manage.py migrate 将操作真正的同步到数据库中 # 只要你修改了models.py中跟数据库相关的代码 就必须重新执行上述的两条命令 ******************************************************************
ps-error 1 ---数据库迁移过程可能出现的bugs:
No changes detected
Running migrations: No migrations to apply.
如何解决:
https://www.cnblogs.com/bigorangecc/p/13034352.html
—————————————————————————————————————————————— class User(models.Model): # id int primary_key auto_increment id = models.AutoField(primary_key=True,verbose_name='主键') # username varchar(32) username = models.CharField(max_length=32,verbose_name='用户名') """ CharField必须要指定max_length参数 不指定会直接报错 verbose_name该参数是所有字段都有的 就是用来对字段的解释 """ # password int password = models.IntegerField(verbose_name='密码') class Author(models.Model): # 由于一张表中必须要有一个主键字段 并且一般情况下都叫id字段 # 所以orm当你不定义主键字段的时候 orm会自动帮你创建一个名为id主键字段 # 也就意味着 后续我们在创建模型表的时候如果主键字段名没有额外的叫法 那么主键字段可以省略不写 # username varchar(32) username = models.CharField(max_length=32) # password int password = models.IntegerField()
# 字段的增加 1.在已有数据的表中添加字段,可以在终端内直接给出默认值
2.该字段可以为空 null=True
在 models.py 中 添加以下代码后,一定要执行 数据库迁移命令。
info = models.CharField(max_length=32,verbose_name='个人简介',null=True)
3.直接给字段设置默认值
在 models.py 中 添加以下代码后,一定要执行 数据库迁移命令。
hobby = models.CharField(max_length=32,verbose_name='兴趣爱好',default='study')
【具体操作】
1、在已有数据的表中添加字段
(1)基础数据表(添加完数据,一定要记得点击 如图所示 高亮着的“submit”按钮(在‘小飞机’旁边的类似于保存的按钮))
(2)增加age字段——在 models.py 文件里,添加代码,再执行 数据库迁移命令,会出现问题(数据没法写入表中)
出现提示:
选择1,输入默认值 18
(3)执行第二条数据库迁移命令 migrate
(PS:error 2---在执行 migrate 命令时,会出现警告错误——迁移失败)
解决办法:在 settings.py 里面修改【严格模式】,再重新执行数据库迁移命令
(参考阅读:https://www.cnblogs.com/bigorangecc/p/13034352.html)
(4)刷新数据库的表,查看:
2.该字段可以为空—— null=True
在 models.py 中 添加以下代码后,一定要执行 数据库迁移命令。
info = models.CharField(max_length=32,verbose_name='个人简介',null=True)
# 字段的修改 直接修改代码然后执行数据库迁移的两条命令即可! # 字段的删 直接注释对应的字段然后执行数据库迁移的两条命令即可! 执行完毕之后字段对应的数据也都没有了。。谨慎删库 """ 在操作models.py的时候一定要细心 千万不要注释一些字段 执行迁移命令之前最好先检查一下自己写的代码 """ # 个人建议:当你离开你的计算机之后一定要锁屏——防人之心不可无
2、
# 查 res = models.User.objects.filter(username=username) """ 返回值你先看成是列表套数据对象的格式 它也支持索引取值 切片操作 但是不支持负数索引 它也不推荐你使用索引的方式取值
user_obj = models.User.objects.filter(username=username).first() """ filter括号内可以携带多个参数 参数与参数之间默认是and关系 你可以把filter联想成where记忆 # 增 from app01 import models res = models.User.objects.create(username=username,password=password) # 返回值就是当前被创建的对象本身 # 第二种增加 user_obj = models.User(username=username,password=password) user_obj.save() # 保存数据
# 先将数据库中的数据全部展示到前端 然后给每一个数据两个按钮 一个编辑一个删除 #1 查看 def userlist(request): # 查询出用户表里面所有的数据 # 方式1 # data = models.User.objects.filter() # print(data) # 方式2 user_queryset = models.User.objects.all() # return render(request,'userlist.html',{'user_queryset':user_queryset}) return render(request,'userlist.html',locals()) #2改---编辑功能 # 点击编辑按钮朝后端发送编辑数据的请求 """ 如何告诉后端用户想要编辑哪条数据? 将编辑按钮所在的那一行数据的主键值发送给后端 利用url问号后面携带参数的方式 {% for user_obj in user_queryset %} <tr> <td>{{ user_obj.id }}</td> <td>{{ user_obj.username }}</td> <td>{{ user_obj.password }}</td> <td> <a href="/edit_user/?user_id={{ user_obj.id }}" class="btn btn-primary btn-xs">编辑</a> <a href="" class="btn btn-danger btn-xs">删除</a> </td> </tr> {% endfor %} """ # 后端查询出用户想要编辑的数据对象 展示到前端页面供用户查看和编辑 def edit_user(request): # 获取url问号后面的参数 edit_id = request.GET.get('user_id') # 查询当前用户想要编辑的数据对象 edit_obj = models.User.objects.filter(id=edit_id).first() if request.method == "POST": username = request.POST.get('username') password = request.POST.get('password') # 去数据库中修改对应的数据内容 # 修改数据方式1 # models.User.objects.filter(id=edit_id).update(username=username,password=password) """ 将filter查询出来的列表中所有的对象全部更新 批量更新操作 只修改被修改的字段 """ # 修改数据方式2 edit_obj.username = username edit_obj.password= password edit_obj.save() """ 上述方法当字段特别多的时候效率会非常的低 从头到尾将数据的所有字段全部更新一边 无论该字段是否被修改 """ # 跳转到数据的展示页面 return redirect('/userlist/') # 将数据对象展示到页面上 return render(request,'edit_user.html',locals()) #3 删除功能 """ 跟编辑功能逻辑类似 def delete_user(request): # 获取用户想要删除的数据id值 delete_id = request.GET.get('user_id') # 直接去数据库中找到对应的数据删除即可 models.User.objects.filter(id=delete_id).delete() """ 批量删除 """ # 跳转到展示页面 return redirect('/userlist/') """ # 真正的删除功能应该需要二次确认 我们这里先不做后面会讲 # 删除数据内部其实并不是真正的删除 我们会给数据添加一个标识字段用来表示当前数据是否被删除了,如果数据被删了仅仅只是讲字段修改一个状态 username password is_delete jason 123 0 egon 123 1
""" 表与表之间的关系 一对多 多对多 一对一 没有关系 判断表关系的方法:换位思考 """ 图书表 出版社表 作者表 作者详情表 """ 图书和出版社是一对多的关系 外键字段建在多的那一方 book 图书和作者是多对多的关系 需要创建第三张表来专门存储 作者与作者详情表是一对一 """ from django.db import models # Create your models here. # 创建表关系 先将基表创建出来 然后再添加外键字段 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 如果你自作聪明的加了_id那么orm还是会在后面继续加_id 后面在定义ForeignKey的时候就不要自己加_id """ """ 图书和作者是多对多的关系 外键字段建在任意一方均可 但是推荐你建在查询频率较高的一方 """ authors = models.ManyToManyField(to='Author') """ authors是一个虚拟字段 主要是用来告诉orm 书籍表和作者表是多对多关系 让orm自动帮你创建第三张关系表 """ class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=32) class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() """ 作者与作者详情是一对一的关系 外键字段建在任意一方都可以 但是推荐你建在查询频率较高的表中 """ author_detail = models.OneToOneField(to='AuthorDetail') """ OneToOneField也会自动给字段加_id后缀 所以你也不要自作聪明的自己加_id """ class AuthorDetail(models.Model): phone = models.BigIntegerField() # 或者直接字符类型 addr = models.CharField(max_length=32) """ orm中如何定义三种关系 publish = models.ForeignKey(to='Publish') # 默认就是与出版社表的主键字段做外键关联 authors = models.ManyToManyField(to='Author') author_detail = models.OneToOneField(to='AuthorDetail') ForeignKey OneToOneField 会自动在字段后面加_id后缀 """ # 在django1.X版本中外键默认都是级联更新删除的 # 多对多的表关系可以有好几种创建方式 这里暂且先介绍一种 # 针对外键字段里面的其他参数 暂时不要考虑 如果感兴趣自己可以百度试试看
# 每个人都要会画 这个图是你们后期复习django最好的一个梳理方式 # 扩展知识点 """ 缓存数据库 提前已经将你想要的数据准备好了 你来直接拿就可以 提高效率和响应时间 当你在修改你的数据的时候 你会发现数据并不是立刻修改完成的 而是需要经过一段时间才会修改 博客园 了解即可 """
(大佬画的图----》)
https://www.cnblogs.com/xiaomage666/p/11234508.html
https://www.bilibili.com/video/av56548916/?spm_id_from=333.788.videocard.19
参考阅读:
https://www.cnblogs.com/Dominic-Ji/articles/10982272.html
🐱不负韶华,只争朝夕🍚