Django框架的开始
首先我们的前端是如何实现从后端提取数据的:就是通过的我们的前端向服务器提供要求,后端通过我们的前端的要求实现返回数据给前端
为什么我们使用Django框架,就是因为我们需要使用这个框架来实现完成我们的web程序的开发
搭建服务器的方法
import socket
socket = socket.socket()
socket.bind(('127.0.0.1', 9999))
socket.listen(5)
while True:
conn, addr = socket.accept()
data = conn.recv(1024)
print(data)
conn.send("hello world".encode("utf-8"))
conn.close()
http协议的基本格式
http协议的基本格式的话,分为请求数据的格式和响应数据的格式
1.http请求数据的格式:
请求首行:请求的http的版本号和请求的方式
请求头:就是一大推键值对,就是一些请求数据
空白行
请求体:get含有请求体,post请求才含有请求体
2.http响应数据的格式:
相应首行:http版本号,响应状态码
响应头:一大推键值对
空白行
响应体:就是服务端的一些响应数据
服务器向前端传送普通的文本的操作
import socket
socket = socket.socket()
socket.bind(('127.0.0.1', 9999))
socket.listen(5)
while True:
conn, addr = socket.accept()
data = conn.recv(1024)
print(data)
conn.send(b"HTTP/1.1 200 ok \r\n\r\n")
conn.send(b"<h1>hello world<h1>")
conn.close()
服务器向前端返回html文件内容
import socket
socket = socket.socket()
socket.bind(('127.0.0.1', 9999))
socket.listen(5)
while True:
conn, addr = socket.accept()
data = conn.recv(1024)
print(data)
conn.send(b"HTTP/1.1 200 ok \r\n\r\n")
with open("text.html", "r", encoding="utf-8") as f:
data = f.read()
conn.send(data)
conn.close()
服务器向前端返回数据库中的内容
import socket
import pymysql
import json
socket = socket.socket()
socket.bind(('127.0.0.1', 9999))
socket.listen(5)
def get_data():
db_conn = pymysql.connect(
host = "127.0.0.1",
user = "juwenzhang",
password = "451674",
database = "db_name",
charset = "utf8"
)
cursor = db_conn.cursor()
sql = """select * from users;"""
cursor.execute(sql)
data = cursor.fetchall()
db_conn.close()
return json.dumps(data, ensure_ascii=False).encode('utf-8')
while True:
conn, addr = socket.accept()
data = conn.recv(1024)
print(data)
conn.send(b"HTTP/1.1 200 ok \r\n\r\n")
conn.send(get_data())
conn.close()
import socket
import pymysql
import json
socket = socket.socket()
socket.bind(('127.0.0.1', 9999))
socket.listen(5)
def get_data():
try:
db_conn = pymysql.connect(
host="127.0.0.1",
user="juwenzhang",
password="451674",
database="db_name",
charset="utf8"
)
cursor = db_conn.cursor()
sql = """select * from users;"""
cursor.execute(sql)
data = cursor.fetchall()
db_conn.close()
return json.dumps(data, ensure_ascii=False).encode('utf-8')
except Exception as e:
return json.dumps({'error 数据出错': str(e)}, ensure_ascii=False).encode('utf-8')
finally:
return b"databases error"
while True:
conn, addr = socket.accept()
data = conn.recv(1024)
print(data)
conn.send(b"HTTP/1.1 200 ok \r\n\r\n")
conn.send(get_data())
conn.close()
import socket
import pymysql
import json
socket = socket.socket()
socket.bind(('127.0.0.1', 9999))
socket.listen(5)
def get_data():
try:
db_conn = pymysql.connect(
host="127.0.0.1",
user="juwenzhang",
password="451674",
database="db_name",
charset="utf8"
)
cursor = db_conn.cursor()
sql = """select * from users;"""
cursor.execute(sql)
data = cursor.fetchall()
db_conn.close()
return json.dumps(data, ensure_ascii=False).encode('utf-8')
except Exception as e:
return json.dumps({'error 数据出错': str(e)}, ensure_ascii=False).encode('utf-8')
finally:
return b"databases error"
while True:
conn, addr = socket.accept()
data = conn.recv(1024)
data01 = data.decode('utf-8').split(" ")
print(data)
print(data01[1])
conn.send(b"HTTP/1.1 200 ok \r\n\r\n")
conn.send(str(get_data()).encode("gbk"))
conn.close()
Django的基本学习
Django的话实现的就是我们的服务器程序和应用程序
python web 程序就是实现的我们的那个这两个部分
服务器程序就是实现的对socket实现的封装,并且在请求的时候,对请求的数据实现整理
应用程序的话,负责对我们的具体的逻辑的处理
所以说为了方便我们的开发,就出现了众多的web框架,Django/ flask等等
最后的话,我们实现的就是那个使用我们的socket的实现
python中的主流的学习的web框架: Django / flask / tornado
Django:大而全,就是功能多并且全面
flask: 小而精,第三方模块十分多
tornado: 异步非阻塞的框架知识,就是支持高并发,支持开发游戏的服务器
我们是可以实现将我们web框架拆分为三个部分:
1.socket服务器的开发
2.路径和函数的匹配关系(路由匹配)
3.模板语法,实现我们将数据插入我们的那个html模板中,就是实现我们将py的变量名实现插入我们的html中去
Django: socket:wsgiref这个服务器
路由匹配: 自己写的
模板语法: 自己写的
flask: socket: 使用的别人的
路由匹配: 自己写的
模板语法: jinja2
tornade: 就是啥都是自己写的(裂开)
注意事项: 如果想要计算机正常启动Django项目,从计算机名称开始到文件的名称都不可以使用中文
Django的话,运行的时候,就是实现的只运行一个py文件
python的解析器的使用的版本不要使用高版本,接下来使用的Django的版本是我们的2.2.12,一般的话高版本的不稳定
安装:Django: pip install django==2.2.12
因为我们实现的就是将不同的功能存放在不同的文件中实现不同的业务逻辑的实现
业务核心逻辑存放的文件:views.py
对应关系(后缀和需要学习的函数): urls.py
Django 的基本操作
Django 命令行操作
首先先切换到想要创建项目的目录中:cd D:
然后实现创建属于自己的想要的创建的目录下面
创建django项目: django-admin startproject 项目名
启动django项目的话,就要切换到我们的项目路径下面: python manage.py runserver
如果遇到环境问题:那么可以在正确的目录下面实现使用 pip install virtualenvwrapper-win
同时我们的创建的时候,我们是可以实现创建我们的一些那个app目录的,这个是用来实现完成每一个特定的功能的
1.创建app的方法是: python manage.py startapp app名称
2.将app的路径添加到配置文件中:settings.py中寻找:INSTALLED_APPS,添加app
templates: 这个目录下面就是实现的存放我们的html文件的
'DIRS': [os.path.join(BASE_DIR, 'templates')],
Django settings.py配置文件介绍
BASE_DIR: 就是获取项目的根目录路径
DEBUG: 用于实现配置我们的Django的启动项目的模式的,True表示在开发环境中处于调试模式,False表示在运行在生产环境中
ALLOWED_HOSTS: 设置允许被访问本项目的主机,[]空列表表示的只有本机在可以访问,就是DEBUG为True的时候使用
["*"] 表示人格主机才可以访问
["地址一", "地址二"]: 就是我们的列表中的这两个地址才可以实现访问
INSTALLED_APPS: 就是实现注册我们的app,注册后我们才可以实现使用这个功能
MIDDLEWARE: 中间件的设置
ROOT_URLCONF: 就是我们的根页面,首先实现的访问的就是我们的这个路径
TEMPLATES: 就是用于存储html文档的路径
WSGI_APPLICATION: 就是我们的服务器的配置
DATABASES: 数据库
URL 统一资源定位符
用于表示的就是互联网上的某个资源的地址(网址)
互联网上的每个文件都含有唯一的url
http协议的默认端口为80,可以省略不写
一般的格式: 协议类型://域名[:端口号]/路径[?query][
urls.py 文件中实现的功能就是实现的将我们的路径和函数实现一一匹配,匹配成功,那么我们就可以实现调用对应的函数
Django响应的三个必备内容
HttpResponse: 返回给我们的浏览器内容就是我们的字符串
render: 实现的是将我们的html文件实现返回给页面
redirect: 实现的是重定向(就是会实现跳转其他的页面)
注意我们的主要的功能是写在我们的那个view.py中的
path("home/", views.home),
def home(request):
return HttpResponse("hello world")
from django.shortcuts import render, HttpResponse, redirect
def home(request):
return HttpResponse("hello world")
def about(request):
return render(request, "index.html")
def content(request):
return redirect("https://www.baidu.com")
urlpatterns = [
path('admin/', admin.site.urls),
path("home/", views.home),
path("about/", views.about),
path("content/", views.content),
]
Django 的路由配置
就是在我们的项目中的那个urls.py中实现的
首先的话,我们的这个函数实现的就是我们的path()
path(路由配置, 视图函数, name)
路由配置就是我们的字符串类型,匹配的请求路径
视图函数: 就是我们的视图函数对应的那个视图函数的名称
name: 实现为我们的地址别名(模板中的地址反向解析的时候使用的)
Django 静态资源
注意我们的静态资源文件的话,能够直接调用使用的文件(js,css,bootstrap),必须放在那个static目录的下面
然后我们是可以在这个下面实现基本的那个分文件的: js目录, css目录, image目录
同时有的时候,我们还需要在我们的那个settings.py中添加一个语句
STATICFILES_DIRS=[os.path.join(BASE_DIR, "static")]
STATIC_URL = '/static/' 但是注意即使是使用那个拼接我们的资源的路径,我们还是需要实现基本的那个加入这个令牌的,课修改
模板语法: {% 导入的路径 %}
"{% static '路径' %}"
![image-20240730061445538]()
form中的action参数:就是书写的发起请求的路径,请求到路径路径后,就触发对应的后端函数,返回相应的数据
不写的时候,就是向我们的当前文件所在的位置提交数据信息
全写url: 就是向我们的这个url提交信息
只写后缀:就是向我们的当前的服务器提交数据信息的
method参数:就是实现的我们的请求方法
Django的路由层
开始讲解我们的每个函数中的request参数的实际意义
首先我们的request就是我们的前端发送过来的请求
其中包含的属性含有method,这个就是我们的前端向后端发送过来的请求方法
Django request的常用的方法
request.method 就是用来实现的是我们的前端的请求方式
==============================================================================================
request.POST 就是用户的post请求实现的提交的普通数据
request.POST.get() 这个就是实现的是活取的是POST请求的时候实现的最后一个元素的值
request.POST.getlist() 就是实现的是活取我们的所有的值,返回的是一个字典
==============================================================================================
==============================================================================================
request.GET 就是用户的GET请求实现的提交的普通数据
request.GET.get() 这个就是实现的是活取的是GET请求的时候实现的最后一个元素的值
request.GET.getlist() 就是实现的是活取我们的所有的值,返回的是一个字典
def login(request):
if request.method == "post" or request.method == "POST":
print(request.POST,"\n")
print(request.POST.get())
return HttpResponse("post请求的登录页面")
else:
return render(request, "login.html")
==============================================================================================
为了实现防止
CSRF的攻击:
<form action="" method="post">{% csrf_token %}
或者说我们就在setting.py文件中添加:
CSRF_TRUSTED_ORIGINS
Django的连接数据库
连接数据库之前我们首先需要做的就是改变我们的setting.py中的DATABASES的设置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME' : 'your_database_name',
'USER' : 'your_user_name',
'PASSWORD' : 'your_password',
'HOST' : '127.0.0.1',
'PORT' : '3306',
'CHARSET': 'utf8'
}
}
=============================================================================================
然后我们的操作数据库就可以实现使用django中的orm方法来实现基本的操作数据库
orm ---- object relative map 的对象关系映射实现的连接数据库
类---表
对象---记录
对象属性---记录某个字段对应的某个值
首先我们的数据库的操作的地就是在models.py
from django.db import models
class User(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=24)
password = models.CharField(max_length=24)
=============================================================================================
实现迁移数据库: 命令行中的运行
python manage.py makemigrations
python ../manage.py migrate
pip install mysqlclient
python.exe -m pip install --upgrade pip
执行完迁移操作后,数据库中就会出现很多的表
==============================================================================================
实现基本的用户登录的校验
def login(request):
if request.method == "post" or request.method == "POST":
print(request.POST,"\n")
print(request.POST.get("username"),request.POST.get("password"))
res = models.User.objects.filter(name=request.POST.get("username"))
if res:
if request.POST.get("password") == res[0].password:
return HttpResponse("post请求的登录页面")
else:
return HttpResponse("密码错误...")
else:
return HttpResponse("用户不存在...")
else:
return render(request, "login.html")
Django 路由匹配
取消路由自动添加斜杠: 就要在我们的那个setting.py文件中设置:
APPEND_SLASH = False
======================================================================================
在我们实现路由匹配的时候,我们的配置就是在urls.py中实现的匹配
然后里面含有一个:
urlpatterns的配置文件
前面我们实现的是使用基本的:path来实现的路由匹配: path("路由名称", 视图函数)
但是我们的还是可以通过基本的re_path方法来实现精准的正则表达式的匹配模式: re_path(正则表达式,视图函数,name)
path('admin/', admin.site.urls),
path("home/", views.home),
path("about/", views.about),
path("content/", views.content),
path("login/", views.login),
# 开始实现基本的re_path的使用方法
re_path('^$', views.home)
=======================================================================================
当我们使用正则匹配括号的时候,那么这个时候我们就会实现基本的将其当作参数传递给函数,这个就是无名分组
re_path("test/(\d+)", view.test)
def test(request, arg):
print(arg)
render(request, "test.html")
=======================================================================================
就是我们是可以给我们的正则表达式来一个别名,基本的格式就是,这个就是我们的有名分组: (?P<别名>)
re_path("test/(?P<year>\d+)", views.test)
def test(request, year):
print(year)
render(request, "test.html")
# 注意我们的无名分组和又名分组不可以混合使用,但是可以实现的是一种正则表达式实现多次使用
re_path("test/(?P<year>\d+)/(?P<month>\d+)/(?P<date>\d+)", views.test)
def test(request, year, month, date):
print(year, month, date)
render(request, "test.html")
Django 反向解析
通过一些方法就可以实现得到一些结果,从而来实现触发一些函数
就是实现的是我们的路由匹配怎么实现改变,我们都可以实现访问这个函数
方法1: 就是给我们的的url取别名即可
前端页面实现的操作
<a href="{% url 'xxx' %}">1234</a>
path("func", view.func, name=xxx)
后端想要解析我们的后缀名,就是实现的reverse来实现的
首先我们需要先导入
from django.shortcuts import render, HttpResponse, redirect, reverse
print(reverse("xxx")) # 就是实现的是得到了最后的那个: func
================================================================================
有名分组和无名分组中的反向解析
re_path("test/(?P<year>\d+)/(?P<month>\d+)/(?P<date>\d+)", views.test, name=time)
<a href="{% url 'time' '1' %}"></a>
print(reverse("time", kwarg={'year':123, 'month':6, 'date':21}))
# 首先我们的time只可以用来实现匹配得到test的内容
Django 的注意事项
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',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load static %}
<link rel="stylesheet" href="">
<script src=""></script>
</head>
<body>
<h1>登录页面</h1>
<form action="" method="post">
username(用户名):<input type="number" placeholder="请输入账号" name="username">
password(密码):<input type="password" placeholder="请输入密码" name="password">
<input type="submit" value="登录">
</form>
</body>
</html>
"""ProjectDjango URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, re_path
from app import views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login, name='login')
]
from django.shortcuts import render, HttpResponse, redirect
from app import models
"""
render 就是用于实现的是返回我们的html页面给前端页面
一般的话,我们的render函数,实现的基本的语法规则就是: 一个是请求参数,一个是html页面
HttpRequest 就是用于实现返回我们的普通的字符串给我们的前端页面
redirect 就是用于实现重定向
"""
"""
request 就是用来实现接收我们的前端返回来的数据
"""
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
res = models.User.objects.filter(username=username)
if res:
if password == res[0].password:
return HttpResponse("登录成功")
else:
return HttpResponse("登录失败,密码错误...")
else:
return HttpResponse("登录失败,用户不存在...")
return render(request, 'login.html')
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME' : 'atm',
'USER' : 'root',
'PASSWORD' : '451674',
'HOST' : '127.0.0.1',
'PORT' : '3306',
'CHARSET': 'utf8'
}
}
from django.db import models
class User(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=24)
password = models.CharField(max_length=24)
python manage.py makemigrations
python manage.py migrate
Django 的登录和注册的后端业务逻辑的实现
from django.shortcuts import render, HttpResponse, redirect
from app import models
# 下面的就是实现的是登录功能的页面的后端业务逻辑
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
# 然后在我们的数据库中实现比对信息是否正确
# filter就是用于实现过滤的
res = models.User.objects.filter(username=username)
if res:
if password == res[0].password:
return HttpResponse("登录成功")
else:
return HttpResponse("登录失败,密码错误...")
else:
return HttpResponse("登录失败,用户不存在...")
return render(request, 'login.html')
# 开始实现注册功能的业务逻辑的实现
def register(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
re_password = request.Post.get('re_password')
# 直接将我们的数据直接传入数据库
if password == re_password:
models.User.objects.create(username=username, password=password)
return redirect('login.html')
else:
return HttpResponse("注册失败,两次密码不一致")
return render(request, 'register.html')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load static %}
<link rel="stylesheet" href="">
<script src=""></script>
</head>
<body>
<h1>登录页面</h1>
<form action="" method="post">
username(用户名):<input type="text" placeholder="请输入账号" name="username"><br>
password(密码):<input type="password" placeholder="请输入密码" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>注册页面</h1>
<form action="" method="post">
username(用户名):<input type="text" placeholder="请输入账号" name="username"><br>
password(密码):<input type="password" placeholder="请输入密码" name="password"><br>
re_password(确认密码):<input type="password" placeholder="再次输入密码" name="re_password"><br>
<input type="submit" value="注册">
</form>
</body>
</html>
Django 实现将我们的后端的所有数据展示给页面
from django.contrib.auth.hashers import make_password, check_password
from django.shortcuts import render, HttpResponse, redirect
from app import models
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
res = models.User.objects.filter(username=username)
if res:
if check_password(password, res[0].password):
return HttpResponse("登录成功")
else:
return HttpResponse("登录失败,密码错误...")
else:
return HttpResponse("登录失败,用户不存在...")
return render(request, 'login.html')
def register(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
re_password = request.POST.get('re_password')
if password == re_password:
models.User.objects.create(username=username, password=make_password(password))
return HttpResponse("登录成功")
else:
return HttpResponse("注册失败,两次密码不一致")
return render(request, 'register.html')
"""
开始我们的基本的功能就是将我们的数据库种的每个数据实现获取出来
然后给我们的前端按钮来实现基本的增加两个按钮
一个编辑,一个删除
"""
def userList(request):
All_User_Data = models.User.objects.all()
return render(request, 'userList.html', {'All_User_Data': All_User_Data})
def edit(request, id):
editId = id
res = models.User.objects.filter(id=id).first()
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
res.update(username=username, password=make_password(password))
return redirect('/userList/')
return render(request, "edit.html", locals())
def delete(request, id):
models.User.objects.filter(id=id).first().delete()
return redirect('/userList/')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>开始我们的数据展示页面</h1>
<div>
<div>
<table>
<thead>
<tr>
<th>id(编号)</th>
<th>username(用户名)</th>
<th>password(用户密码)</th>
<th>method(功能)</th>
</tr>
</thead>
<tbody>
{% for foo in All_User_Data %}
<tr>
<td>{{ foo.id }}</td>
<td>{{ foo.username }}</td>
<td>{{ foo.password }}</td>
<td>
<a href="/edit/{{ foo.id }}/">编辑</a>
<a href="/delete/{{ foo.id }}/">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>需要实现需改的用户名的页面</h1>
<div>
<form action="" method="post">
<div>用户编号(id):{{ editId }}</div>
<div>用户名(username):<input type="text" name="username" value="{{ res.username }}"></div>
<div>密码(password):<input type="password" name="password" value="{{ res.password }}"></div>
<div><input type="submit" value="提交修改"></div>
</form>
</div>
</body>
</html>
Django 的路由分发
就是每一个应用的时候,我们的实现就是实现的是:含有多个app的程序
这个时候,我们的就需要含有属于自己的app和template 以及urls
由于我们的每一个文件的实现都是实现的是:组长在实现我们的合并的时候
就需要在最后整合的时候,实现最后的整合,这一步就利用到了我们的路由分发
这个时候就需要我们在app中再次创建一个urls.py的文件,来实现我们的路由的分配
创建一个新的应用的方法: python manage.py startapp app的名称
实现了这一步之后,我们就可以得到我们的app应用
最后,我们需要实现的就是完成我们在每一个app中创建一个app的urls
urls就是实现的是对应的每一个的路由匹配的功能
from django.contrib import admin
from django.urls import path, re_path, include
from app import urls as app_urls
from app01 import urls as app01_urls
urlpatterns = [
path('admin/', admin.site.urls),
path('app/', include(app_urls)),
path('app01/', include(app01_urls)),
"""
同时我们还是可以实现不用导入模块直接使用的
path('app/', include('app.urls')),
path('app/', include('app.urls')),
"""
]
from django.urls import path, re_path
from app import views
urlpatterns = [
path('login/', views.login),
path('register/', views.register),
path('userList/', views.userList),
re_path('edit/(\d+)/', views.edit),
re_path('delete/(\d+)/', views.delete)
]
from django.urls import path, re_path
from app01 import views
urlpatterns = [
]
"""
同时我们还是会有基本别名空间的
就是当我们在两个不同的路由中实现了命名别名
但是两个别名一致,name
这个时候,我们就需要实现基在总路由中实现
命名空间,namespace
"""
Django 视图层
首先我们的这个函数就是实现的是,我们的py的一个一个的函数来实现的
就是每一个函数就对应每一个视图
然后在这个响应里面,我们的响应前端页面都是需要基本的一些: HttpResponse, render, redirect
视图层就是实现的是用于实现接收web请求并且返回web响应
每一个视图函数都必须是含有第一个参数request
HttpResponse, render, redirect, JsonResponse
我们的这里就需要使用到基本的json模块来实现基本的一些功能
JsonResponse
我们再返回一个字典格式的数据的时候,我们就需要实现基本的一些功能就是: 使用我们的json模块
来实现转化我们的基本的字典数据
然后再通过我们的HttpResponse来实现返回
同时我们还是可以实现通过上面的两个步骤来实现基本的融合为一个步骤来实现
就是直接使用我们的JsonResponse直接实现传递即可
from django.http import JsonResponse
import json
def test(request):
data_dict = {'test': '测试函数', 'data_dict': [1, 2, 3]}
return JsonResponse(data_dict, safe=False)
Django form表单上传文件后端如何实现获取
前端上传文件的时候,就是通过的我们的input框来实现的基本的操作的
然后就是我们需要考虑的就是如何实现基本的如何实现后端获取文件
表单上传文件的时候,我们需要实现的是两件事情:
1.method 必须指定为: post
2.enctype 换成 form-data
enctype 就是我们的 encodetype 的编码类型,默认值是我们的的 application/x-www-form-urlencoded
这个的话我们是不可以实现上传文件,只能获取的是我们的文本数据
multipart/form-data 就是允许的是我们传递的是我们的文本数据,又有文件的二进制格式的数据
request.FILES.get('file') 获取文件的操作
def file(request):
if request.method == 'POST':
print(request.POST)
username = request.POST.get('username')
file_data = request.FILES.get('file')
print(username, file_data.name)
with open(file_data.name, 'wb') as f:
for chunk in file_data.chunks():
f.write(chunk)
return render(request, 'file.html')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
username(用户名):<input type="text" name="username"><br>
select-file(选择文件):<input type="file" name="file"><br>
<input type="submit" value="上传文件">
</form>
</body>
</html>
from django.urls import path, re_path
from app01 import views
urlpatterns = [
path('test/', views.test),
path('file/', views.file)
]
开始实现总结request的方法含有那些:
request.POST.get(键名) 获取数据列表中的最后一个数据
request.POST.getlist(键名) 获取整个列表数据
request.path 获取路径
request.path_info 获取路径
request.get_full_path() 获取路径,这个可以实现获取网页的完整的路径,包括参数
print(request.path, request.path_info, request.get_full_path())
Django 的FBV 和 CBV
FBV 就是一种基于函数的一种处理视图的方式: function basic views
CBV 就是一种基于面向对象的处理视图的方式: class basic views
就是将视图函数的逻辑拆成类下的一个一个的函数,依靠对象中的函数来实现操作我们的视图
from django.http import JsonResponse
from django.views import View
from django.shortcuts import render, HttpResponse
from django.shortcuts import render
class loginView(View):
"""
注意: 当我们看View的底层源码的时候,我们就可以了解得到:就是我们的get和post函数是我们来实现处理页面的时候必须函数
"""
def get(self, request):
return render(request, 'login.html')
def post(self, request):
return HttpResponse("欢迎来到post请求页面")
# 开始实现我们的处理CBV的处理对象的对象: 就是实现的自动调用loginView-> 实现了直接实例化
path('login/', views.loginView.as_view(), name='login'),
Django 模板层
通过我们的模板语法将我们的后端数据实现返回给前端页面
Django 模板层的基本语法
{{ 变量名 }} : 变量相关的处理
{% %}: 逻辑相关的处理
模板语法是可以支持传递所有的数据类型,传递函数的时,可以自动调用函数的,但是仅仅限于无参数函数
class IndexView(View):
def get(self, request):
num = 123
data = [1, 2, 3, 4, 5]
def func():
return 'hello world'
class Myclass:
def get_method(self):
return 'get_method'
@classmethod
def get_class(cls):
return 'Myclass'
@staticmethod
def get_static():
return 'static'
myclass = Myclass()
return render(request, 'indexNew.html', locals())
def post(self, request):
return HttpResponse("post请求页面")
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>整形数据:{{ num }}</p>
<p>列表数据:{{ data }}</p>
<p>函数数据:{{ func }}</p>
<br>
<p>{{ Myclass }}</p>
<p>类中的对象绑定方法:{{ Myclass.get_method }}</p>
<p>类中的类绑定方法:{{ Myclass.get_class }}</p>
<p>类中的静态方法:{{ Myclass.get_static }}</p>
<br>
<p>{{ myclass }}</p>
<p>实例化对象中的对象绑定方法:{{ myclass.get_method }}</p>
<p>实例化对象中的类绑定方法:{{ myclass.get_class }}</p>
<p>实例化对象中的静态方法:{{ myclass.get_static }}</p>
<br/>
<ul>
{% for dataItem in data %}
<li>{{ dataItem }}</li>
{% endfor %}
</ul>
</body>
</html>
Django 模板语法逻辑处理(过滤器)
首先我们的过滤器的话,最多包含两个参数
这个就相当于是我们的内置函数
django中含有多种过滤器,但是内置的只需要了解几个就行了
基本的语法: {{ 数据|过滤器:参数 }}
第一种:实现统计我们的字符串的长度
<p>{{ str|length }}</p>
第二种:实现默认值的操作
<p>{{ bool|default:"啥也不是" }}</p>
第三种:实现获取文件大小,本质上就是实现的将一串数字转换为文件大小的格式
<p>{{ files|filesizeformat }}</p>
第三种:实现我们的日期格式
<p>{{ current_time|date:'Y-m-d h:i:s' }}</p>
Y 表示的年, m表示的月, d表示的日, h表示的小时, i表示的是分, s表示的秒
第四种:切片操作
<p>{{ list|slice:'0:4:2' }}</p>
第五种:实现截取单词
<p>截取英文:{ eng|truncatewords:10 }}</p>
<p>截取中文:{{ china|truncatechars:10 }}</p>
第六种:移除空格
<p>移除空格:{{ eng|cut:' ' }}</p>
第七种:拼接操作
<p>{{ list|join:'%' }}</p>
第八种: 转义
后端数据为: data = '<h1>你好呀</h1>'
<p>{{ data|safe }}</p>
<!-- 注意我们实现的是通过在前端页面来对数据实现的处理,我们也是可以通过后端数据处理后再实现返回给前端是一样的 -->
Django 中的模板语法逻辑操作
1.在前端页面的for循环的操作:
{% for item in 可迭代对象 %}
前端标签
{% endfor %}
这种模板语法常用于我们的列表的操作的实现
例子:
<ul>
{% for dataItem in data %}
<li>{{ dataItem }}-{{ forloop }}</li>
{% endfor %}
</ul>
2.在前端页面中的if判断
{% if 条件 %}
内部代码
{% elif 条件 %}
内部前端代码
{% else %}
内部代码
{% endif %}
同时这两个是可以实现同时混合使用的
自己思考,我就不写了(不要问为什么,我懒,哈哈),通过的是我们的forloop来实现的
forloop.first 就是我们的第一次操作
forloop.last 就是我们的最后一次的操作
Django 自定义过滤器、标签、inclusion_tag
1.在我们的应用文件下面实现创建一个文件叫做: templatetags 的文件夹
这个里面就是实现的是存放我们的一些自定义的标签
2.在templatetags 的文件夹的下面自定义一个任意名称的 .py 文件
3.在我们的 py文件中写入固定的两句代码
from django import template
变量 = template.Library() # 实现实例化一个类出来
4.注意事项,我们的自定义过滤器的话,参数最多含有两个
from django import template
register = template.Library()
@register.filter(name='get_sum')
def get_sum(v1: int, v2: int):
return v1 + v2
@register.simple_tag(name='get_three_sum')
def get_three_sum(num_list: list) -> int:
return sum(num_list)
@register.inclusion_tag('base.html')
def left_lap(n: int):
data = ['第{}项'.format(i+1) for i in range(n)]
return locals()
{% load mytags %}
<p>{{ num | get_sum:666 }}</p>
<p>{% get_three_sum data %}</p>
{% left_lap 6 %}}
<ul>
{% for foo in data %}
<li>{{ foo }} </li>
{% endfor %}
</ul>
Django 模板继承
我们实现模板继承的原因: 就是因为我们在做一些网络页面的时候,其中包含了很多的子页面
然后实现的就是实现的模板继承来实现基本的简化前端代码的书写工作
实现继承模板的方法就是:就是直接在我们的html中是按继承我们的父类模板即可
{% extends '模板.html' %} 这个就可以实现我们的继承模板
我们通过发现就可以知道,一个模板中我们需要实现修改的页面的部分
这个时候我们就要将我们需要实现修改的地方直接使用我们另一个模板语法来实现,注意我们也是需要在模板中实现这一步操作
{% block 区域名 %}
别修改区域
{% endblock %}
一般来说的话,我们的实现的话,一般至少含有三块我们需要修改的区域: js区域,CSS区域, html区域
注意我们的模板继承的话,我们实现的就是基本的一些整个页面的导入
但是当我们使用到了后面的那个模板带入的话,就是使用的是我们的: {% include '模板。html' %}
通过这个我们就可以实现基本的导入局部的一些基本的样式
由于我们的前后端实现了分离,我们只用对模板层了解即可,不用做太多的了解事情
Django orm操作数据库
注意我们的那个django的内置的数据库的话是使用的是我们的sqlite
但是我们需要实现使用的是我们的mysql数据库
注意我们实现迁移数据库的时候,报错的话,应该就是我们没有第三方模块: mysqlclient
这个时候就需要我们实现下载即可
前面是有的,回头看就行了
但是操作数据之前,必须本地是具有数据库的
否则就不行,去mysql官网实现下载即可,然后像csdn搜索如何配置mysql即可
Django 操作数据库的简单操作
首先我们实现操作数据库的时候,在django中使用的是我们的是映射关系来实现的连接数据库
具体的操作数据库的话,就是通过的我们的models.py文件中实现的基本的操作
from django.db import models
class UserInfo(models.Model):
username = models.CharField(max_length=50)
userAge = models.IntegerField()
password = models.CharField(max_length=50)
email = models.CharField(max_length=50)
register_time = models.DateTimeField(auto_now=True)
"""
auto_now 就是在我们每次实现操作数据的时候,那个字段会实现自动将当前的时间实现更新
auto_now_add 就是在我们的创建的时候,就是这个时间,后面就不会随着我们的操作实现修改
上面的两个是二选一,相互排斥的
"""
def __str__(self):
return self.username
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ProjectDjango.settings')
import django
django.setup()
from app01 import models
import datetime
res = models.UserInfo.objects.all()
print(res)
current_time = datetime.datetime.now()
user_obj = models.UserInfo.objects.create(username='test', password='<PASSWORD>',
userAge=16, email='<EMAIL>', register_time=current_time)
print(user_obj)
user_obj.save()
res01 = models.UserInfo.objects.all().filter(username="test").delete()
print(res01)
res02 = models.UserInfo.objects.filter(username='test').first()
print(res02)
models.UserInfo.objects.filter(username='test').update(userAge=20)
user_obj.save()
"""
在我们的上面的展示中:
我们实现得到的是:
1.filter()
2.all()
3.update()
4.delete()
5.first()
6.values() 就是实现的获取我们的传入的字段名的数据
7.distinct() 就是实现的是数据根据字段名来去重
8.order_by() 就是传入某个字段名,实现根据字段名来排序,默认是升序排列
"""
django实现操作数据库的常用的方法:
models.表名.objects.下面的方法
all(): 就是实现的是查询数据库中的表的所有的数据
filter(): 就是实现的根据字段名来实现过滤
get(): 就是实现的是直接拿到我们的数据对象
first(): 就是实现的是获取的第一个元素
last(): 就是实现的是获取我们的最后一个元素
values(): 就是实现的获取指定的数据字段
values_list(): 就是实现的是获取我们的数据字段
distinct() 就是实现的是去重的操作
order_by(): 就是我们的排序
reverse(): 就是实现的反转
count() 就是实现的是统计当前的数据的个数
exclude() 就是实现的是将查询的数据实现取反,就是除了这个的数据实现查询出来
exist() 就是用来实现的是判断某个对象是否存在,返回bool值
result = models.UserInfo.objects
print(result.count())
print(result.filter(id=4).exists())
Django 的 orm区别于mysql的用法
大于: __gt
小于: __lt
大于等于: __gte
小于等于: __lte
在某个范围区间的用法: __in
寻找区间:__range
模糊查询:
__contains 区分大小写
__icontains 不区分大小写
from django.test import TestCase
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ProjectDjango.settings')
import django
django.setup()
from app01 import models
import datetime
data = models.UserInfo.objects
print(data.filter(userAge__gt=10, userAge__lt=20))
print(data.filter(userAge__gte=10, userAge__lte=20))
print(data.filter(userAge__in=[16, 19, 20]))
print(data.filter(userAge__range=[16, 20]))
print(data.filter(username__icontains='T'))
print(data.filter(username__istartswith='T'))
print(data.filter(username__iendswith='T'))
print(data.filter(register_time__month="08"))
print(data.filter(register_time__year="2024"))
注意事项:数据的表的创建的话,会实现我们的自动创建我们的组件
Django 的字段类型/参数/关系字段
字段类型
AutoField 自动增长的整型
IntergeField 整型类型(不可以实现存放手机号)
DecimalField 浮点型的字段,需要两个参数,第一位(max_digits)表示总共的位数,第二位(decimal_places)表示小数点后面的数字个数
BooleanField 布尔字段,True/False
NullBooleanField Null/True/False
CharField 字符串类型,必须指定参数max_length最长长度来表示最大字符数
TextField 大文本,一半超过4000字符的时候使用
DateField: 日期,auto_now(每次操作数据库时候,自动更新时间),auto_now_add(创建数据的时候记录的时间)【年月日】
TimeField: 日期,同时都是含有两个可选参数的,就是上面的两个【时分秒】
DateTimeField: 日期,包含了年月日时分秒,还是含有两个可选参数的
FileField: 就是用于实现存储文件的数据
ImageField: 就是用来保存图片的字段,确保存放的是图片
EmailField:就是我们的邮箱,用来实现的是校验是否复合我们的格式
字段参数
null 默认的是表示某个字段可以为空
unique 设置为true,就表示这个字段是唯一的
default 设置我们的默认值
db_column 表示的是表的名称,如果没有设定那么就直接设置为我们的属性名
db_index 给表中的字段添加索引
primary_key 表示的是添加主键
关系字段
ForeignKey 外键(创建一对多的关系)
参数: to: 设置关联的表格,可选
to_filed 需要关联的字段,可选
on_delete 当删除关联表的数据时,当前表和关联表的行为,一般的话就是给一个;models.CASCADM
就是实现的是删除关联数据的时候,与之关联的也删除
OneToOneField 就是一对一,参数和我们的上面一样
ManyToManyField 多对多,自动创建第三张关系表
创建表以及表之间关系
from django.db import models
"""
开始实现创建我们的图书表
1.图书表
2.出版社
3.作者
4.作者详情
图书表和出版社之间的关系就是:一个图书表中含有多种图书,但是每种图书来袭不同的出版社,这个就是一对多的关系
图书表和作者: 一本图书含有多个作者,一个作者可以写多本图书,就是我们的多对多关系
作者和作者详情是一对一的关系
"""
class Book(models.Model):
book_title = models.CharField(max_length=50)
book_price = models.DecimalField(max_digits=10, decimal_places=2)
book_publish_time = models.DateTimeField(auto_now_add=True)
book_publisher = models.ForeignKey(to='Publisher',
on_delete=models.CASCADE)
book_authors = models.ManyToManyField(to='Author')
class Publisher(models.Model):
publisher_name = models.CharField(max_length=50)
publisher_address = models.CharField(max_length=50)
publisher_email = models.EmailField()
class Author(models.Model):
author_name = models.CharField(max_length=50)
author_age = models.IntegerField()
author_detail_info = models.OneToOneField(to='AuthorDetailInfo',
on_delete=models.CASCADE)
class AuthorDetailInfo(models.Model):
author_address = models.CharField(max_length=50)
author_email = models.EmailField()
测试环境中实现增删改查
from django.test import TestCase
import os
import app01
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ProjectDjango.settings')
import django
django.setup()
from app01 import models
Django 正反向概念
正方向概念: 上面的书籍表和出版社表,外键字段在书籍表中,通过书籍表来实现查询出版社信息,就是正向
反方向概念: 通过出版社查询书籍,那么就是反向
多表查询
子查询
就是基于对象的连表查询
from django.test import TestCase
import os
import app01
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ProjectDjango.settings')
import django
django.setup()
from app01 import models
book_obj = models.Book.objects.filter(pk=9).first()
res = book_obj.book_publisher
print(res)
print(res.publisher_name)
print(res.publisher_email)
print(res.publisher_address)
res01 = book_obj.book_authors.all()
print(res01[0])
author_obj = models.Author.objects.filter(pk=1).first()
res02 = author_obj.author_detail_info
print(res02.author_address)
print(res02.author_email)
print(res02.id)
publisher_obj = models.Publisher.objects.filter(publisher_name="东方出版者").first()
print(publisher_obj.book_set.all())
print(publisher_obj.publisher_address)
连表查询
就是实现的是基于上下划线的查询
from django.test import TestCase
import os
import app01
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ProjectDjango.settings')
import django
django.setup()
from app01 import models
res = (models.Author.objects.filter(pk=1).
values("author_detail_info__author_address"))
print(res)
res01 = models.Author.objects.filter(author_detail_info__pk=1).values("author_name")
print(res01)
print(models.Book.objects.filter(pk=10).values("book_authors__author_detail_info__author_email"))
聚合查询
就是使用的是我们的aggregate
聚合查询的话,通常是和我们的分组查询annoatae来实现的联合使用
其中我们的聚合查询含有:
1.count
2.sum
3.max
4.mina
5.avg
首先使用的时候,需要导入那个
from django.db.models import Count, Max, Min, Avg, Sum
from django.db.models import Count, Max, Min, Avg, Sum
print(models.Book.objects.aggregate(Sum('book_price'),
Avg('book_price'),
Count('book_price')))
res = (models.Book.objects.annotate(author_num=Count("book_authors")).
values("book_title", "author_num")).all()
print(res)
res = models.Publisher.objects.annotate(min_price=Min("book__book_price")).\
values("book__book_title", "publisher_name", "min_price")
print(res)
res = (models.Book.objects.annotate(num=Count("book_authors")).filter(num__gte=1).
values("book_title", "num")).all()
print(res)
F 和 Q 查询
如果说我们实现迁移数据库后,我们还要实现的基本的添加新的字段,那么就要给一个默认值
from django.db.moodels import F,Q
F可以帮助我们查询出来每一个对应的字段的对应的值
Q查询就是可以实现的是我们的实现基本的条件查询,就是实现的是:and or not 的联合使用
如果说我们的数据的话,实现的是基本的那个filter中使用的是,来实现的连接两个的话,那么默认的就是我们的Q查询
Django 其他参数
choices 参数
针对某些可以实现完全列举的可能性的字段,我们就可以实现通过choices来实现保存我们的可选参数
class User(models.Model):
user_name = models.CharField(max_length=100)
user_age = models.IntegerField()
user_gender_choices = (
(1, "男"),
(2, "女"),
(3, "保密")
)
user_gender = models.IntegerField(choices=user_gender_choices)
user_email = models.EmailField(max_length=100)
user_password = models.CharField(max_length=100)
from django.test import TestCase
import os
if __name__=="__main__":
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'book_admin.settings')
import django
django.setup()
from app01 import models
user_obj = models.User.objects
print(user_obj.first().user_gender)
print(user_obj.first().get_user_gender_display())
class User(models.Model):
user_name = models.CharField(max_length=100)
user_age = models.IntegerField()
user_gender_choices = (
(1, "男"),
(2, "女"),
(3, "保密")
)
user_gender = models.IntegerField(choices=user_gender_choices)
score = (
("A", "优秀"),
("B", "良好"),
("C", "挺不错")
)
user_score = models.CharField(choices=score, max_length=10, default=1)
user_email = models.EmailField(max_length=100)
user_password = models.CharField(max_length=100)
多对多三种创建方式
1.就是使用我们的orm来实现自动的创建第三张表: 就是直接通过我们的ManyToManyField 来实现的:建议使用就是这个,方便简洁
2.就是实现的是纯手动的创建我们的第三张表: 就是通过的是我们的ForeignKey来实现的
3.就是实现的是我们的半自动来实现的,就是一半的是自动,一半的是我们的手动
了解即可,代码就不来了
Django框架进阶
Django Ajax
首先我们在学习的前端时候,里面也是有一个Ajax的,这个时候,就体现了一句话Ajax是属于每种编程语言中的技术的
Ajax 就是实现的是: 发起异步请求,然后提交,实现最后的局部刷新
在我们的前面实现的是我们的前端通过input的提交按钮来实现向后端发送请求,然后后端实现处理数据,同时最后实现刷新整个页面
但是使用我们的ajax的时候,就是实现的向我们的后端实现请求,然后最后实现的是局部刷新
动态的获取用户实时的数据,然后和后端的数据实现校验,实现实时的展示给前端
前端向后端发送请求方法
1.浏览器的地址栏中直接输入我们的url,然后就可以实现发送请求,是我们的get请求
2.通过a标签来实现发发送请求,get请求
3.form表单来实现我们的提交请求: 默认的是我们的get请求,但是可以通过我们的method来实现我们的发送:post请求
4.通过ajax技术来实现的请求: get / post
Ajax: 在不刷新整个页面的情况下来实现的是和服务器交换数据,然后进行局部的刷新
通过我们的ajax的请求的时候,还是可以实现的就是我们的以键值对的形式来让我们的后端实现修改数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load static %}
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<script src="{% static 'jquery_3.6.0.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
</head>
<body>
<input type="text" id="i1">
<br>
<input type="text" id="i2">
<br>
<button id="btn">获取总和</button>
<input type="text" id="i3">
<script>
jQuery("#btn").click(function() {
console.log("我执行了")
$.ajax({
url:"",
type:'post',
data:{'inputData01':$('#i1').val(), 'inputData02':$('#i2').val()},
success: function (args) {
$('#i3').val(args)
}
})
})
</script>
</body>
</html>
from django.shortcuts import render, HttpResponse, redirect
def test(request) -> HttpResponse:
if request.method == 'POST':
inputData01 = request.POST.get('inputData01')
inputData02 = request.POST.get('inputData02')
print(inputData01, inputData02)
inputData03 = int(inputData01) + int(inputData02)
return HttpResponse(inputData03)
return render(request, "test.html", locals())
在我们的后端的中实现是那个: HttpResponse 实现的返回的数据,那么就不会自动的反序列化
JsonResponse 返回的数据,回调函数就会自动反序列化
前后端传输数据的编码格式(contentType)
这个的编码格式的话,一般我们实现考虑就是考虑的就是我们的post请求
可以向后端提交post请求的方法: form表单, ajax请求
1.urlencoded: 就是用来实现的是传输文本格式
2.formdata: 就是实现的是传输我们的文件格式
3.json: 就是实现的是用来实现传输json数据
form 默认的传输的数据格式就是我们的: urlencoded,这个就是我们的文本格式
数据格式就是我们的: username=xxx&age=10
form-data的数据格式的话,就不可以通过我们的network直接看到我们的数据,这种模式的话,是专门针对于我们的文件格式来实现的
只可以通过我们的request.FILES来实现我们的接收数据
我们的form表单是不可以实现传输json格式的数据的
https:
ajax的数据格式
默认的编码格式为: urlencoded,后端实现的是通过我们的:request.POST来实现的请求
发送json格式的数据:
实现传递的时候,需要的是那个:使用我们的contentType:application/json
同时实现使用我们的JSON,stringify({})
在后端实现的时候,就是实现的是使用我们的:request,body来实现我们的那个: 获取我们的数据,默认传递的是我们的二进制的值,然后实现使用我们的那个:json.loads来实现反序列化
发送文件格式的数据的时候的操作:
js的内置对象:FormData 来实现我们的处理数据
let formDataObj = new FormData()
// 实现是先放入我们的键值对
formDataObj.append(“username”, $("#elementID"))
contentType:false, // 就是实现的是不需要任何的编码
processData:false // 就是实现的是让浏览器不要对数据实现处理
后端实现的获取的方法是: request.FILES 来实现我们的接收数据
form: enctype:"multipart/form-data"
这个时候我们的django可以实现的就是我们的将我们的: 对应的数据存放于对应的方法中:request.POST 和 request.FILES中
Django 后端分页的操作
分页的就是实现的是我们的那个: 每个页面中实现只展示固定个数的数据,并不是将所有的数据全部实现展示在我们的那个一个页面中
基本的思路就是实现的是我们的切片的操作
在实现我们的分页的操作的时候,我们的参数含有: 访问哪一个页面, 一页中含有多少数据, 开始实现展示的位置和结束位置
def pages_data(request):
book_list - models.Book.objects.all()
all_count = book_list.count()
try:
current_page = int(request.GET.get('page'))
except ValueError:
current_page = 1
current_user = request.GET.get('user')
per_page_num = 10
start_num = (current_page - 1) * per_page_num
end_num = current_page * per_page_num
page_num, more = divmod(all_count, per_page_num)
if more:
page_num += 1
show_data = models.Book.objects.all()[start_num:end_num]
clone_current_page = current_page
if clone_current_page < 6:
current_page = 6
for i in range(current_page - 5, current_page + 6):
if clone_current_page == i:
page_html = '<li class="blue"><a href="?page=%s">%s</a></li>' % (i, i)
else:
page_html = '<li><a href="?page=%s">%s</a></li>' % (i, i)
return render(request, "page.html", locals())
Django form组件
登录原生代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load static %}
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<script src="{% static 'jquery_3.6.0.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
</head>
<body>
<div style=>
<form action="" method="post" enctype="application/x-www-form-urlencoded">
<p>
<input type="text" placeholder="请输入用户名" name="username"><br>
<span style="color:red">{{ back_error_info.username }}</span>
</p>
<p>
<input type="text" placeholder="请输入密码" name="password"><br>
<span style="color:red">{{ back_error_info.password }}</span>
</p>
<input type="submit" value="登录">
</form>
</div>
</body>
</html>
from django.shortcuts import render, HttpResponse, redirect
def login_view(request):
back_error_info = {"username": "", "password": ""}
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if username:
if '666' in username:
back_error_info["username"] = "用户名设置不正确,请重新设置"
else:
back_error_info["username"] = "用户名未输入"
if password:
if len(password) < 8:
back_error_info["password"] = "密码少于8位,请重新设置"
else:
back_error_info["password"] = "用户密码未输入"
return render(request, "login_view.html", locals())
django 的内置form组件
class MyForm(forms.Form):
username = forms.CharField(min_length=1, max_length=10)
password = forms.CharField(min_length=8, max_length=15)
email = forms.EmailField()
import os
import django
from django.test import TestCase
if __name__ == "__main__":
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_pro.settings')
django.setup()
from LoginPage import views
form_obj = views.MyForm(
{
"username": "test",
"password": "ndsj",
"email": "123"
})
print(form_obj.is_valid())
print(form_obj.errors)
print(form_obj.cleaned_data)
实现渲染
只用用来实现渲染我们的用于实现输入的input框,不可以实现渲染我们的提交按钮
我们的实现渲染的话,就可以在最后的自定义的开始渲染
使用我们的内置的表单组件的时候,实现的时候分为三个步骤: 就是实现的是我们的:
1.生成我们的表单类
2.开始在前端页面实现渲染
3.实现展示报错信息
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="" method="post" novalidate>
<p>第三种的渲染方法</p>
{% for item in form_obj %}
<p>{{ item.label }}:{{ item }}</p>
<span style="color: red">{{ item.errors.0 }}</span>
{% endfor %}
<input type="submit" value="提交">
</form>
</body>
</html>
class MyForm(forms.Form):
username = forms.CharField(min_length=1, max_length=10, label="用户名")
password = forms.CharField(min_length=8, max_length=15, label="密码")
email = forms.EmailField(label="邮箱")
def index(request):
form_obj = MyForm()
if request.method == "POST":
form_obj = MyForm(request.POST)
if (form_obj.is_valid()):
return HttpResponse("登录成功")
else:
pass
return render(request, 'index.html', locals())
这些的话实际上不管用,好好的实现我们的那个ajax请求就可以了,不用使用我们的这些模板语法的,了解即可,用的不多的
玩玩就行了
Django session和cookie
cookie + session
我们的http请求的话原本就是一个无状态的,就是实现的是将我们的用户名和密码通过cookie来实现保存起来
就是我们的服务器实现的是服务器将我们的用户信息实现保存,然后用户在下次实现访问这个页面的时候就可以是自动的登录
cookie 就是是是实现的是通过服务器发送出来是实现存储在浏览器中的一些键值对,下一次是实现基本的访问相同的页面的时候,我们就可以直接
免登录,就是用来保存我们的用户的个人信息的
session 就是实现的就是我们的最终的数据保存在服务端,同时他的保存形式是键值对实现的保存
从总的概述来说,我们的cookie 就是实现的是我们的保存在浏览器端的信息
然后我们的session就是实现的是我们的保存在服务端的信息
然后在我们的服务端的实现的那个保存cookie就是通过的是我们的最终的那个;
在视图函数中是实现的返回值的设置
就是通过的我们的最终的那个: return obj 来实现的返回
这个obj 的话就是是实现的是最基本的那个: 创建的HttResponse对象来实现的操作
通过的我们的最终的obj来实现的操作cookie
设置/获取cookie
就是通过的是我们的: set_cookie(key, value) 来实现的我们的操作cookie
获取cookie: 就是通过的是我们的request.COOKIES.get('key')来实现的获取cookie值
登录和登出的业务逻辑
def login(request):
if request.method == "POST":
username = request.POST.get('username')
password = request.POST.get('password')
if username and password:
url = request.Get.get('next')
if url:
obj = redirect(url)
else:
obj = redirect('home')
obj.set_cookie('username', username, 'password', password, max_age=3600)
return obj
def login_auth(func):
def inner(request, *args, **kwargs):
url = request.get_full_path()
if request.COOKIES.get('username') and request.COOKIES.get('password'):
return func(request, *args, **kwargs)
else:
return redirect('login/?next=%s/' % url)
return inner
@login_auth
def home(request):
return HttpResponse("已有cookie,欢迎来到首页界面")
@login_auth
def logout(request):
obj = redirect('login/?next=%s/' % request.path)
obj.delete_cookie('username')
return obj
session 的操作
当用户实现登陆后,服务器产生一个随机字符串,交给浏览器来实现保存
实现获取我们的session的方法就是:
request.session.get("key")
django对session操作的本质
设置session:
1.django 就是实现的是我们的随机生成一个随机字符串
2.然后实现的就是将我们的这个随机字符串存储于我们的django_session的表中
3.最后实现的是返回这个生成的随机字符串返回给客户端浏览器实现保存
request.session[key] = value
获取session:
1.自动的从浏览器请求中获取sessionid对应的字符串
2.然后实现的就是实现的是拿着这个sessionid的的字符串来实现基本的从表中实现查找对应的数据
3.和数据库实现了匹配成功,那么这个时候就直接返回数据,否则就是None
request.session.get(key)
我们的django的中的session表中的数据条数只会有一条数据(相同的一台电脑和浏览器)
同台电脑和不同浏览器的时候,那么有几个浏览器实现了访问,我们的最终的呈现的效果就是:和浏览器个数一致
django的默认的session过期时间是:14天
同时我们是可以实现通过函数来设置我们的过期时间的
request.session.set_expiry()
括号中的参数设置:整数(s)
日期对象:指定过期日期
0:就是一旦关闭浏览器就失效
没得: 就是默认的django设置的时间:14天
清除session的数据
request.session.delete() 就是实现的将服务端的数据全部删除完
request.session.flush() 这个就是实现的是将服务端和客户端的数据实现全部删除
Django 中间件
请求来的时候,需要我们经过中间件,我们才可以达到django的后端服务器
响应走的时候,我们也是需要经过中间件才可以实现发送出去
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',
]
Django 自定义中间件
我们django的自定义中间件含有五个,但是比较重要就只有两个:
两个必须掌握:
process_request
process_response
三个了解:
process_view
process_template_response
process_exception
自定义中间件的方法:
1.首先先在我们的项目名中开始自定义文件夹
2.然后实现我们的自定义一个py文件(但是我们必须继承: MiddlewareMixin)
3.然后在这个类中书写这五个方法,需要书写那些就写那些
4.最后就实现的是添加到上面的中间件的配置文件中
from django.utils.deprecation import MiddlewareMixin
class MyMiddleware(MiddlewareMixin):
def process_request(self, request):
print("这个是我们在中间件中实现的定义的第一个必要的process_request函数方法")
return request
def process_response(self, request, response):
print("这个是我们在中间件中需要自定义的第二个必要的process_response函数方法")
return response
def process_view(self, request, callback, callback_args, callback_kwargs):
print(request)
print(callback)
print(callback_args)
print(callback_kwargs)
return callback(request, callback_args, callback_kwargs)
def process_template_response(self, request, response):
print(request)
print(response)
return response
def process_exception(self, request, exception):
print(request)
print(exception)
return request
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'LoginPage.mymiddleware.mymiddlerware.MyMiddleware',
]
Django 的中间件配置项第四句话讲解
'django.middleware.csrf.CsrfViewMiddleware'
我们的这句话就是来实现的是开实现检查我们的所有的状态是否合法,来检查我们的请求和响应是否合法
针对于我们的form表单的
csrf跨站请求伪造
就是我们的钓鱼网站,就是一个和我们的原本的正规网站是分相似的网站,就是一个一比一还原的盗版网站
在这个的背景之下,我们就出现了对这个csrf的需求
我们为了解决这个问题,我们就要通过给我们的页面加上一个唯一标识来实现防止csrf伪造
只有我们的标识符匹配,才可以实现发送请求
就是直接在form表单中添加 {% csrf_token %}
Django中的auth模块的使用
首先现在开始实现我们的获取微信/qq/邮箱来实现发送消息的函数的实现
def wechat(content):
print("微信通知", content)
def Qq(content):
print("QQ通知", content)
def Email(content):
print("邮箱通知", content)
import webbrowser
from relative import *
# 开始实现我们的传输我们的信息
def send_all(content):
wechat(content)
Qq(content)
Email(content)
send_all("hello world")
上面的就是我们的基本的思路的实现,就是先实现定义,然后实现我们的在另一个模板中使用我们的定义的方法即可
class NotifyQQ:
def __init__(self):
pass
def send_msg(self, msg):
print("QQ通知", msg)
class NotifyWeChat:
def __init__(self):
pass
def send_msg(self, msg):
print("微信通知", msg)
class NotifyEmail:
def __init__(self):
pass
def send_msg(self, msg):
print("邮箱通知", msg)
NoTIFY_LIST = [
"notify.qq.NotifyQQ",
"notify.wechat.NotifyWeChat",
"notify.email.NotifyEmail",
]
from django.shortcuts import settings
import importlib
def send_all(content):
for item in settings.NOTIFY_LIST:
module_path, class_name = item.rsplit(".", maxsplit=1)
module = importlib.import_module(module_path)
cls = getattr(module, class_name)
obj = cls()
obj.send(content)
auth模块的开始使用
auth 创建超级管理员
就是我们在实现创建一个项目的时候,我们可以发现,会默认含有一个admin的视图函数,这个就是我们的超级管理员的视图函数
python manage.py createsuperuser
我们实现通过这个指令可以实现的是我们的创建我们的超级用户
然后就可以实现使用我们的admin的路由的页面了
我们的管理员默认的就是我们的管理我们的auth_users的表中的数据,admin就是实现的是我们的来管理我们的数据的
我们同时是可以来实现添加我们的管理员可以实现的操作的数据,否则默认的就只有我们的auth_users表中的数据
from django.contrib import admin
from django.contrib import auth
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
def Manager_login(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
res = auth.authenticate(request, username=username, password=password)
if res:
auth.login(request, res)
return render(request, 'admin/login.html')
@login_required(login_url='admin:login')
def home(request):
print(request.user.is_authenticated)
我们实现登录的时候,我们需要实现的是我们的对密码和用户名的校验
原本的就是在我们的数据库表中的一些具体的操作来实现的获取我们的密码和用户名来实现校验
auth.authenticate(request, username, password) 来实现将我们的信息和数据库中的用户来实现查找数据库中的详细信息
auth.login(request, 用户) 用来实现的是保存我们的用户登录的状态
request.user 实现的是查询我们的已经登录的用户有哪些
request.user.is_authenticated 来实现的是我们的判断用户是否处于登录的状态
from django.contrib.auth.decorators import login_required
@login_required(login_url=“跳转地址”) 来实现我们的最后的判断用户是否处于登录的装饰器,被装饰的部分只有用户处于登录的情况下才可以实现使用
同时这个登录的校验我们还是可以实现的是进行全局配置的: 就是在我们的setting.py中实现使用我们的: LOGIN_URL="路径"
https://blog.csdn.net/achen_m/article/details/134631126
auth 实现修改密码逻辑
from django.contrib import admin
from django.contrib import auth
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
def Manager_login(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
res = auth.authenticate(request, username=username, password=password)
if res:
url = request.GET.get('url')
if url:
return redirect(url)
auth.login(request, res)
return render(request, 'admin/login.html')
@login_required(login_url='admin:login')
def home(request):
print(request.user.is_authenticated)
@login_required(login_url='admin:login')
def set_password(request):
if request.method == 'POST':
old_password = request.POST.get('old_password')
new_password = request.POST.get('new_password')
confirm_password = request.POST.get('confirm_password')
if new_password == confirm_password:
if request.user.check_password(old_password):
request.user.set_password(new_password)
request.user.save()
return redirect("/login/")
return render(request, 'set_password.html', locals())
auth来实现登出功能
@login_required(login_url='admin:login')
def logout(request):
auth.logout(request)
return redirect("/login/")
auth 注册功能实现
from django.contrib import admin
from django.contrib import auth
from django.contrib.auth.models import User
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
def Manager_login(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
res = auth.authenticate(request, username=username, password=password)
if res:
url = request.GET.get('url')
if url:
return redirect(url)
auth.login(request, res)
return render(request, 'admin/login.html')
@login_required(login_url='admin:login')
def home(request):
print(request.user.is_authenticated)
@login_required(login_url='admin:login')
def set_password(request):
if request.method == 'POST':
old_password = request.POST.get('old_password')
new_password = request.POST.get('new_password')
confirm_password = request.POST.get('confirm_password')
if new_password == confirm_password:
if request.user.check_password(old_password):
request.user.set_password(new_password)
request.user.save()
return redirect("/login/")
return render(request, 'set_password.html', locals())
@login_required(login_url='admin:login')
def logout(request):
auth.logout(request)
return redirect("/login/")
def Manage_register(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
User.objects.create_superuser(username=username, password=password, email=request.POST.get('email'))
User.objects.create_user(username=request.POST.get('username'), password=request.POST.get('password'))
return redirect("/login/")
return render("register.html")
"""
我们实现基本的创建的时候,我们使用的常见的方法就是;
create这是我们的普通的创建的方法,密码那些是不会实现加密的
create_user 实现的就是我们的创建一个普通用户,但是最终我们的密码那些都是实现了加密的
craete_superuser 实现的就是我们的创建了一个超级用户,最终的密码这些东西都是实现了加密的
"""
项目的开发流程
1.需求分析
先实现我们的确定用户的基本的需求以及一些初步使用的方案
2.项目设计
首先先确定我们的项目完成需要的语言有哪些,然后使用的架构有哪些,使用的开发框架有哪些,需要的完成的功能有哪些等等
3.分组开发
不同的人来实现我们的功能的开发,然后实现解决明显bug
4.测试开发
就是来实现的是我们的测试是否含有问题,启动是否有问题
5.交付上线(部署上线)
交付上线后的问题就是运维的事情