2.Django 前后端数据交互

文章目录

1. 注册登入项目

项目需求:
1. 127.0.0.1:8080/regisert 进入注册页面
2. 127.0.0.0:8080/login 进入登入页面

2. 项目准备

2.1 新建项目

image-20220302001416163

2.2 结果路径报错问题

修改 Templates 模板文件的路径拼接文件 -->  / 改为 ,

image-20220302001829663

2.3 创建app应用

一个程序必须有一个应用.
在pycharm底部打开终端,输入:
python manage.py startapp app01

image-20220302002007645

2.4 注册app引用

创建的app必须要注册,在settings配置文件中添加注册.
setting.py 的第 33 
INSTALLED_APPS = [
    'django.contrib.admin',
 ····························
    'app02'  # 添加app应用名称
]

image-20220302002207051

3. 登入功能

需求: 在地址栏输入127.0.0.1/login/ 返回一个登入页面

3.1 路由层

路由层中写 路由  视图函数 的对应关系.
# urls.py

from django.conf.urls import url
from django.contrib import admin

# 0.导入视图模块
from app01 import views     

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # 1. 路由与视图函数的关系
    url(r'^login/', views.login)
]

3.2 视图层

打开app01应用的views.py的视图层,写登入函数.
* 所有视图函数都需要接收request形参.
* 使用render函数必须返回request形参.
# views.py
# 0. Django 自动导入 render 函数
from django.shortcuts import render

# 1.接收request参数
def login(request):
    
    # 2.返回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

image-20220302172754540

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>
    <!--0. 引入jQuery 库文件-->
    <script src="/static/js/jquery-3.6.0.min.js"></script>
    <!--1. 引入bootstrap css文件-->
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
    <!--2. 引入bootstrap js文件-->
    <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

1. 令牌
Django的settings.py文件下第122行:

# 静态url 
STATIC_URL = '/static/'  

STATIC_URL设置的值相当于令牌,访问的路径必须以这个令牌的名称开始.
* 令牌名字更改了,所有相关的路径都需要改. 前端

image-20220302163458198

2. 开放
STATICFILES_DIRS 设置静态文件的路径, 设置之后便能正常访问静态文件.
格式:(在令牌后面设置)
STATICFILES_DIRS = [路径1, 路径2, ...]

从前玩后依次从列表中取值,取到则返回,都没有则报错.
# 令牌
STATIC_URL = '/static/' 
# 设置静态文件的路径
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]

image-20220302204840173

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 %}
    <!--0. 引入jQuery 文件-->
    <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
    <!--1. 引入bootstrap css文件-->
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <!--2. 引入bootstrap js文件-->
    <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

