django(web框架推导、简介、数据库初识)
一 web框架推导
cs架构
bs架构
bs本质是也是cs
# HTTP协议:无状态,无连接,基于请求,基于tcp/ip的应用层协议 # mysql:c/s架构,底层基于soket,自己封装的协议。mysql的其他客户,navicate(c++图形化界面,实现了请求和响应协议);pymysql(用python语言实现了请求和响应协议) # redis:c/s架构,基于socket,自己封装的协议 # docker:c/s架构,基于HTTP协议,使用restfull规范 # elasticsearch:c/s架构,基于http协议,使用restfull规范
# HTTP协议 ''' 网络协议 HTTP协议 数据传输是明文 HTTPS协议 数据传输是密文 websocket协议 数据传输是密文 四大特性 1.基于请求响应 2.基于TCP、IP作用于应用层之上的协议 3、无状态 4、短/无链接 数据格式 请求首行 请求头 请求体 响应状态码 1xx 2xx 3xx 4xx 5xx 如何做到后缀的不同返回不同的内容 拿到用户输入的后缀,做判断 不足之处 1、代码重复 2、手动处理http格式的数据,并且只能拿到url后缀,其他数据获取繁琐 3、并发的问题 '''
例:
# 可以将web框架理解成服务端 import socket server = socket.socket() # TCP 三次握手四次握手 osi七层 server.bind(('127.0.0.1', 8080)) # IP协议 以太网协议 arp协议 server.listen(5) # 池 ''' b'GET / HTTP/1.1\r\n Host: 127.0.0.1:8080\r\n Connection: keep-alive\r\n Cache-Control: max-age=0\r\n sec-ch-ua: "Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"\r\n sec-ch-ua-mobile: ?0\r\n sec-ch-ua-platform: "Windows"\r\n Upgrade-Insecure-Requests: 1\r\n User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n Sec-Fetch-Site: none\r\n Sec-Fetch-Mode: navigate\r\n Sec-Fetch-User: ?1\r\n Sec-Fetch-Dest: document\r\n Accept-Encoding: gzip, deflate, br\r\n Accept-Language: zh-CN,zh;q=0.9,en;q=0.8\r\n\r\n' ''' while True: conn, addr = server.accept() data = conn.recv(1024) print(data) # 二进制 data = data.decode('utf-8') # 字符串 # 获取字符串中特定的内容 正则 如果字符串有规律也可以考虑用切割 # 直接忽略favicon.ico conn.send(b'HTTP/1.1 200 ok\r\n\r\n') current_path = data.split(' ')[1] # print(current_path) if current_path == '/index': # conn.send(b'index ha ha') with open(r'templates/新闻页面.html', 'rb') as f: conn.send(f.read()) elif current_path == '/login': conn.send(b'login ai ai') else: conn.send(b'Hello word') conn.close()
''' urls.py 路由和视图函数对应关系 views.py 视图函数(后端业务逻辑) templates文件夹 专门用来存储html文件 ''' # 按照功能的不同拆分之后,后续添加功能只需要在urls.py书写对应关系然后去views.py书写业务逻辑即可
from wsgiref.simple_server import make_server
from urls import urls
from views import *
def run(env, response):
'''
:param env: 请求相关的所有数据
:param response: 响应相关的所有的数据
:return: 返回给浏览器的数据
'''
# print(env) # 大字典 wsgiref模块帮你处理好http格式的数据,字典格式
# 从env中获取
response('200 ok', []) # 响应首行 响应头
current_path = env.get('PATH_INFO')
# if current_path == '/index':
# return [b'hello index']
# elif current_path == '/login':
# return [b'hell login']
# return [b'404 error']
# 定义一个变量,存储匹配到的函数名
func = None
for url in urls:
if current_path == url[0]:
# 将url对应的函数名赋值给func
func = url[1]
break # 匹配一个之后,应该立刻结束
if func:
res = func(env)
else:
res = error(env)
return [res.encode('utf-8')]
if __name__ == '__main__':
server = make_server('127.0.0.1', 8080, run)
'''
会实时监听127.0.0.1:8080地址,只要有客户端来了
都会交给run函数处理(加括号触发run函数的运行)
flask启动源码
make_server('127.0.0.1',8080,obj)
'''
server.serve_forever() # 启动服务端
静态网页
页面上的数据是直接写死的,一直不变(不需要数据库操作)
动态网页
数据是实时获取的(就需要进行数据库操作)
ps:
1、后端获取当前时间展示到html页面上
2、数据是从数据库中获取的展示到html页面上
# 动态网页制作 import datetime def get_time(env): current_time = datetime.datetime.now().strftime('%Y-%m-%d %x') # 如何将后端获取的数据“传递”给html文件? with open(r'templates/03 mytime.html', 'r', encoding='utf-8') as f: data = f.read() # data就是一堆字符串(html文件是一对字符串) data = data.replace('lq', current_time) # 在后端将html页面处理好之后再返回给前端,操作字符串 return data # 后端获取数据库中数据展示到前端页面 # 利用wsgiref模块封装的web框架加上jinja2模板语法,结合前端后端数据库
# 将一个字典传递给html文件,并且可以在文件上方便快捷的操作字典数据 pip3 install jinja2 '''模版语法是在后端起作用的''' from jinja2 import Template def get_dict(env): user_dic = {'username': 'lq', 'age': 18, 'hobby': 'read'} with open(r'templates/04 get_dict.html', 'r', encoding='utf-8') as f: data = f.read() tmp = Template(data) res = tmp.render(user=user_dic) # 给get_dict.html传递了一个值,页面上通过变量名user就能够拿到user_dict return res # 模板语法(非常贴近python语法) {{user}} {{user.get('username')}} {{user.age}} {{user['hobby']}} {% for user_dict in user_info %} <tr> <td>{{ user_dict.id }}</td> <td>{{ user_dict.name }}</td> <td>{{ user_dict.password }}</td> <td>{{ user_dict.hobby }}</td> </tr> {% endfor %}
import pymysql def get_user(env): # 视图文件中的视图函数 # 去数据库中获取数据,传递给html页面,借助于模版语法,发送给浏览器 conn = pymysql.connect( host='127.0.0.1', port=3306, user='root', password='123', db='day59', charset='utf8', autocommit=True ) cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) sql = 'select * from userinfo' affect_rows = cursor.execute(sql) data_list = cursor.fetchall() # data_list,列表套字典格式 # print(data_list) with open(r'templates/05 get_user.html', 'r', encoding='utf-8') as f: data = f.read() print(data) tmp = Template(data) res = tmp.render(user_info=data_list) return res
wsgiref模块
1、请求来的时候解析http格式的数据,封装成大字典
2、响应走的时候给数据打包成符合http格式,再返回给浏览器
''' django 特点:大而全,自带的功能特别多 不足之处: 有时候过于笨重
django是一个同步框架,django3.x异步框架 flask 特点:小而精,自带的功能特别少 第三方的模块特别多,越来越来像django 不足之处: 比较依赖第三方的开发者 tornado 特点:异步非阻塞,支持高并发 ''' A:socket部分 B:路由与视图函数对应关系(路由匹配) C:模板语法 django A用的别人的 wsgiref模块 B用的是自己的 C用的是自己的(没有jinja2好用,但是很方便) flask A用的是别人的 werkzeug(内部还是wsgiref模块) B自己写的 C用的别人的(jinja2) tornado A B C都是自己写的
# 如何让你的计算机能够正常的启动django项目 1、计算机的名称不能有中文 2、一个pycharm窗口只开一个项目 3、项目里面所有的文件也尽量不要出现中文 4、python解释器尽量使用3.4-3.6之间的版本 (如果你的项目报错,点击最后一个报错信息去 源码中把逗号删除) # django版本问题 1.x 2.x 3.x(直接忽略) 1.x 和 2.x 本身差距不大,以1.x为例 LTS维护时间 # django安装 pip3 install django==1.11.11 如果已经安装了其他版本,无需自己卸载 直接重装,会自动卸载安装新的 验证是否安装成功的方式 终端输入django-admin看看有没有反应
# 命令行操作 1、创建django项目 windows可以先切换到对应的需要建项目存储位置,然后再创建 django-admin startproject mysite mysite文件 manage.py mysite文件夹 __init__.py setting.py urls.py wsgi.py # 2、启动django项目 ''' 一定要先切换到项目下 cd /mysite ''' python3 manage.py runserver http://127.0.0.1:8000/ # 3、创建应用 ''' Next, start your first app by running python manage.py startapp [app_label]. ''' python3 manage.py startapp app01 应用名应该做到见名知意 user order web 教学统一用app01/02/03 有很多文件
# 1、new project 选择左侧第二个django即可 # 2、启动 1)还是用命令行 2)点击绿色小箭头即可 # 3、创建应用 1)pycharm提供的终端直接输入完整命令 python3 manage.py startapp app01 2)pycharm tools run manage.py task提示 # 4、修改端口号以及创建server edit confi
''' django是一款专门用来开发app(功能)的web框架 比如淘宝 订单功能 用户相关 投诉相关 创建不同的app对应不同的功能 还比如选课系统 学生功能 老师功能 一个app就是一个独立的功能模块 ''' **************创建的应用一定要去配置文件中注册************* INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', # 全写 'app02', # 简写 ] # 创建出来的应用第一步先去配置文件中注册 ps:在用pycharm创建项目的时候,Pycharm可以帮你创建一个app并且自动注册
-mysite项目文件夹 --mysite文件夹 --settings.py 配置文件 --urls.py 路由与视图函数对应关系(路由层) --wsgi.py wsgiref模块(不考虑) --manage.py django的入口文件 --db.sqlite3 django自带的sqlite3数据库(小型数据库,功能不多有bug) --app01文件夹 --admin.py django后台管理 --apps.py 注册使用 --migrations文件夹 数据库迁移记录 --models.py 数据库相关的 模型类(orm) --tests.py 测试文件 --views.py 视图函数(视图层)
# 命令行创建不会自动有templates文件,需要自己手动创建,而pycharm会自动帮你创建,并且自动在配置文件中配置对应的路径。 # 命令行创建 TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], }, ] # pycharm创建 TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], }, ] ''' 命令行创建django项目的是空,不仅要创建templates文件,还要配置templates文件路径 'DIRS': [os.path.join(BASE_DIR, 'templates') '''
app应用下面views.py中 from django.shortuts import HttpResonse,render,redirect HttpResponse 返回字符串类型的数据 return HttpResponse('我不想值班,好累') render 返回html文件 return render(request, 'first.html') # setting文件里路径已帮忙设置好 def ab_render(request): # 视图函数必须要接受一个形参request user_dict = {'username': 'lq', 'age': 18} # 第一种传值方式:更加的精准,节省资源 # return render(request, '01 ab_render.html', {'data': user_dict}) # 第二种传值方式:当你要传的数据特别多的时候 # locals会将所在的名称空间中所有的名字全部传递给html页面 return render(request, '01 ab_render.html', locals()) redirect 重定向 return redirect('https://www.xiaomi.com/') return redirect('/home/') # 跳自己的网址
# 登录功能 html文件默认都放在templates文件下 将网站所使用的静态文件默认都放在static文件夹下 静态文件 前端已经写好了的,能够直接调用使用的文件 网站写好的js文件 网站写好的css文件 网站用到的图片文件 第三方前端框架 拿来就可以直接使用的 # django默认是不会自动创建static文件夹,需要自己手动创建 一般情况下我们在static文件夹内还会做进一步的划分处理 -static --js --css --img 其他三方文件 ''' 在浏览器中输入url能够看到对应的资源 是因为后端提前开设了该资源的接口 如果访问不到资源,说明后端没有开设该资源的接口 http://127.0.0.1:8000/static/bootstrap-3.4.1-dist/css/bootstrap.min.css ''' ******************************************************** # 静态文件配置 STATIC_URL = '/static/' # 类似于访问静态文件的令牌 # 要想访问静态文件,必须以static开头 # /static/bootstrap-3.4.1-dist/js/bootstrap.min.js # /static/令牌 # 取列表里面从上往下依次查找 # bootstrap-3.4.1-dist/js/bootstrap.min.js # 都没有才报错 # 配置 STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), os.path.join(BASE_DIR, 'static1'), os.path.join(BASE_DIR, 'static2'), ] # 从上往下找 ******************************************************** 当你在写django项目的时候,可能会出现后端代码修改了但是前端页面没有变化的情况 1.你在同一个端口开了好几个django项目 一直在跑的其实是第一个django项目 2.浏览器缓存的问题 settings network disable cache 勾线上 ******************************************************** # 静态文件动态解析 在html文件中 {% load static %} <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js'%}">
# form表单默认是get请求数据 http://127.0.0.1:8000/login/?username=lq&password=123 ''' form表单action参数 1、不写 默认朝当前所在的url提交数据 2、全写 指名道姓 3、只写后缀 /login/ 自动补全ip和端口 ''' # 在前期使用django提交post请求的时候,需要取配置文件中注释掉一行代码 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', ]
request.method # 返回请求方式,并且是全大写的字符串类型 < class 'str'> request.POST # 获取用户POST请求提交的普通数据不包含文件
print(request.POST)
# 字典嵌套列表的格式
# <QueryDict: {'username': ['lq'], 'password': ['123'], 'hobby': ['111', '222', '333']}>
request.POST.get() # 获取列表最后一个元素,获取类型是字符串 request.POST.getlist() # 直接将列表取出,类型是列表 request.GET # 获取用户GET请求提交的普通数据不包含文件
print(request.GET)
# 字典嵌套列表的格式
# <QueryDict: {'username': ['lq'], 'password': ['123'], 'hobby': ['111', '222', '333']}>
request.GET.get() # 获取列表最后一个元素 request.GET.getlist() # 直接将列表取出 ''' GET请求携带的数据是有大小限制的,大概只有4kb左右 POST请求则没有限制 '''
def login(request): # 返回一个登录界面 ''' get请求和post请求应该有不同的处理机制 :param request: 请求相关的数据对象,里面有很多简易的方法 :return: ''' # print(request.method) # 返回请求方式,并且是全大写的字符串形式 if request.method == 'GET': print(request.GET) # return HttpResponse('收到,宝贝') # elif request.method == 'POST': # return HttpResponse('收到,宝贝') # 推荐写法 if request.method == 'POST': # 获取用户数据 print(request.POST) # 获取用户提交的post请求数据(不包含文件) # <QueryDict: {'username': ['lq'], 'password': ['123']}> # username = request.POST.get('username') # print(username, type(username)) # lq<class 'str'> # get只会获取列表最后一个元素,所以获取的值是字符串类型 # hobby = request.POST.getlist('hobby') # 列表 hobby = request.POST.get('hobby') # 字符串 print(hobby, type(hobby)) # getlist 获取的值就是个列表 # 获取用户的用户名和密码,然后利用orm操作数据,校验数据是否正确 username = request.POST.get('username') password = request.POST.get('password') # print(password, type(password)) # 去数据库中查询数据 res = models.User.objects.filter() print(res) # <QuerySet [<User: User object>]> [数据对象1,数据对象2...],表中的一行一行的数据 user_obj = models.User.objects.filter().first() user_obj = res[1] print(user_obj) print(user_obj.username) print(user_obj.password, type(user_obj.password)) if user_obj: # 比对密码是否一直 if password == str(user_obj.password): return HttpResponse('登录成功') else: return HttpResponse('密码错误') else: return HttpResponse('用户不存在') # print(request.GET) # 获取用户提交的get请求数据 # # <QueryDict: {'username': ['lq'], 'password': ['123'], 'hobby': ['111', '222', '333']}> # hobby = request.GET.get('username') # print(hobby, type(hobby)) # print(request) return render(request, 'login.html')
三 数据库
''' 三个位置查找数据库相关 右侧上方database 左下方database 配置里面的plugins插件搜索安装 再没有,只有卸载pycharm pycharm可以充当很多款数据库软件的客户端 ''' # 需要提前创建好库 # 明明链接上了数据库,但是看不到表无法操作这个时候只需要将刚刚创建的链接删除,重新链接一次即可
# 默认用的是sqkite3 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } # django链接MySQL 1、第一步配置文件中配置 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'day60', 'USER': 'root', 'PASSWORD': '123', 'HOST': '127.0.0.1', 'PORT': 3306, 'CHARSET': 'utf8', 'OPTIONS':{'init_command':'SET sql_mode="STRICT_TRANS_TABLES",storage_engine=INNODB;'} #设置数据库为INNODB,为第三方数据库登录用 } } 2、代码声明 django默认用得是mysqldb模块链接MySQL 但是该模块的兼容性不好,需要手动改为用pymysql链接 需要告诉django不要用默认的mysqldb,而是用pymysql # 在项目名下的init或者任意的应用名下的init文件中书写以下代码即可 import pymysql pymysql.install_as_MySQLdb()
*******ORM不会帮你创建库,只能创建到表的层面********** ''' 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) # 等价sql语句,username varchar(32) username=models.CharField(max_length=32) # 等价sql语句,password int password=models.IntegerField() *******************2.数据库迁移命令********************** ''' python3 manage.py makemigrations 将操作记录到(migrations文件夹) python3 manage.py migrate 将操作真正的同步到数据库中 pycharm简单快捷输入 tools run manage.py tassk 自动提示 ''' ****只要你修改了models.py中跟数据库相关的代码,就必须重新执行上述的两条命令**** class User(models.Model): # id int primary_key auto_increment id = models.AutoField(primary_key=True) username = models.CharField(max_length=32, verbose_name='用户名') ''' CharField必须要指定max_length参数,不指定会直接报错 verbose_name该参数是所有的字段都有的,就是用来对字段的解释 ''' password = models.IntegerField(verbose_name='密码') class Author(models.Model): ''' 由于一张表中必须要有一个主键字段,并且一般情况下都叫id字段 所以orm不定义主键字段的时候,orm会自动帮你创建一个名为id主键字段 后续在创建模型表的时候,主键字段名没有额外的叫法,那么主键字段可以省略不写 ''' username = models.CharField(max_length=32) password = models.IntegerField()
# 字段的增加 1、可以在终端内直接给出默认值 2、该字段可以为空 info = models.CharField(max_length=32, verbose_name='个人简介', null=True) 3、直接给字段设置默认值 hobby = models.CharField(max_length=32, verbose_name='兴趣爱好', default='study') # 字段的修改 直接修改字段代码然后执行数据库迁移的两条命令即可 # 字段的删 直接注释对应的字段,再执行数据库迁移的两条命令即可 执行完毕后字段对应的数据也都没有了 ''' 在操作models.py的时候一定要细心 千万不要注释一些字段 执行迁移命令之前最好先检查一下自己写的代码 '''
# 查 res=models.User.objects.filter(username=username) print(res) # <QuerySet [<User: User object>]> [数据对象1,数据对象2...],表中的一行一行的数据 ''' 返回值是一个querySet对象,你先看成是列表套数据对象的格式 [数据对象1,数据对象2....],表中的一行一行的数据 它支持索引取值,切片操作,但是不支持负数索引 同样不支持索引取值 ''' user_obj = res[0] print(user_obj) print(user_obj.username) print(user_obj.password, type(user_obj.password)) # 推荐的取值方式 user_obj=models.User.objects.filter(username=username).first() # first()对应的就是索引为0的数据对象,在mysql表中,也是取主键值为1的一行数据集合对象 ''' filter括号内可以携带多个参数,参数与参数之间默认是and关系,筛选出那一行数据 可以把filter联想成where记忆 '''
# 直接获取用户数据存入数据库, insert into t1(age,name) values(18,'jason'); # mysql中插入数据 def reg(request): if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') # 直接获取用户数据存入数据库 # 第一种增加方式 # res = models.User.objects.create(username=username, password=password) # 返回值就是当前被创建的对象本身 # print(res, res.username, res.password) # 第二种增加方式 user_obj = models.User(username=username, password=password) user_obj.save() # 先给用户返回一个注册页面 return render(request, 'reg.html') # 第一种方式增加 from app01 import models res = models.User.objects.create(username=username, password=password) # 返回值就是当前被创建的对象本身 print(res, res.username, res.password) # 第二种方式增加
user_obj=models.User(username=username,password=password) user_obj.save()
需求:先讲数据库中的数据全部展示到前端,然后给每一个数据两个按钮,一个编辑,一个删除
# 查 def userlist(request): # 查询用户表里面所有的数据 # 方式一 # data=models.User.objects.filter() # print(data) # 方式二 user_queryset = models.User.objects.all() # print(data) # <QuerySet [<User: User object>, <User: User object>]> # return render(request,'userlist.html',{'user_queryset':user_queryset}) return render(request, 'userlist.html', locals())
useerlist.html
<body> <h1 class="text-center">数据展示</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> <table class="table table-striped table-hover"> <thead> <tr> <th>ID</th> <th>username</th> <th>password</th> <th>action</th> </tr> </thead> <tbody> {% 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="/delete_user/?user_id={{ user_obj.id }}" class="btn btn-danger btn-xs">删除</a> </td> </tr> {% endfor %} </tbody> </table> </div> </div> </body>
流程:
点击userlist.html中的编辑a标签,是用get的方式,通过urls.py中的/edit/到视图函数edit(),根据选择的edit_id,
从数据库中查询到要编辑的数据,展现到edit.html文件中,修改后,点击提交,from表单中的action没有值,
提交的数据的地址任是/edit/,这次是post请求,就把数据传给数据库,并修改,redirect(/userlist/),再执行视图函数
uselist(),查询新的更新后的数据库数据,展示到userlist.html。
# 编辑功能 # 点击编辑按钮朝后端发送编辑数据的请求 ''' 如何告诉后端用户想要编辑那一条数据? 将编辑按钮所在的那一行数据的主键值发送给后端 利用url问号后面携带参数的方式 ''' 后端查询出用户想要编辑的数据对象,展示到前端页面供用户查看和编辑
def edit(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/') # 查询当前用户想要编辑的数据对象 edit_obj = models.User.objects.filter(id=edit_id).first() # 返回编辑页面 return render(request, 'edit_user.html', locals())
edit_user.html
<body> <h1 class="text-center">编辑</h1> <div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <form action="" method="post"> <p>username:<input type="text" name="username" class="form-control" value="{{ edit_obj.username }}"></p> <p>password:<input type="text" name="password" class="form-control" value="{{ edit_obj.password }}"></p> <input type="submit" class="btn btn-info btn-block" value="编辑"> </form> </div> </div> </div> </body>
# 删除功能 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 lq 123 0 zd 123 1
''' 表与表之间的关系 一对多 多对多 一对一 判断表关系的方法:换位思考 ''' 图书表 出版社表 作者表 作者详情表 ''' 图书和出版社是一对多的关系,外键字段建在多的那一方,book 图书和作者是多对多的关系,需创建第三张表专门储存 作者和作责详情表是一对一 ''' # 创建表关系,先将基表创建出来,然后再添加外键字段 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,后面还是会加_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版本中外键默认都是级联更新级联删除 # 多对多的表关系可以有好几种创建方式,暂且介绍一种 # 针对外键字段里面的其他参数,暂时不考虑,自己可以百度
扩展知识
缓存数据库
提前已经将你想要的数据准备好了,你来直接拿就可以
提高效率和响应时间
当你在web页面修改数据时,并没有立刻修改,要等段时间才修改 是因为请求数据还是在访问缓存数据库,没有访问后端数据库
在正常开发中,我们给每一个项目配备一个该项目独有的解释器环境
该环境只有该项目用到的模块,用不到一概不装
linux缺什么才装什么
虚拟环境
每创建一个虚拟环境就类似于重新下载了一个纯净的python解释器
但是虚拟环境不要创建太多,是需要消耗硬盘空间
扩展:
每一个项目要用到很多模块,能不能一次装好
开发中,给每一个项目配备一个requirement.txt文件
里面书写该项目所有的模块既版本
直接输入一条命令即可一键安装所有模块既版本
创建虚拟环境的步骤,new project---pure python---点击new environment ---点击make available to all projects---create---退出
---setting---interpreter---安装包---django---退出---new project---选择虚拟环境的解释器
''django1.x路由层使用的是url方法
而django2.x和3.x版本中路由使用的是path方法 url()第一个参数支持正则 path()第一个参数是不支持正则,写什么就匹配什么 如果习惯使用path那么再提供另外一种方法 ''' from django.urls import path, re_path from django.conf.urls import url re_path(r'^index/',views.index) url(r'^login/',login) # 2.x和3.x版本里的re_path等价一1.x里的url # 虽然path不支持正则,但是它内部支持五种转换器 path('index/<int:id>/', views.index) # 将第二个路由里面的内容先转成整型,然后以关键字的形式传递给视图函数 def index(request, id): print(id,type(id)) return HttpResponse('index') ''' str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式 int,匹配正整数,包含0。 slug,匹配字母、数字以及横杠、下划线组成的字符串。 uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。 path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?) ''' # 除了有默认的五个转换器之外,还支持自定义转换器(了解) class MonthConverter: regex='\d{2}' # 属性名必须为regex def to_python(self, value): return int(value) def to_url(self, value): return value # 匹配的regex是两个数字,返回的结果也必须是两个数字 from django.urls import path,register_converter from app01.path_converts import MonthConverter register_converter(MonthConverter,'mon') from app01 import views urlpatterns = [ path('articles/<int:year>/<mon:month>/<slug:other>/', views.article_detail, name='aaa'), ] # 模型层里面1.x外键默认都是级联更新删除的,但是到了2.x和3.x中需要你手动匹配参数 models.ForeignKey(to='Publish') models.ForeignKey(to='Publish',on_delete=models.CASCADE,
on_update=models.CASCADE)
django2.0版的re_path与path,更多详细看下面链接
https://www.cnblogs.com/xiaoyuanqujing/articles/11642628.html