1. 注册登入项目
项目需求:
1. 127.0.0.1:8080/regisert 进入注册页面
2. 127.0.0.0:8080/login 进入登入页面
2. 项目准备
2.1 新建项目
![image-20220302001416163](https://i-blog.csdnimg.cn/blog_migrate/816c88adff7274ff06efe11495158e13.png)
2.2 结果路径报错问题
修改 Templates 模板文件的路径拼接文件 --> 将 / 改为 ,
![image-20220302001829663](https://i-blog.csdnimg.cn/blog_migrate/c9500959abf525017cac8f093a5d4635.png)
2.3 创建app应用
一个程序必须有一个应用.
在pycharm底部打开终端,输入:
python manage.py startapp app01
![image-20220302002007645](https://i-blog.csdnimg.cn/blog_migrate/3178f93234bd2dcd3a06813c7965a123.png)
2.4 注册app引用
创建的app必须要注册,在settings配置文件中添加注册.
setting.py 的第 33 行
INSTALLED_APPS = [
'django.contrib.admin',
····························
'app02'
]
![image-20220302002207051](https://i-blog.csdnimg.cn/blog_migrate/e95da182ab23b05f918c94fffed404e8.png)
3. 登入功能
需求: 在地址栏输入127.0.0.1/login/ 返回一个登入页面
3.1 路由层
路由层中写 路由 与 视图函数 的对应关系.
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/', views.login)
]
3.2 视图层
打开app01应用的views.py的视图层,写登入函数.
* 所有视图函数都需要接收request形参.
* 使用render函数必须返回request形参.
from django.shortcuts import render
def login(request):
return render(request, 'login.html')
3.3 静态文件
1.介绍
静态文件:不会改变的文件.
项目中的 CSS文件,JavaScript文件,图片,音频文件,第三方框架...都是静态文件.
2. 存放位置
html文件都放在templates目录下.
静态文件都放在static目录下.
* 需要自己手动在项目下创建文件static目录.可以是别的名字,但是别人都使用这个名称,就约定俗成了.
3. 创建目录划分子目录
0. 在项目目录下创建static目录
1. 对静态文件进一步的划分,不同类型的文件存在在不同的子目录当中.
static (需要的时候在创建子目录,可以先不创建子目录)
|-js
|-css
|-img
|-其他
4.项目需要的静态文件
前端需要使用到bootstrap框架 和 jquery库文件.
bootstrap是基于jquery使用的,引入bootstrap相关文件前必须先引入jquery库文件.
0.在static下创建js目录.
1.将jquery-3.6.6.min.js复制到static的子目录js下.
2.将前端框架bootstrap-3.3.7-dist复制到static目录下.
jquery库文件下载地址: https://code.jquery.com/jquery-3.6.0.min.js
bootstrap框架下载地址: https://v3.bootcss.com/getting-started/#download
bootstrap下载后需要解压
![image-20220302153836749](https://i-blog.csdnimg.cn/blog_migrate/9670eebf4e3ce17458664ac2d58c175d.png)
![image-20220302172754540](https://i-blog.csdnimg.cn/blog_migrate/8b3a1e536c42bdf55af2d2ea3ace6a7a.png)
3.4 登入页面
* 前端页面代码存放在templates目录中.
0. templates下创建login.html文件.
1. html中引入jQuery 库文件
2. html中引入bootstrap css文件
3. html中引入bootstrap js文件
4. 写一个简单的登入页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登入页面</title>
<script src="/static/js/jquery-3.6.0.min.js"></script>
<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>
<style>
body {
background-image: url("../static/img/3.jpg");
background-size: cover;
background-repeat: no-repeat;
}
</style>
</head>
<body>
<div class="container">
<h1 class="text-center">登入</h1>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<form action="">
<p>
<label for="d1">用户名称:</label>
<input type="text" id='d1' name="username" class="form-control">
</p>
<p>
<label for="d2">用户密码:</label>
<input type="text" id='d2' name="password" class="form-control">
</p>
<p>性别:
<input type="radio" name="gender" value="male"> 男
<input type="radio" name="gender" value="female"> 女
</p>
<input type="submit" class="btn btn-success btn-block">
</form>
</div>
</div>
</div>
</body>
</html>
3.5 静态路径开放
静态文件都放在static目录下,后端服务器正常运行下:
如果能够看到对应的静态资源,那么就是后端开设了静态文件资源的接口.
0. 启动程序后,浏览器输入 127.0.0.1:8000/login
1. 在后端查看信息
结论:静态资源无法访问.
![image-20220302204546145](https://i-blog.csdnimg.cn/blog_migrate/e87a9b54edc860fe4c1c96fd5cde5c92.png)
1. 令牌
Django的settings.py文件下第122行:
# 静态url
STATIC_URL = '/static/'
STATIC_URL设置的值相当于令牌,访问的路径必须以这个令牌的名称开始.
* 令牌名字更改了,所有相关的路径都需要改. 前端
![image-20220302163458198](https://i-blog.csdnimg.cn/blog_migrate/d85f7226f9648b4c0ac4a32f26db50ec.png)
2. 开放
STATICFILES_DIRS 设置静态文件的路径, 设置之后便能正常访问静态文件.
格式:(在令牌后面设置)
STATICFILES_DIRS = [路径1, 路径2, ...]
从前玩后依次从列表中取值,取到则返回,都没有则报错.
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
![image-20220302204840173](https://i-blog.csdnimg.cn/blog_migrate/7eba392151e144b18e5fe13c3c37207b.png)
3. 动态修改
使用模板语法,获取令牌名字,
当名字更改了,所有相关的路径都自动改.
{% load static %}
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js'%}"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登入页面</title>
{% load static %}
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<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>
</head>
<body>
<div class="container">
<h1 class="text-center">登入</h1>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<form action="">
<p>
<label for="d1">用户名称:</label>
<input type="text" id='d1' name="username" class="form-control">
</p>
<p>
<label for="d2">用户密码:</label>
<input type="text" id='d2' name="password" class="form-control">
</p>
<p>性别:
<input type="radio" name="gender" value="male"> 男
<input type="radio" name="gender" value="female"> 女
</p>
<input type="submit" class="btn btn-success btn-block">
</form>
</div>
</div>
</div>
</body>
</html>
![image-20220302205934783](https://i-blog.csdnimg.cn/blog_migrate/4eee7287e8ac1fb68bf0d4b5ad15a2f6.png)
测试之后将名字改回来.
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
3.6 浏览器缓存
在写django项目的时候可能会出现后端代码修改了,前端页面没有变化.
常见的情况:
1. 在用一个端口开了好几个django项目,一直运行的还是第一个gjango项目
2. 浏览器缓存的问题
按下 F12 进入开发者模式 点击设置图片
找到 netword
勾选 disable xxxxx 禁用缓存
刷新页面
3. 代码有问题.
![image-20220302205958581](https://i-blog.csdnimg.cn/blog_migrate/ac8cf4fb86b15f561f82847481712c58.png)
![](https://i-blog.csdnimg.cn/blog_migrate/73af49e972a7eec7260fa05d980bd9c5.png)
4. 请求方式
请求方式有两种:
1.GET
2.POST
区别:
1.get请求携带数据有大小的限制,大概4kb左右.
2.post请求携带数据没有限制.
request对象中存放了请求头的数据.
request.method 方法获取http请求方式
4.1 GET请求访问服务端
app01/views.ps 中添加获取请求方式的代码.
from django.shortcuts import render
def login(request):
print(request.method)
return render(request, 'login.html')
![image-20220302211327391](https://i-blog.csdnimg.cn/blog_migrate/2d672270df8019a2949e92f57d8ad422.png)
客户端访问服务端是GET请求.
4.2 GET请求提交表单数据
form表单的action属性值可以指定提交的地址.
action值的三种情况:
1.不写,默认朝当前所有url提交数据.
2.全写,指定详细位置.
3.指定后缀/login/
现在不设置action属性的值,在浏览器输入: 127.0.0.1:8000/login
* 当前的url就是我们输入的.
![image-20220302212618410](https://i-blog.csdnimg.cn/blog_migrate/caadfe2d995528dc9841cc26f7e94011.png)
在表单填数据
姓名:kid
密码:123
性别:男
写好后点提交.
![image-20220302212940728](https://i-blog.csdnimg.cn/blog_migrate/c9784c4aa87bcb5fc0250d34caaa47c2.png)
from表单默认是get方式提交.
4.3 POST请求提交表单
form 表单的 method 属性可以设置请求方式.
不设置默认是GET请求.
0. 修改from表单的提交方式为post,
1. 浏览器输入: 127.0.0.1:8000/login
2. 写好表单信息后提交数据.
<form action="" method="post">
4.4 Csrf中间件问题
Django提交post请求的时候需要在配置中注释掉Csrf中间键,否则报错 403.
settings中第
MIDDLEWARE =[
···
# 'django.middleware.csrf.CsrfViewMiddleware'
···
]
没有注释前.
![image-20220302214508719](https://i-blog.csdnimg.cn/blog_migrate/c5b6e583c39c2a52d02bdc1b21b4d450.png)
注释掉之后.
![image-20220302214753698](https://i-blog.csdnimg.cn/blog_migrate/1859f27836638643d9d643fd34e9748a.png)
post提交表单,表单的数据不会跟当前页面的url后面展示.
4.5 获取POST请求数据
request.POST 获取用户提交的post请求中除文件外所有数据数据,字典类型.
request.POST.get('xxx') 通过get键取值,如果有多个值,优先取最后一个值.
request.POST.getlist('xx') 如果键对应有多个值则取多个值,返回一个列表.
<p>爱好:
<input type="checkbox" name="hobby" value="reading"> 看书
<input type="checkbox" name="hobby" value="learning"> 学习
</p>
app01/views.ps 中添加代码
from django.shortcuts import render
def login(request):
print(request.method)
if request.method == 'POST':
print(request.POST)
print(request.POST.getlist('gender'))
return render(request, 'login.html')
![image-20220302222410112](https://i-blog.csdnimg.cn/blog_migrate/a5bb790e77f7b1c165d920a24f95eb36.png)
![image-20220302222540458](https://i-blog.csdnimg.cn/blog_migrate/36c7c93d1549f85a4822a320ff2b8c41.png)
GET
[02/Mar/2022 22:24:40] "GET /login/ HTTP/1.1" 200 1584
POST
<QueryDict: {'username': ['kid'], 'password': ['123'], 'gender': ['male'], 'hobby': ['reading', 'learning']}>
kid
['reading', 'learning']
[02/Mar/2022 22:24:47] "POST /login/ HTTP/1.1" 200 1584
4.6 获取GET请求数据
request.GET 获取用户提交的post请求中除文件外所有数据数据,字典类型.
request.GET.get('xxx') 通过get键取值,如果有多个值,优先取最后一个值.
request.GET.getlist('xx') 如果键对应有多个值则取多个值,返回一个列表.
<form action="" method="get">
from django.shortcuts import render
def login(request):
print(request.method)
if request.method == 'POST':
print(request.POST)
print(request.POST.get('username'))
print(request.POST.getlist('hobby'))
if len(request.GET) != 0:
print(request.GET)
print(request.GET.get('username'))
print(request.GET.getlist('hobby'))
return render(request, 'login.html')
![image-20220302223744832](https://i-blog.csdnimg.cn/blog_migrate/b3236250cbcf4598feb692d21ecfdc8c.png)
# 第一次获取登入页面
GET
[02/Mar/2022 22:36:04] "GET /login/ HTTP/1.1" 200 1583
# 第二次提交数据
[02/Mar/2022 22:36:11] "GET /login/?username=kid&password=123&gender=male&hobby=reading&hobby=learning HTTP/1.1" 200 1583
GET
<QueryDict: {'username': ['kid'], 'password': ['123'], 'gender': ['male'], 'hobby': ['reading', 'learning']}>
kid
['reading', 'learning']
4.7 获取POST后面的数据
def login(request):
print(request.method)
print(request.GET.get('uuid'))
![image-20220304024705744](https://i-blog.csdnimg.cn/blog_migrate/942b0f2e1e7b326e586c30010ae3c242.png)
只要是 路径后面有值就能通过GET.get()取到.
5. 连接数据库
![image-20220302224558710](https://i-blog.csdnimg.cn/blog_migrate/6ed74a4f7b28598f8a9d72642523317d.png)
如过没有则去plugins插件搜索darabase安装.
Pycharm可以充当很多款数据库软件的客户端.
第一次选择数据库后记得下载驱动.
5.1 选择数据库
![image-20210811181907356](https://i-blog.csdnimg.cn/blog_migrate/59d4071cc01f44b9ed23d90cfd1147ff.png)
5.2 安装驱动
点DOwnload
![image-20210810222340598](https://i-blog.csdnimg.cn/blog_migrate/5f89a85372df54b57239c8f6f0dd1bf9.png)
5.3 通信配置
填好了先点Test ** 测试先是否能成功连通,
连接的库必须是提前建立好的.
创建库
使用Navicat创建
https://blog.csdn.net/qq_46137324/article/details/119303398
命令行创建
https://blog.csdn.net/qq_46137324/article/details/119150449
![image-20210811182447807](https://i-blog.csdnimg.cn/blog_migrate/48edc43ef6ef26428d6e6f4747602856.png)
5.4 测试成功点ok
![image-20210811183104172](https://i-blog.csdnimg.cn/blog_migrate/410582dbbe1d4146e9a441b1b722bbb7.png)
5.5 查看数据库
![image-20210811183744282](https://i-blog.csdnimg.cn/blog_migrate/9d1798fec52a5690eb3d1d657f9a96a7.png)
6. Django连接数据库
6.1 数据库配置文件
Django 自带一个 sqkite3数据库,兼容性不好
Django 的数据库配置在settings.py 75 行
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
6.2 自定义配置
将默认的库修改为MySQL.
第一步:settings配置文件修改:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'db1',
'USER': 'root',
'PASSWORD': 123,
'HOST': '127.0.0.1',
'POST': 3306,
'CHARSET': 'utf8'
}
}
第二步:代码声明
django 默认是使用mysqldb模块连接sqkite3,需要手动改为pymysql模块链接pymysql.
安装 pip3 install pymysql
在app01应用下有个__init__,或者任何应用名下书写以下代码
import pymysql
pymysql.install_as_MySQLdb()
![image-20220303014611597](https://i-blog.csdnimg.cn/blog_migrate/5b3de3a7dc66c4fd85e2b3021a321647.png)
7. ORM 操作数据库
ORM的作用能够通过Python面向对象的代码简单快捷的操作数据路.
不足之处:封装程度太高,有时候效率低,需要自己写sql语句.
ORM对象关系映射:
类 ---> 表
对象 ---> 记录
对象属性 ---> 记录中的某个字段
7.1 表操作
1.创建表
app应用下面的models.py中创建表.
models.py中书写一个类就是创建一个表,这个类必须继承models.Modeld.
from django.db import models
class User(models.Model):
id = models.AutoField(primary_key=True, verbose_name='主键')
username = models.CharField(max_length=32, verbose_name='用户名称')
password = models.IntegerField(verbose_name='用户密码')
verbose_name 字段注释
id = models.AutoField(primary_key=True, verbose_name="主键")
等同于
id int primary_key auto_increment
username = models.CharField(max_length=32, verbose_name="用户名")
等同于
username char(32)
password = models.IntegerField()
等同于
password int
varchar字段必须指定max_length参数不指定就会直接报错.
![image-20220303123452257](https://i-blog.csdnimg.cn/blog_migrate/e55b2f967e84a61ceaaec625c19a9d48.png)
2.数据库迁移
创建好表后,需要迁移数据库文件才能生效.
1. python manage.py makemigrations
(简写,运行task的 run manage task,直接输入makemigrations)
2. python manage.py migrate
将操作真正的同步到数据库中.
* 只要修改了models.py中的更数据库相关的代码就必须重新执行数据库迁移命令
* 无法迁移的话,检查app是否注册.
python manage.py makemigrations
命令是记录对models.py的所有改动,
并且将并记录保存到migrations文件下生成一个文件(默认只有一个__init__.py)
![image-20220303114738873](https://i-blog.csdnimg.cn/blog_migrate/30972fd1124d21502680150f5d55a022.png)
python manage.py migrate
命令执行migrations里面改动的迁移文件作用到数据库,比如创建数据表,或者增加字段...
![image-20220303115007778](https://i-blog.csdnimg.cn/blog_migrate/91c07182a65409a39e86470fa7acfe78.png)
orm创建表,会自动加上一个前缀,
避免Django项目开发多个应用时,出现表名冲突.
3. id字段
每个表中都需要有一个主键字段,并在一般情况下都叫id字段,
在没有定义id字段时,且没有其他的主键,orm会自动创建一个名为id的主键字段.
* 后续在创建模型表的时候如果主键字段名就叫id,那么主键字段可以省略不写.
class Author(models.Model):
username = models.CharField(max_length=32)
password = models.IntegerField()
7.2 字段操作
1. 增加字段
后续增加的字典要设置值
* 1.4 1.5 1.6 一个一个的添加看效果
from django.db import models
class User(models.Model):
id = models.AutoField(primary_key=True, verbose_name='主键')
username = models.CharField(max_length=32, verbose_name='用户名称')
password = models.IntegerField(verbose_name='用户密码')
lv = models.IntegerField(validators='1', verbose_name='用户等级')
info = models.CharField(max_length=32, null=True, verbose_name='用户信息')
hobby = models.CharField(max_length=32, default='reading', verbose_name='爱好')
每次修改了models.py的信息都要,执行数据库迁移迁移命令.
0. python manage.py makemigrations
1. python manage.py migrate
lv = models.IntegerField(validators='1', verbose_name='用户等级')
![image-20220303115600891](https://i-blog.csdnimg.cn/blog_migrate/71a34ac014f464a3137c48a426203968.png)
您试图在没有默认值的情况下向用户添加不可为空的字段“年龄”;
我们不能这样做(数据库需要一些东西来填充现有的行)。
请选择修复程序:
1) 现在提供一个一次性默认值(将在所有现有行上设置此列的空值)
2) 退出,让我在模型中添加一个默认值。(设置default)
0. 选择1回车
1. 输入值
info = models.CharField(max_length=32, null=True, verbose_name='用户信息')
![image-20220303120336081](https://i-blog.csdnimg.cn/blog_migrate/e02fe253d017f2f7c464f48799a8b390.png)
在检测到为空的时候会有一个警告.
第三情况,设置default默认值,添加的字段全部为默认的值
hobby = models.CharField(max_length=32, default='reading', verbose_name='爱好')
![image-20220303120753319](https://i-blog.csdnimg.cn/blog_migrate/a706c8442eeeb1c9a092a73fb7910612.png)
![image-20220303122944949](https://i-blog.csdnimg.cn/blog_migrate/5bdd44c8b0016ad8e7653a00d0117dd1.png)
后续新增字段执行python manage.py makemigrations 都会增加一个文件.
第一次创建的在第一个文件中.
![image-20220303122439018](https://i-blog.csdnimg.cn/blog_migrate/9ce90e0c0a0c97695836da11ade5e2ca.png)
2. 更改字段
password = models.CharField(max_length=30, validators='密码')
![image-20220303123631583](https://i-blog.csdnimg.cn/blog_migrate/5645847085518b32f304a0d6d416ceab.png)
3. 删除字段
* 字段的删除只需要将对应的字段注释掉,(在不写入数据的数据原来的数据还存在,
如果写了数据,被注释字段的数据一样被删除,看下的7.4.2 )
* 直接删除字段,对应的数据会全部丢失.(不要轻易的操作删除字段)
* 操作迁移命令的时候一定要检查自己写的代码,代码搞错了数据会丢失.
# 将 lv 和 info 注释掉
# lv ...
# info ...
![image-20220303124216083](https://i-blog.csdnimg.cn/blog_migrate/dd800b2e1ee07e3cc7a9e3d98e3e9e33.png)
![image-20220303125917384](https://i-blog.csdnimg.cn/blog_migrate/9fbaabb319e06283fa5d02f692ed5c79.png)
字段还存在无法写值
4.字段的查拿眼看
...
7.3 制作脚本
脚本可以是应用下的test.py,可以单独开设的别的py文件.
测试环境取manage.py中拷贝前四行代码,然后补上需要的代码.
![image-20220303150111798](https://i-blog.csdnimg.cn/blog_migrate/8ab561edbd35e84b628c90ff18c07d69.png)
from django.test import TestCase
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django2.settings")
import django
django.setup()
from app01 import models
先搭建好,等下要测试从数据库中获取数据.
7.4 数据操作
先在Navicat为app01_user添加数据:
id username password
1 kid 123
2 qz 456
![image-20220303130033063](https://i-blog.csdnimg.cn/blog_migrate/5891e6471a0e56c97dc328ac8de47d9e.png)
* 查增都有一个对象.当对象是一条数据的时候可以使用.点方法的方式取值.
* 改删 返回影响的行数.
1. 查看数据
models.表名.objects 获取一个表的对象
models.表名.objects.all() 获取表中所有的信息 可以看成是一个列表.
models.表名.objects.all()first() 获取表中第一条数据
models.表名.objects.all()[索引] 获取表中第n条数据
models.表名.objects.filter(查询条件) 获取表中符合条件的所有的信息
models.表名.objects.filter(查询条件).first() 获取表中符合条件的第一条数据
对象只有一个值的时候使用.方法取值.
from django.test import TestCase
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django2.settings")
import django
django.setup()
from app01 import models
user_obj = models.User.objects
print(user_obj)
print(user_obj.all())
"""
<QuerySet [<User: User object>, <User: User object>, <User: User object>]>
查询对象 列表套对象 一个<> 代表一天数据
User: 表名
User object --> 数据现在是看不见的.
"""
![image-20220303152309141](https://i-blog.csdnimg.cn/blog_migrate/10794fa5f1f8f35e8ffa9f92c81fb53a.png)
User object 是获取的数据,无法显示是以为没有对数据进行输出.
在应用下的models.py 为创建的User类 设置 __str__ 魔方反法
__srt__ 在输入时自动触发
self.xxx xxx是前面定义过的字段
def __str__(self):
return '%s %s' % (self.username, self.password)
![image-20220303152251621](https://i-blog.csdnimg.cn/blog_migrate/e38eda58efc7f19f57449106afa0d43a.png)
print(user_obj.all().first())
print(user_obj.all()[0])
print(user_obj.all()[1])
![image-20220303153311516](https://i-blog.csdnimg.cn/blog_migrate/5bca1d2f1a3def511732e06c01f84027.png)
user_obj2 = models.User.objects.filter(username='kid')
print(user_obj2)
print(user_obj2.all())
print(user_obj2.first())
print(user_obj2[0])
![image-20220303154405518](https://i-blog.csdnimg.cn/blog_migrate/6b92c1cabf7e6c23cbf3083049ff489c.png)
res = models.User.objects.first()
print(res)
print(res.username)
print(res.password)
![image-20220303212338893](https://i-blog.csdnimg.cn/blog_migrate/79c23270941b685c274e29cc00d576cc.png)
2. 增加数据
* 被删除的字段信息和信息被删除
models.表名.objects.create(字段=值, 字段=值) 添加数据
models.User.objects.create(username='hh', password='000')
![image-20220303155921889](https://i-blog.csdnimg.cn/blog_migrate/0c456ab82950d46eb71bf055785e8e6a.png)
3. 修改数据
models.表名.objects.filter(查询条件).update(更改的字段=值,更改的字段=值)
models.表名.objects.update(更改的字段=值,更改的字段=值) 修改符合添加的数据
models.表名.objects.filter(查询条件).update(更改的字段=值,更改的字段=值) 修改整张表
models.User.objects.update(username='qq', password=123)
![image-20220303192847242](https://i-blog.csdnimg.cn/blog_migrate/e1a438d8dfeb31a2a0f536ca7c5c706a.png)
models.User.objects.filter(id=1).update(username='kid')
![image-20220303193908322](https://i-blog.csdnimg.cn/blog_migrate/65727b19fdb157239b6136d1f6613dd5.png)
4. 删除数据
models.表名.objects.delete() 删除整张表的数据
models.表名.objects.filter(删除的条件).delete() 删除符合条件的数据
models.User.objects.filter(id=5).delete()
![image-20220303194330486](https://i-blog.csdnimg.cn/blog_migrate/4d70b2f84c7534873afeccfd0c67ac3c.png)
5. 返回对象
* 查增都有一个对象.当对象是一条数据的时候可以使用.点方法的方式取值.
* 改删 返回影响的行数.
res = models.User.objects.first()
print(res, res.id, res.username, res.password)
![image-20220303214955483](https://i-blog.csdnimg.cn/blog_migrate/e10443c13bfa4e1fe46fefcbe139a4ad.png)
res = models.User.objects.create(username='xx', password='111')
print(res, res.id, res.username, res.password)
![image-20220303215140343](https://i-blog.csdnimg.cn/blog_migrate/1c425dad45b97f207bd4bd722643c717.png)
res = models.User.objects.filter(id=2).update(username='qwe', password=456)
print(res)
![image-20220303215500964](https://i-blog.csdnimg.cn/blog_migrate/809bb651ef71d22398fc08eaea138091.png)
res = models.User.objects.filter(id=2).delete()
print(res)
![image-20220303215630539](https://i-blog.csdnimg.cn/blog_migrate/8873027b7649a7f8d2d5de7650277c57.png)
6. 单独更新数据
obj = models.User.objects.first()
obj.username = 'sb'
obj.password = 666
obj.save()
![image-20220304015335323](https://i-blog.csdnimg.cn/blog_migrate/4ff6491232b73f182057e5db0313beb8.png)
8.前后端数据校验
读取数据库中的值,与提交的数据进行比对.
0.前端POST请求提交数据.
1.后端从数据库中读取数据&检验数据
<form action="" method="post">
![image-20220303135952710](https://i-blog.csdnimg.cn/blog_migrate/fd98171655e3f57507918bdf5504ac79.png)
8.1 登入页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登入页面</title>
{% load static %}
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<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>
</head>
<body>
<div class="container">
<h1 class="text-center">登入</h1>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<form action="" method="post">
<p>
<label for="d1">用户名称:</label>
<input type="text" id='d1' name="username" class="form-control">
</p>
<p>
<label for="d2">用户密码:</label>
<input type="text" id='d2' name="password" class="form-control">
</p>
<input type="submit" class="btn btn-success btn-block">
</form>
</div>
</div>
</div>
</body>
</html>
8.2 数据检验
视图函数中需要导入应用下的models模块,来获取数据库的数据.
1.获取前端的数据
from django.shortcuts import render
from app01 import models
def login(request):
print(f'请求方式为{request.method}')
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
print(f'账户:{username}, 密码:{password}')
return render(request, 'login.html')
![image-20220303140603981](https://i-blog.csdnimg.cn/blog_migrate/14d1ac9c7b026353d06ad0f3fabf5a6d.png)
第二次测试时遇到一个未知问题,前端页面反馈这行报错,无法展示网页.
我想把这行这行注释, 然后就正常了,我在接触注释之前的报错也没出现.
![image-20220303201850401](https://i-blog.csdnimg.cn/blog_migrate/057a076141cec535be92c8ec45c26f60.png)
2.获取后端数据&检验
user_obj = models.User.objects.filter()
print(user_obj, type(user_obj))
![image-20220303200529090](https://i-blog.csdnimg.cn/blog_migrate/0962cccfea071d7a23515cb743ed55b2.png)
user_obj = models.User.objects.filter(username=username, password=password)
print(user_obj, type(user_obj))
![image-20220303200823484](https://i-blog.csdnimg.cn/blog_migrate/3490bb5512f058a4b8db8a9e516c10e0.png)
from django.shortcuts import render
from app01 import models
def login(request):
print(f'请求方式为{request.method}')
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
print(f'账户:{username}, 密码:{password}')
user_obj = models.User.objects.filter(username=username, password=password)
print(user_obj, type(user_obj))
if user_obj:
print('登入成功...')
else:
print('账户或密码错误...')
return render(request, 'login.html')
3.测试
第一次输入正确的账户密码.
![image-20220303202139910](https://i-blog.csdnimg.cn/blog_migrate/f65a0e79fcff1749b815cd5e5eb18c6f.png)
第二次输入错误的信息.
![image-20220303202245431](https://i-blog.csdnimg.cn/blog_migrate/2be165cf3902ed77b11c603baf810ad3.png)
可以放回一个页面就不弄了.
9. 注册功能
开设一个注册功输入 127.0.0.1:8000/regisert 进入一个注册页面
0. form 表单中需要获取用户名和密码.
字段为id(自增的)username password
* hobby 字段不用管了.
9.1 路由成
路由层中写 路由 与 视图函数 的对应关系.
url(r'^register/', views.reg),
9.2 视图层
打开app01应用的views.py的视图层,写注册函数.
* 所有视图函数都需要接收request形参.
* 使用render函数必须返回request形参.
def register(request):
return reder(request,'register.html')
9.3 注册页面
在templates创建register.html
复制登入页面的代码,简单的修改一下.(看图)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面</title>
{% load static %}
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<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>
</head>
<body>
<div class="container">
<h1 class="text-center">登入</h1>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<form action="" method="post">
<p>
<label for="d1">用户名称:</label>
<input type="text" id='d1' name="username" class="form-control">
</p>
<p>
<label for="d2">用户密码:</label>
<input type="text" id='d2' name="password" class="form-control">
</p>
<input type="submit" class="btn btn-success btn-block" value="注册">
</form>
</div>
</div>
</div>
</body>
</html>
![image-20220303204058890](https://i-blog.csdnimg.cn/blog_migrate/81d6c1a9bfe7f0d12cf9eb87af5897a0.png)
9.4 获取前端数据
0. 获取post方式提交的数据.
1. 将信息写入数据库中.
def register(request):
print(request.method)
if request.method == 'POST':
in_username = request.POST.get('username')
in_password = request.POST.get('password')
in_hobby = request.POST.get('hobby')
models.User.objects.create(
username=in_username, password=in_password, hobby=in_hobby)
return HttpResponse('注册成功!')
return render(request, 'register.html')
![image-20220303211210067](https://i-blog.csdnimg.cn/blog_migrate/846a3f13a6d1fa7251394417eb8b7c20.png)
![image-20220303211141174](https://i-blog.csdnimg.cn/blog_migrate/c785d02bba81437c56a0e7ce41014b33.png)
res = models.User.objects.create(username=username, password=password)
print(res, res.username, res.password)
![image-20220303211310554](https://i-blog.csdnimg.cn/blog_migrate/75ea35b2ecdf717bf0868d16312a401b.png)
![image-20220303211653199](https://i-blog.csdnimg.cn/blog_migrate/3cc1b35be7cffb2c1c3188a0df96fe13.png)
10. 编辑功能
要求:
0. 展示所有的用户信息.
1. 点击修改按钮跳转到修改页面,页面中展示用户名和密码
2. 完成后写入数据库.
后端从数据库读取信息传递到前端.
0.后端获取数据库所有的数据
1.后端将数据传入 locals() 名称空间中
2.前端使用模板语法获取名称空间中的数据
10.1 路由层
路由层中写 路由 与 视图函数 的对应关系.
# 在urls.py中添加路由与视图函数的关系.
url(r'^edit', views.edit),
10.2 视图层
def edit(request):
queryset = models.User.objects.all()
return render(request, 'edit.html', locals())
queryset 中有所有的数据信息
locals() 获取当前名称空间所有变量
render() 可以将其他数据传给前端
10.3 编辑页面
在templates创建edit.html.
![image-20220303222520087](https://i-blog.csdnimg.cn/blog_migrate/29b699db8c22910ffdaa0907daf3e4ff.png)
模板语法的 for 循环
{% for obj in queryset %}
obj.方法获取值(循环一次执行一次)
{% endfor %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>编辑页面</title>
{% load static %}
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<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>
</head>
<body>
<div>
<h1 class="text-center">用户数据</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>密码</th>
<th>编辑</th>
</tr>
</thead>
<tbody>
{% for obj in queryset %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.username }}</td>
<td>{{ obj.password }}</td>
<td>
<a href="" class="btn btn-primary btn-xs">编辑</a>
<a href="" class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
![image-20220303232033486](https://i-blog.csdnimg.cn/blog_migrate/742a882588690bcbd7e7c2d81453c6cf.png)
10.4编辑数据
1. a标签跳转网页
点击编辑按钮,提交get请求,携带当前用户的id值到后端.
a便签可以跳转使用本地的路由.
<a href="/edit_user/?user_id={{ user_obj.id }}" class="btn btn-primary btn-xs">编辑</a>
/edit_user/?user_id={{ user_obj.id }}
edit_user 是地址
user_id={{ user_obj.id }} ?号后面跟着user_id = 当前编辑所在行的id
/edit_user/?user_obj.id=1
以get请求方式向 edit_user提交数据
2. 路由层
url(r'^edit_user/', views.edit_user),
3. 视图层
edit_id = request.GET.get('user_id') 获取需要修改的用户id.
def edit_user(request):
print(f'请求方式{request.method}')
user_id = request.GET.get('user_id')
print(request.GET)
print(user_id)
edit_queryset = models.User.objects.filter(id=user_id).first()
return render(request, 'edit_user.html', locals())
4. 编辑用户数据页面
value="{{ edit_querySet.username }} # 展示用户的数据做为修改的参考
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>编辑用户数据</title>
{% load static %}
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<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>
</head>
<body>
<div>
<h1 class="text-center">{{ edit_queryset.username }}的数据</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form action="" method="post">
<p>用户名称:
<input type="text" name="username" class="form-control" value="{{ edit_queryset.username }}">
</p>
<p>用户密码:
<input type="text" name="password" class="form-control" value="{{ edit_queryset.password }}">
</p>
<p>
<input type="submit" class="btn btn-danger btn-block" value="确定修改" >
</p>
</form>
</div>
</div>
</div>
</body>
</html>
![image-20220304011124324](https://i-blog.csdnimg.cn/blog_migrate/4e39b18ebbe56c062f37500e6c82f737.png)
1.选择一个用户的编辑按钮,编辑按钮是一个a标签,
点了a标签相当于在当前url输入了 127.0.0.1:8000/edit_user/?user_obj.id=xx
2.通过路由层执行对应的视图函数
3.视图函数,获取get请求的数据
依据数据去数据库中读取信息
返回一个编辑用户的页面和当前名称空间的变量
4.前端页面使用模板语法获取后端的值
![image-20220304010305348](https://i-blog.csdnimg.cn/blog_migrate/95a4faaa60d8cc83c80f7509eea1d308.png)
5.确定修改
编辑用户数据的页面点击确定修改后,向后端发送POST请求.
从POST请求中获取用户名称和密码.
更新数据库中的值,在跳转到编辑页面edit.html去.
![image-20220304011328070](https://i-blog.csdnimg.cn/blog_migrate/15b23ed7795e6b9c2fcff8cec3aa1c6b.png)
models.User.objects.filter(id=edit_id).update(username=username,password=password) 更新数据.
def edit_user(request):
print(f'请求方式{request.method}')
user_id = request.GET.get('user_id')
print(request.GET)
print(user_id)
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
models.User.objects.filter(id=user_id).update(username=username, password=password)
return redirect('/edit/')
edit_queryset = models.User.objects.filter(id=user_id).first()
return render(request, 'edit_user.html', locals())
![image-20220304014647460](https://i-blog.csdnimg.cn/blog_migrate/dcd448b7f9adc072dc1699f3dc8a5fc4.png)
10.5 删除功能
要求:
0. 点击删除按钮跳转到删除页,页面中展示用户名和密码
1. 确定删除后写入数据库.
后端从数据库读取信息传递到前端.
0.后端获取数据库所有的数据
1.后端将数据传入 locals() 名称空间中
2.前端使用模板语法获取名称空间中的数据
1. a标签跳转网页
点击删除按钮,提交get请求,携带当前用户的id值到后端.
<a href="/delete_user/?user_id={{ obj.id }}" class="btn btn-danger btn-xs">删除</a>
2. 路由层
url(r'^delete_user/', views.delete_user),
3. 视图层
def delete_user(request):
return render(request, 'delete_user.html')
4. 删除页面
在templates下的edit.html的删除标签.
0. 删除页面复制编辑页面的代码,添加input的disabled数据,让input框不可选中.
1. 修改按钮的名称.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>删除用户</title>
{% load static %}
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<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>
</head>
<body>
<div>
<h1 class="text-center">{{ del_queryset.username }}的数据</h1>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form action="" method="post">
<p>用户名称:
<input type="text" name="username" class="form-control" value="{{ del_queryset.username }}" disabled>
</p>
<p>用户密码:
<input type="text" name="password" class="form-control" value="{{ del_queryset.password }}" disabled>
</p>
<p>
<input type="submit" class="btn btn-danger btn-block" value="确定删除" >
</p>
</form>
</div>
</div>
</div>
</body>
</html>
![image-20220304022609576](https://i-blog.csdnimg.cn/blog_migrate/da255145ebf016b1bc14bec07b084e8d.png)
5. 获取用户数据
在视图函数中 写业务逻辑
def delete_user(request):
print(f'请求方式{request.method}')
user_id = request.GET.get('user_id')
print(user_id)
queryset = models.User.objects.filter(id=user_id).first()
return render(request, 'delete_user.html', locals())
![image-20220304022807374](https://i-blog.csdnimg.cn/blog_migrate/1d5d8859232653137c17e066d2421cbd.png)
6. 删除用户数据
删除用户数据的页面点击确定删除之后,向后端发送POST请求.
从POST请求, POST后面跟着这个数据在数据中的id.
通过id删除数据,在跳转到编辑页面edit.html去.
def delete_user(request):
print(f'请求方式{request.method}')
user_id = request.GET.get('user_id')
print(user_id)
if request.method == 'POST':
models.User.objects.filter(id=user_id).delete()
return redirect('/edit/')
del_queryset = models.User.objects.filter(id=user_id).first()
return render(request, 'delete_user.html', locals())
![image-20220304023323846](https://i-blog.csdnimg.cn/blog_migrate/c31f29232f085a24a171ec6908589dfb.png)
7.删除注意点
0.真正的删除功能应该需要二次确认,
1.删除数据内部其实并不去真正的数据.为数据添加一个标识字段来表示当前数据是否被删除了.
如果数据被删了仅仅只是将字段修改了一个状态
userbane password is_delete
kid 123 0
qz 456 1
查询数据时过滤 is_delete = 0
后续使用模板语法的if语句之后都不真删数据了.
11. ORM建立表关系
book(图书) | | | publish(出版社) | | |
---|
id | title | price | id | name | addr |
1 | linux | 123.0 | 1 | 上海出版社 | 上海 |
2 | python | 456.0 | 2 | 北京出版社 | 北京 |
author(作者) | | | authordetail(作者详情) | | |
---|
id | name | age | id | phone | addr |
1 | kid | 18 | 1 | 10086 | 上海 |
2 | qz | 19 | 1 | 10010 | 北京 |
0. 先创建所有的表,与基础字段,
1. 后分析关系添加外键字段.
11.1创建表基表
class Book(models.Model):
title = models.CharField(max_length=32, varbose_name='书名')
price = models.DecimalField(max_digits=8, decimal_places=2, varbose_name='价格')
class Publish(models.Model):
name = models.CharField(max_length=32, varbose_name='出版社名称')
addr = models.CharField(max_length=32, varbosr_name='出版社地址')
class Author(models.Model):
name = models.CharField(max_length=32, varbose_name='作者名字')
age = models.IntegerField(varbose_name='作者年龄')
class AuthorDetail(models.Model):
phone = models.CharField(max_length=32, varbose_name='作者电话')
addr = models.CharField(max_length=32, varbose_name='作者地址')
11.2 确定关系
* 表与表之间:一对一, 一对多, 多对多, 关系判断:换位思考.
![image-20220304150327851](https://i-blog.csdnimg.cn/blog_migrate/a2dee8764a8051cdbdf39b401d22f675.png)
0. 书 与 出版社:
书 能被多个出版社出版吗 X (不抬杠)
出版社能出版多本书吗 √
出版社 一对多 图书
外键建在多的一方(图书这边建外键)
![image-20220304151115970](https://i-blog.csdnimg.cn/blog_migrate/0dbc0d6f3354719fc6ebe4b70c16f2aa.png)
1.书 与 作者:
书可以被多个作者著作 √
多个作者可以著作一本书 √
书 与 作者 多对多的关系,
外键建在查询频率高的一方(图书中建立外键),ORM会自动创建第三张表。
![image-20220304151529907](https://i-blog.csdnimg.cn/blog_migrate/26c800ac4ce3bc01ffd8bb0148793349.png)
2. 作者 与 作者详情:
一个作者可以有个信息 X
一个信息可以给多个作者 X
作者与作者信息有关系 ✓
一对一关系,外键建在查询频率高的一方(作者表)。
11.3 建立外键的方法
# 一对多
外键 = models.ForeignKey(to='被关联表')
# 一对一
外键 = models.OneToOneField(to="被关联表")
* ForeignKey 与 OneToOneField 会自动在字段中添加_id后缀,也就是默认关联主键id
多对多:
虚假字段 = models.ManyToManyField(to="被关联表")
在Django1.x版本中外键默认都是级联更新,级联删除的。
多对多注意点:
书和作者是多对多的关系,外键字段建在任意一方都可以,推荐键在查询频率高的一方,
ORM会自动自动创建第三张表.
设置的外键是一个虚拟的字段主要是用来告诉ORM书表和作者表是多对多的关系,
让ORM自动创建第三张表,在book下建立 名称就是app02_book_authors
虚拟的表中存( 主键id book_id author_id)三个字段.
11.4 建立外键
0. 出版社 一对多 图书 -->外键建在多的一方(图书表中建外键)
![image-20220304170029439](https://i-blog.csdnimg.cn/blog_migrate/d2836e8b359d0ea9f5fc7b0556fb0dbd.png)
1. 书 与 作者 多对多的关系 --> 外键建在查询频率高的一方(图书中建立外键),ORM会自动创建第三张表。
![image-20220304170324077](https://i-blog.csdnimg.cn/blog_migrate/a2e24338b26869e7b875290738b76e0c.png)
2. 作者 一对一 作者详情 --> 外键建在查询频率高的一方(作者表)。
![image-20220304170405390](https://i-blog.csdnimg.cn/blog_migrate/63bef668ecc0dcc4326e3ab5b403b864.png)
class Book(models.Model):
title = models.CharField(max_length=32, varbose_name='书名')
price = models.DecimalField(max_digits=8, decimal_places=2, varbose_name='价格')
publish_id = models.ForeignKey(to='Publish')
author = models.ManyToManyField(to='Author')
class Publish(models.Model):
name = models.CharField(max_length=32, varbose_name='出版社名称')
addr = models.CharField(max_length=32, varbosr_name='出版社地址')
class Author(models.Model):
name = models.CharField(max_length=32, varbose_name='作者名字')
age = models.IntegerField(varbose_name='作者年龄')
AuthorDetail_id = models.OneToOneField(to='AuthorDetail')
class AuthorDetail(models.Model):
phone = models.CharField(max_length=32, varbose_name='作者电话')
addr = models.CharField(max_length=32, varbose_name='作者地址')
11.4数据库迁移
0. python manage.py makemigrations
1. python manage.py migrate
![image-20220304165225255](https://i-blog.csdnimg.cn/blog_migrate/19c0dbffab0a7637f5eccb8076d34486.png)