测试之后将名字改回来.
# 令牌
STATIC_URL = '/static/'
# 设置静态文件的路径
STATICFILES_DIRS = [
    os.path.join(BASE_DIR,
]

3.6 浏览器缓存

在写django项目的时候可能会出现后端代码修改了,前端页面没有变化.
常见的情况:
1. 在用一个端口开了好几个django项目,一直运行的还是第一个gjango项目
2. 浏览器缓存的问题
	按下 F12 进入开发者模式 点击设置图片
		找到 netword
		    勾选 disable xxxxx 禁用缓存
		    刷新页面
3. 代码有问题.

image-20220302205958581

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

# Create your views here.


# 1.接收request参数
def login(request):
    # 1.1 获取客户端的请求方式
    print(request.method)
    # 2.返回request, 'login.html')

image-20220302211327391

客户端访问服务端是GET请求.

4.2 GET请求提交表单数据

form表单的action属性值可以指定提交的地址.
action值的三种情况:
    1.不写,默认朝当前所有url提交数据.
    2.全写,指定详细位置.
    3.指定后缀/login/
现在不设置action属性的值,在浏览器输入: 127.0.0.1:8000/login
* 当前的url就是我们输入的.

image-20220302212618410

在表单填数据
姓名:kid
密码:123
性别:男
写好后点提交.

image-20220302212940728

from表单默认是get方式提交.

4.3 POST请求提交表单

form 表单的 method 属性可以设置请求方式.
不设置默认是GET请求.
0. 修改from表单的提交方式为post,
1. 浏览器输入: 127.0.0.1:8000/login
2. 写好表单信息后提交数据.
<!--login.html 第21行-->
<form action="" method="post">

4.4 Csrf中间件问题

Django提交post请求的时候需要在配置中注释掉Csrf中间键,否则报错 403.
settings中第
MIDDLEWARE =[
···
 # 'django.middleware.csrf.CsrfViewMiddleware'
···
 ]
没有注释前.

image-20220302214508719

注释掉之后.

image-20220302214753698

post提交表单,表单的数据不会跟当前页面的url后面展示.

4.5 获取POST请求数据

request.POST                  获取用户提交的post请求中除文件外所有数据数据,字典类型.

request.POST.get('xxx')       通过get键取值,如果有多个值,优先取最后一个值.

request.POST.getlist('xx')    如果键对应有多个值则取多个值,返回一个列表.
<!--login.html 第35行 增加一个多选框-->
<p>爱好:
    <input type="checkbox" name="hobby" value="reading"> 看书
    <input type="checkbox" name="hobby" value="learning"> 学习
</p>
app01/views.ps 中添加代码
from django.shortcuts import render


# Create your views here.


# 1.接收request参数
def login(request):
    # 1.1 获取客户端的请求方式
    print(request.method)
    # 1.2判断请求是否为POST
    if request.method == 'POST':
        # 1.3 获取post除文件外所有数据 -->dict
        print(request.POST)
        # 1.4 获取
        print(request.POST.getlist('gender'))
    # 2.返回request, 'login.html')

image-20220302222410112

image-20220302222540458

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')    如果键对应有多个值则取多个值,返回一个列表.
<!--login.html 第21行-->
<form action="" method="get">
from django.shortcuts import render


# Create your views here.


# 1.接收request参数
def login(request):
    # 1.1 获取客户端的请求方式
    print(request.method)
    # 1.2判断请求是否为POST
    if request.method == 'POST':
        # 1.3 获取post除文件外所有数据 -->dict
        print(request.POST)
        # 1.4 获取数据
        print(request.POST.get('username'))
        print(request.POST.getlist('hobby'))

    # 1.6第一次get请求是没有值的,点击按钮提交from表单,填了则有值否则就空字符串.
    if len(request.GET) != 0:
        # 1.7获取数据
        print(request.GET)
        print(request.GET.get('username'))
        print(request.GET.getlist('hobby'))

    # 2.返回request, 'login.html')

image-20220302223744832

# 第一次获取登入页面
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'], 'learning']

4.7 获取POST后面的数据

def login(request):
    # 1.1 获取客户端的请求方式
    print(request.method)
    print(request.GET.get('uuid'))

image-20220304024705744

只要是 路径后面有值就能通过GET.get()取到.

5. 连接数据库

image-20220302224558710

如过没有则去plugins插件搜索darabase安装.
Pycharm可以充当很多款数据库软件的客户端.
第一次选择数据库后记得下载驱动.

5.1 选择数据库

image-20210811181907356

5.2 安装驱动

点DOwnload

image-20210810222340598

5.3 通信配置

填好了先点Test ** 测试先是否能成功连通,
连接的库必须是提前建立好的.
创建库
使用Navicat创建
https://blog.csdn.net/qq_46137324/article/details/119303398
命令行创建
https://blog.csdn.net/qq_46137324/article/details/119150449

image-20210811182447807

5.4 测试成功点ok

image-20210811183104172

5.5 查看数据库

image-20210811183744282

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__,或者任何应用名下书写以下代码
# 0.安装pymysql模块 pip3 install pymysql
import pymysql
pymysql.install_as_MySQLdb()

image-20220303014611597

7. ORM 操作数据库

ORM的作用能够通过Python面向对象的代码简单快捷的操作数据路.
不足之处:封装程度太高,有时候效率低,需要自己写sql语句.
ORM对象关系映射:
   --->  
对象  ---> 记录
对象属性  ---> 记录中的某个字段

7.1 表操作

1.创建表
app应用下面的models.py中创建表.
models.py中书写一个类就是创建一个表,这个类必须继承models.Modeld.
from django.db import models


# Create your models here.

# 0.创建用户表
class User(models.Model):
    # 1.创建字段
    # 1.1 id字段 自增 主键
    id = models.AutoField(primary_key=True, verbose_name='主键')
    # 1.2 用户名称字段 char类型 长度32
    username = models.CharField(max_length=32, verbose_name='用户名称')
    # 1.3 用户密码字段 integer 类型
    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

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

python manage.py migrate 
命令执行migrations里面改动的迁移文件作用到数据库,比如创建数据表,或者增加字段...

image-20220303115007778

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


# Create your models here.

# 0.创建用户表
class User(models.Model):
    # 1.创建字段
    # 1.1 id字段 自增 主键
    id = models.AutoField(primary_key=True, verbose_name='用户名称')
    # 1.3 用户密码字段 integer 类型
    password = models.IntegerField(verbose_name='用户密码')
    # 1.4 用户等级
    lv = models.IntegerField(validators='1', verbose_name='用户等级')
    # 1.5 用户信息
    info = models.CharField(max_length=32, null=True, verbose_name='用户信息')
    # 1.6 用户等级
    hobby = models.CharField(max_length=32, default='reading', verbose_name='爱好')
每次修改了models.py的信息都要,执行数据库迁移迁移命令.
0. python manage.py makemigrations   
1. python manage.py migrate
# 第一钟情况,在终端输入值 1,添加的字段的值都为1
lv = models.IntegerField(validators='1', verbose_name='用户等级')

image-20220303115600891

您试图在没有默认值的情况下向用户添加不可为空的字段“年龄”;
我们不能这样做(数据库需要一些东西来填充现有的行)。

请选择修复程序:
1 现在提供一个一次性默认值(将在所有现有行上设置此列的空值)
2 退出,让我在模型中添加一个默认值。(设置default)
0. 选择1回车
1. 输入值
# 第二种情况 设置null=True字段可以为空,不需要提供值,添加的字段全部为空
info = models.CharField(max_length=32, verbose_name='用户信息')

image-20220303120336081

在检测到为空的时候会有一个警告.
第三情况,设置default默认值,添加的字段全部为默认的值
hobby = models.CharField(max_length=32, default='reading', verbose_name='爱好')

image-20220303120753319

image-20220303122944949

后续新增字段执行python manage.py makemigrations 都会增加一个文件.
第一次创建的在第一个文件中.

image-20220303122439018

2. 更改字段
# 直接修改代码,后执行数据迁移命令
password = models.CharField(max_length=30, validators='密码')

image-20220303123631583

3. 删除字段
* 字段的删除只需要将对应的字段注释掉,(在不写入数据的数据原来的数据还存在,
如果写了数据,被注释字段的数据一样被删除,看下的7.4.2 )
* 直接删除字段,对应的数据会全部丢失.(不要轻易的操作删除字段)
* 操作迁移命令的时候一定要检查自己写的代码,代码搞错了数据会丢失.
#  lv  info 注释掉
# lv ...
# info ...

image-20220303124216083

image-20220303125917384

字段还存在无法写值
4.字段的查拿眼看
...

7.3 制作脚本

脚本可以是应用下的test.py,可以单独开设的别的py文件.
测试环境取manage.py中拷贝前四行代码,然后补上需要的代码.

image-20220303150111798

# 测试模板
from django.test import TestCase

import os
import sys

if __name__ == "__main__": 
    # 如果要复制这个模板 django2.settings 改成当前项目名称
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django2.settings")
    import django

    django.setup()

    # 所有代码必须等待环境准备完毕之后才能书写
    # 0.导入应用下的models模块 这行代码是不允许在配置文件外面
    from app01 import models
    # ↓ 1.从这开始就是需要测试的代码
    
先搭建好,等下要测试从数据库中获取数据.

7.4 数据操作

先在Navicat为app01_user添加数据:
id   username   password
1     kid        123
2     qz         456

image-20220303130033063

* 查增都有一个对象.当对象是一条数据的时候可以使用.点方法的方式取值.
* 改删 返回影响的行数.
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()

    # 所有代码必须等待环境准备完毕之后才能书写
    # 0.导入应用下的models模块 这行代码是不允许在配置文件外面
    from app01 import models

    # 获取表数据操作
    # 1.获取对象
    user_obj = models.User.objects
    print(user_obj)  # app01.User.objects

    # 2.对象的方法
    # 2.1 对象所有的值
    print(user_obj.all())
    """
    <QuerySet [<User: User object>,<User: User object>,<User: User object>]>
    查询对象  列表套对象     一个<> 代表一天数据
    User: 表名
    User object --> 数据现在是看不见的.
    """

image-20220303152309141

User object 是获取的数据,无法显示是以为没有对数据进行输出.
在应用下的models.py 为创建的User类 设置 __str__ 魔方反法
__srt__ 在输入时自动触发
self.xxx  xxx是前面定义过的字段
    def __str__(self):
        return '%s %s' % (self.username, self.password)

image-20220303152251621

    # 2.2 获取单个值
    print(user_obj.all().first())  # kid 123
    print(user_obj.all()[0])  # kid 123
    print(user_obj.all()[1])  # qz 456

image-20220303153311516

    # 2.3 按条件查询表中信息等到一个对象
    user_obj2 = models.User.objects.filter(username='kid')
    # 等于 select * from User where username = 'kid';
    print(user_obj2)  # <QuerySet [<User: kid 123>]>
    print(user_obj2.all())
    print(user_obj2.first())
    print(user_obj2[0])

image-20220303154405518

    res = models.User.objects.first()
    print(res)  # kid 123
    print(res.username)  # kid
    print(res.password)  # 123

image-20220303212338893

2. 增加数据
* 被删除的字段信息和信息被删除
models.表名.objects.create(字段=, 字段=) 添加数据
    # 3.增加数据
    models.User.objects.create(username='hh', password='000')

image-20220303155921889

3. 修改数据
models.表名.objects.filter(查询条件).update(更改的字段=,更改的字段=) 
models.表名.objects.update(更改的字段=,更改的字段=)  修改符合添加的数据
models.表名.objects.filter(查询条件).update(更改的字段=,更改的字段=)  修改整张表
    # 4.修改数据 
    # 修改整张表
    models.User.objects.update(username='qq', password=123)

image-20220303192847242

    # 修改符合添加的数据
    models.User.objects.filter(id=1).update(username='kid')

image-20220303193908322

4. 删除数据
models.表名.objects.delete() 删除整张表的数据
models.表名.objects.filter(删除的条件).delete() 删除符合条件的数据
    # 5.删除数据
    models.User.objects.filter(id=5).delete()

image-20220303194330486

5. 返回对象
* 查增都有一个对象.当对象是一条数据的时候可以使用.点方法的方式取值.
* 改删 返回影响的行数.
    # 查第一条数据
    res = models.User.objects.first()
    print(res, res.id, res.username, res.password)

image-20220303214955483

    # 添加一条数据
    res = models.User.objects.create(username='xx', password='111')
    print(res, res.password)

image-20220303215140343

    # 返回被修改的行数
    res = models.User.objects.filter(id=2).update(username='qwe', password=456)
    print(res)

image-20220303215500964

 	# 删除一条数据
    res = models.User.objects.filter(id=2).delete()
    print(res)

image-20220303215630539

6. 单独更新数据
    # 表中第一条数据
    obj = models.User.objects.first()
    # 对象可以使用方法取值也能改值
    # 修改值
    obj.username = 'sb'
    obj.password = 666
    # .save() 更新到数据库中
    obj.save()  

image-20220304015335323

8.前后端数据校验

读取数据库中的值,与提交的数据进行比对.
0.前端POST请求提交数据.
1.后端从数据库中读取数据&检验数据
<!--login.html 第21行 修改请求方式-->
<form action="" method="post">
<!--login.html 第31-38行 删除 -->

image-20220303135952710

8.1 登入页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登入页面</title>
    {% load static %}
    <!--0. 引入jQuery 文件-->
    <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
    <!--1. 引入bootstrap css文件-->
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <!--2. 引入bootstrap js文件-->
    <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.获取前端的数据
# 前后端数据校验
# 0.1 导入render函数
from django.shortcuts import render
# 0.2 导入app应用的models模块
from app01 import models


# 0.0 视图函数 -->  写逻辑
def login(request):
    # 1.1 获取请求方式  --> GET & POST
    print(f'请求方式为{request.method}')
    # 1.2 判断请求方式:
    if request.method == 'POST':
        # 2.0 获取POST请求的数据
        username = request.POST.get('username')
        password = request.POST.get('password')
        print(f'账户:{username},密码:{password}')
    return render(request, 'login.html')

image-20220303140603981

第二次测试时遇到一个未知问题,前端页面反馈这行报错,无法展示网页.
我想把这行这行注释, 然后就正常了,我在接触注释之前的报错也没出现.

image-20220303201850401

2.获取后端数据&检验
        # 3.0 获取后端所有的数据 (不推荐)
        user_obj = models.User.objects.filter()
        print(user_obj, type(user_obj))
        # 4.在User.py 类中添加 __str__ 方法 来展示 获取的数据

image-20220303200529090

        # 3.0 获取后端的数据 以用户输入的数据作为查询数据库的依据 (推荐)
        user_obj = models.User.objects.filter(username=username, password=password)
        print(user_obj, type(user_obj))
        # 4.在User.py 类中添加 __str__ 方法 来展示 获取的数据

image-20220303200823484

# 前后端数据校验
# 0.1 导入render函数
from django.shortcuts import render
# 0.2 导入app应用的models模块
from app01 import models


# 0.0 视图函数 -->  写逻辑
def login(request):
    # 1.1 获取请求方式  --> GET & POST
    print(f'请求方式为{request.method}')
    # 1.2 判断请求方式:
    if request.method == 'POST':
        # 2.0 获取POST请求的数据
        username = request.POST.get('username')
        password = request.POST.get('password')
        print(f'账户:{username},密码:{password}')

        # 3.0 获取后端的数据
        user_obj = models.User.objects.filter(username=username, type(user_obj))
        # 4.0在User.py 类中添加 __str__ 方法 来展示 获取的数据

        # 5.判断 user_obj 是否为空,在查询到值的时候,坑定不为空,只有在匹配不到值的时候才为空
        if user_obj:
            print('登入成功...')
        else:
            print('账户或密码错误...')
    return render(request, 'login.html')
3.测试
第一次输入正确的账户密码.

image-20220303202139910

第二次输入错误的信息.

image-20220303202245431

可以放回一个页面就不弄了.

9. 注册功能

开设一个注册功输入 127.0.0.1:8000/regisert  进入一个注册页面
0. form 表单中需要获取用户名和密码.
字段为id(自增的)username password
* hobby 字段不用管了.

9.1 路由成

路由层中写 路由  视图函数 的对应关系.
# 在urls.py中添加
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 %}
    <!--0. 引入jQuery 文件-->
    <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
    <!--1. 引入bootstrap css文件-->
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <!--2. 引入bootstrap js文件-->
    <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

9.4 获取前端数据

0. 获取post方式提交的数据.
1. 将信息写入数据库中.
# 注册
def register(request):
    # 6.1 获取请求方式  --> GET & POST
    print(request.method)
    # 6.2 判断请求方式:
    if request.method == 'POST':
        # 7.0 获取前端数据
        in_username = request.POST.get('username')
        in_password = request.POST.get('password')
        in_hobby = request.POST.get('hobby')
        # 8.0 写入数据 
        models.User.objects.create(
            username=in_username, password=in_password, hobby=in_hobby)

        # 9.0 提示注册成功了 在前面导入HttpResponse
        return HttpResponse('注册成功!')

    return render(request, 'register.html')

image-20220303211210067

image-20220303211141174

# 返回值就是当前被创建对象的本身,可以使用点的方式取值
res = models.User.objects.create(username=username, password=password)
print(res, res.password)

image-20220303211310554

image-20220303211653199

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

模板语法的 for 循环 
{% for obj in queryset %}
    obj.方法获取值(循环一次执行一次)	
{% endfor %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>编辑页面</title>
    <!-- 导入需要的文件  动态获取令牌 -->
    {% load static %}
    <!--0. 引入jQuery 文件-->
    <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
    <!--1. 引入bootstrap css 文件-->
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <!--2. 引入bootstrap js 文件-->
    <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
<div>
    <h1 class="text-center">用户数据</h1>
    <!-- 栅格布局 -->
    <div class="row">
        <!-- 一共12格 用6格 右移3格 -->
        <div class="col-md-6 col-md-offset-3">
            <table class="table table-striped table-hover">
                <!-- 表头 -->
                <thead>
                <!-- 一个tr 一行 -->
                <tr>
                    <th>ID</th>
                    <th>姓名</th>
                    <th>密码</th>
                    <th>编辑</th>
                </tr>
                </thead>

                <!-- 表数据 -->
                <tbody>
                {% for obj in queryset %}
                    <!-- 一个tr 一行 有多少行就有多少行 -->
                    <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

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. 路由层
    # urls.py
    # 4. 单个用户数据
    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')  # 获取id
    print(request.GET)
    print(user_id)

    # 通过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 %}
    <!--0. 引入jQuery 文件-->
    <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
    <!--1. 引入bootstrap css文件-->
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <!--2. 引入bootstrap js文件-->
    <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

1.选择一个用户的编辑按钮,编辑按钮是一个a标签,
点了a标签相当于在当前url输入了 127.0.0.1:8000/edit_user/?user_obj.id=xx 
2.通过路由层执行对应的视图函数
3.视图函数,获取get请求的数据
	依据数据去数据库中读取信息
	返回一个编辑用户的页面和当前名称空间的变量
4.前端页面使用模板语法获取后端的值

image-20220304010305348

5.确定修改
编辑用户数据的页面点击确定修改后,向后端发送POST请求.
从POST请求中获取用户名称和密码.
更新数据库中的值,在跳转到编辑页面edit.html去.

image-20220304011328070

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')  # 获取id
    print(request.GET)
    print(user_id)

    if request.method == 'POST':
        # 获取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/')

    # 通过id 获取数据库中的 数据
    edit_queryset = models.User.objects.filter(id=user_id).first()
    # print(edit_queryset)
    return render(request, locals())

image-20220304014647460

10.5 删除功能

要求:
0. 点击删除按钮跳转到删除页,页面中展示用户名和密码
1. 确定删除后写入数据库.
后端从数据库读取信息传递到前端.
0.后端获取数据库所有的数据
1.后端将数据传入 locals() 名称空间中
2.前端使用模板语法获取名称空间中的数据
1. a标签跳转网页
点击删除按钮,携带当前用户的id值到后端.
<a href="/delete_user/?user_id={{ obj.id }}" class="btn btn-danger btn-xs">删除</a>
2. 路由层
    # 5.删除用户数据
    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 %}
    <!--0. 引入jQuery 文件-->
    <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
    <!--1. 引入bootstrap css文件-->
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
    <!--2. 引入bootstrap js文件-->
    <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>用户名称:
                        <!-- 添加 disabled 不可选-->
                        <input type="text" name="username" class="form-control" value="{{ del_queryset.username }}" disabled>
                    </p>
                    <p>用户密码:
                        <!-- 添加 disabled 不可选-->
                        <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

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

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, locals())

image-20220304023323846

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创建表基表

# 2.图书图书表
class Book(models.Model):
    # 2.1 id字段自动创建
    # 2.2 书名
    title = models.CharField(max_length=32, varbose_name='书名')
    # 2.2 价格      双精度小数    最大 数 = 8 位   小数_位 = 2
    price = models.DecimalField(max_digits=8, decimal_places=2, varbose_name='价格')


# 3.出版社
class Publish(models.Model):
    # 3.1 id字段自动创建
    # 3.2 出版社名字
    name = models.CharField(max_length=32, varbose_name='出版社名称')
    # 3.3 出版社地址
    addr = models.CharField(max_length=32, varbosr_name='出版社地址')


# 4.作者基本信息
class Author(models.Model):
    # 4.1 id 字段自动创建
    # 4.2 作者姓名
    name = models.CharField(max_length=32, varbose_name='作者名字')
    # 4.3 作者年龄
    age = models.IntegerField(varbose_name='作者年龄')


# 5. 作者详情表
class AuthorDetail(models.Model):
    # 5.1 id 字段自动创建
    # 5.2 电话
    phone = models.CharField(max_length=32, varbose_name='作者电话')
    # 5.3 地址
    addr = models.CharField(max_length=32, varbose_name='作者地址')

11.2 确定关系

* 表与表之间:一对一, 一对多, 多对多, 关系判断:换位思考.

image-20220304150327851

0.   出版社:
 能被多个出版社出版吗  X  (不抬杠)
出版社能出版多本书吗     

出版社 一对多 图书
外键建在多的一方(图书这边建外键)

image-20220304151115970

1.  作者:
书可以被多个作者著作     
多个作者可以著作一本书   

  作者 多对多的关系,
外键建在查询频率高的一方(图书中建立外键),ORM会自动创建第三张表。

image-20220304151529907

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

1.   作者 多对多的关系 --> 外键建在查询频率高的一方(图书中建立外键),ORM会自动创建第三张表。

image-20220304170324077

2. 作者 一对一 作者详情 --> 外键建在查询频率高的一方(作者表)

image-20220304170405390

# 2.图书图书表
class Book(models.Model):
    # 2.1 id字段自动创建
    # 2.2 书名
    title = models.CharField(max_length=32, varbose_name='价格')
    # 2.3 外键 默认关联出版社的主键 --> id
    publish_id = models.ForeignKey(to='Publish')
    # 2.4 外键 ORM会自动自动创建第三张表
    author = models.ManyToManyField(to='Author')


# 3.出版社
class Publish(models.Model):
    # 3.1 id字段自动创建
    # 3.2 出版社名字
    name = models.CharField(max_length=32, varbose_name='作者名字')
    # 4.3 作者年龄
    age = models.IntegerField(varbose_name='作者年龄')
    # 4.4 外键 默认绑定作者表详情表的主键 --> id
    AuthorDetail_id = models.OneToOneField(to='AuthorDetail')


# 5. 作者详情表
class AuthorDetail(models.Model):
    # 5.1 id 字段自动创建
    # 5.2 电话
    phone = models.CharField(max_length=32, varbose_name='作者地址')

11.4数据库迁移

0. python manage.py makemigrations
1. python manage.py migrate

image-20220304165225255

相关文章

注:所有源代码均实测运行过。所有源代码均已上传CSDN,请有...
继承APIView和ViewSetMixin;作用也与APIView基本类似,提供...
一、Django介绍Python下有许多款不同的 Web 框架。Django是重...
本文从nginx快速掌握到使用,gunicorn快速掌握到使用,实现小...
uniapp微信小程序订阅消息发送服务通知
Django终端打印SQL语句 1 Setting配置: 2 默认python 使用的...