Django
Django 官网: https://www.djangoproject.com/
概念: Django 是:
- Python web 框架
- 服务端框架
- MVT 设计模式
MVT 设计模式:

开始
- 安装虚拟环境, 避免第三方库的兼容性冲突
# 安装虚拟环境
pip install virtualenv- 创建虚拟环境
环境部署
# 名为 env 的虚拟环境
virtualenv env这个命令会创建一个名为 env 的文件夹
- 激活虚拟环境
到 env/Scripts/ 目录下, 运行 activate
env/Scripts/activate
# 进入虚拟环境后的结果:
(env) 当前工作目录如果要退出虚拟环境, 运行 deactivate 即可
安装
安装 Django 框架
pip install django
# 查看 Django 是否安装完成
django-admin创建与运行
startproject 创建一个 Django 项目
该命令会创建一个文件夹, 包含几个模板 .py 文件
django-admin startproject devsearch启动服务器:
cd devsearch
# 启动服务器
python manage.py runserver参考: https://docs.djangoproject.com/en/4.2/intro/tutorial01/
wsgi.pyWeb Server Gateway Interface (Web 服务器网关接口)asgi.pyAsynchronous Server Gateway Interface (异步服务器网关接口)
创建应用
Django 应用:

创建应用:
# 格式 python manage.py startapp <应用名>
python manage.py startapp projects创建完应用后, 需要在 setting.py 中注册应用
# apps 是模块名
# ProjectsConfig 是类名
INSTALLED_APPS = [
...,
'projects'
]视图 (模板) 和 路由
(Views and URL)
路由
要将创建的应用路径引入到根应用中, 需要在 项目名/urls.py 中添加子应用的路径
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls),
# 导入子应用的自定义url
path("", include("projects.urls")),
]然后在 devsearch\projects文件夹中创建 urls.py
from django.urls import path
# 导入视图模块
# 该处为自建的包核模块
from .views import projects, product
urlpatterns = [
# 此处为自定义的路径
# <str:pk> url参数
path("projects/", projects, name="projects"),
path("project/<str:pk>", product, name="product"),
]
视图 (模板)
在 setting.py 中加入视图模板的位置
# 设置模板目录
TEMPLATES = [
...,
# 模板的目录
# 该代码表示模板存放于当前脚本运行目录下的 template 目录
"DIRS": [
os.path.join(BASE_DIR, "templates"),
],
...
]views.py 是逻辑层, 一般用于存放函数
在渲染视图前, 需指定要渲染的模板
# 函数的定义
def function_name(请求对象, url参数)
return render()from django.shortcuts import render
def projects(request):
msg = "Hello, your are on meassage page"
# render 函数用于渲染页面
# 最后一个参数用于向模板传入数据
return render(request, "projects/projects.html", {"messge": msg})视图格式
{% %} 为标识符
main.html:
<!-- 引入 navbar.html 模板 -->
{% include 'navbar.html'%}
<!-- 插入模板起始位置 -->
{% block content %}
<!-- 插入模板结束位置 -->
{% endblock content %}content.html:
<!-- 插入至定义好的位置 -->
{% extends 'main.html' %}模板数据
访问数据:
{{ 变量名 }} <br />
{{对象.属性}}流程控制:
{% if a > b%}
<p>判断为真, 执行的结果</p>
{% elif %}
<p>同上</p>
{% else %}
<p>判断为假, 执行的结果</p>
{% endif %}循环:
{% for item in list %}
<p>your loop content here</p>
{% endfor %}如果我们将一个路径命了名, 我们可以引入路径名
# 路径名为 project
path("projects/", projects, name="project"),<a href="{% url '路径名'%}"></a> <br />
<a href="{% url '路径名' 路径参数 %}"></a>消息
message.success('消息...') 会将数据传入到模板的 messages 变量中, 类型为列表
message.tags消息类型message消息
from django.contrib import messages
message.success('成功的消息')
# 其它类型的消息详见代码补全
render(request, ){% for message in messages %}
<li {% if message.tags %} class="{{ message.tags }}" {% endif %}>{{ message }}</li>
{% endfor %}常用变量
<!-- 判断用户是否验证 -->
{% if request.user.is_authenticated %} {% endif %}模型 (Model) 与 管理员面板
管理员面板
在我们运行 python manage.py runserver 这个命令时, 会看到以下报错
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.首先是在 setting.py 中的数据库设置, 设置数据库并没有任何数据
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}如同报错所说, 运行 python manage.py migrate 来进行初始化操作
此时, 数据库将会完成表单的初始化, 但我们还需创建一个管理员账号
运行 python manage.py createsuperuser 来创建管理员账号
创建完成后就可以访问管理员面板了: http://127.0.0.1:8000/admin
模型 (Model)

通过创建一个类来创建对应表
具体的类型约束参考官方文档
import uuid
# 创建的表
class Project(models.Model):
title = models.CharField(max_length=200) # 设置最大直段
description = models.TextField(null=True, blank=True) # 允许字段为空
demo_link = models.CharField(max_length=2000, null=True, blank=True)
source_link = models.CharField(max_length=2000, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True)运行 python manage.py makemigrations 来创建迁移文件
Django 会在 migrations 文件夹创建 0001_initial.py 文件
然后将利用迁移文件将表创建至数据库 python manage.py migrate
python manage.py makemigrations
python manage.py migrate当表创建至数据库, 我们还不能通过管理员面板查看刚刚创建的表
还需要将创建的模型注册进管理员面板中
在 应用名/admin.py 中注册模型
from .models import 模型类名
# 注册模型
admin.site.register(模型类名)关系性数据库
一个关系可视化的网站: https://www.drawsql.app
三个基础关系:
- 一对一
- 一对多
- 多对多
查询函数

# 进入项目内的 python shell
python manage.py shell表单模型
新建一个文件 forms.py
from django.forms import ModelForm
from .models import Project
# 创建一个表单模型
class ProjectForm(ModelForm):
class Meta:
model = Project
# 这是设置要渲染的字段
# 我们还可以用一个列表指定要渲染的字段
fields = "__all__"然后在 views.py 中传入表单模型的实例
def createProject(request):
form = ProjectForm()
context = {"form": form}
return render(request, "projects/project_form.html", context)最后在模板 html 中加入
Django 会自动将表模型的对应字段添加进模板
<!-- csrf_token 要写在表单标签里面 -->
<form action="" method="POST">
{% csrf_token %} {{form}}
<input type="submit" />
</form><!-- 将 input标签按行渲染 -->
{{form.as_p}}
<!-- 渲染表单中的某个字段 -->
{{form.title}}
<!-- 渲染字段的名字-->
{{form.title.label}}
<!-- 循环渲染 -->
{% for field in form %} {{field.label}} {{field}} {%endfor%}自定义表单
用于自定义在模板中的渲染, 通常是修改样式
from django.contrib.auth.forms import UserCreationForm
from django.forms.fields import CharField, EmailField
class ExampleForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
# super(ExampleForm, self).__init__(*args, **kwargs) # python 2.x
super().__init__(*args, **kwargs) # python 3.x
# 自定义特定字段
self.fields["title"].widget.attrs.update(
{"class": "input", "placeholder": "add title"}
)
# 将所有字段的class改为 'input'
for _, field in self.fields.items():
# 指定类型
current_field: CharField | EmailField = field
print(current_field.widget.attrs.update({'class': 'input'}))self.fields 为字典, .items() 方法可将其转换为可迭代对象
field.widget为 HTML 元素 (与fileds['字段名']等价)field.widget.attrs类型为字典, 为 HTML 属性
CRUD 操作
CRUD (Create Read Update Delete)
在 views.py 中
- CREATE 操作
from django.shortcuts import render, redirect
# 接受提交过来的表单, 并将其转换为字典
request.POST
def createProject(request: HttpRequest):
form = ProjectForm()
if request.method == "POST":
form = ProjectForm(request.POST)
# 校验表单是否合法
if form.is_valid():
form.save()
return redirect('projects')
context = {"form": form}
return render(request, "projects/project_form.html", context)
- UPDATE 操作
与创建有些许不同, 主要是要指明要更新的对象
def updateProject(request: HttpRequest, pk: str):
project = Project.objects.get(id=pk)
form = ProjectForm(instance=project)
if request.method == "POST":
form = ProjectForm(request.POST, instance=project)
if form.is_valid():
form.save()
return redirect("projects")
context = {"form": form}
return render(request, "projects/project_form.html", context)静态文件
不难, 看官方文档
在 setting.py 文件下, 静态文件夹的设置可以这么写:
STATICFILES_DIRS = [BASE_DIR / "static"]用户图片
在模型层 models.py 设置 models.ImageField() 字段, 可以通过管理页面上传图片
设置这个字段需要安装 Pillow 库
# 静态文件
feature_image = models.ImageField(null=True, blank=True, default="default.jpg")如果没有在 setting.py 中设置 MEDIA_ROOT, 上传的图片都会存储在项目根目录中
在 setting.py 中设置 MEDIA_ROOT 和 MEDIA_URL
MEDIA_URL = "images/"
MEDIA_ROOT = os.path.join(BASE_DIR, "static/images")接着, 在项目的 urls.py 中, 添加相关路径
from django.conf import settings
from django.conf.urls.static import static
urlpartterns = [...]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)在模板中, 通过访问数据库来获取其图片路径, 要注意的是, 这里的 project 是从 View 层传入的对象
<img src="{{ project.feature_image.url }}" alt="head" />上传的表单
enctype 指定提交的表单类型
<form action="" method="POST" enctype="multipart/form-data">
......
<input type="submit" />
</form>要让 Django 接受表单传过来的文件, 需要在让 Model 对象接受 request.FILES
这样, 文件和数据库的信息将被一同存储下来
if request.method == "POST":
form = ProjectForm(request.POST, request.FILES)生产环境下的静态托管
到目前为止, Django 的静态文件不是为生产环境准备的
事实上, Django 官方并不推荐用这样的方式管理静态文件
官方推荐采用托管的方式管理和存储静态文件
在 setting.py 中, 将 DEBUG 设为 False, 设置的静态文件将不在生效
# 在生产环境下, 只有该静态文件设置有效
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')# 将所有 DEBUG=True 下设置的静态文件打包指 STATIC_ROOT 中
python manage.py collectstatic将 DEBUG设为 True 并打包静态文件后, 以前的设置将不在生效
需要重新设置 urls.py 的路径, 然后还需安装一个第三方库 whitenoise1
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)whitenoise 的安装, 查看 官方文档
pip install whitenoise用户
Django 自带一个名叫 User 和 Group 的数据库对象, 用于管理员面板的使用
通过继承 User 对象来实现自建的用户表, 是依赖于 Django 的用户验证系统的, 如果在使用过程中对该
用户表有不当操作, 会导致整个 Django 的验证出现问题
因此, 建议再重新创建一个名为 Profile 的数据库对象, 来与 Django 自带的用户表做以分离,实以现自建的用户表
from django.contrib.auth.models import User, Group信号 Signals
建议看看官方文档: https://docs.djangoproject.com/en/5.0/topics/signals/

Django 接受的信号:
post_savepost_delete...
在 models.py 中, 编写代码:
from django.db.models.signals import post_save, post_delete
# 定义接受器
def pfunction_name(sender, instance, created: bool, **kwargs):
# instance 发送的实例
# created 是否创建
pass
def deleteUser(sender, instance, **kwargs):
print("Deleting User...")
# 设置接受器
# 参数 (接收器, 发送者)
post_save.connect(profileUpdated, sender=Profile)
post_delete.connect(deleteUser, sender=Profile)装饰器写法:
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
# 定义接受器
@receiver(post_save, sender=Profile)
def pfunction_name(sender, instance, created: bool, **kwargs):
pass如果想将信号相关的代码从 models.py 中分离出来, 除了将上面所有的代码放入 signals.py 中
还需在 apps.py 中注册分离出来的代码文件
class UsersConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "users"
# 将 "signals.py" 注册进该应用中
def ready(self) -> None:
import users.signals用户认证 (Session)
当使用 Django 执行数据库初始迁移命令时
Django 会创建一个名叫 django_session 的表单
该表存储用户的 session(用户会话), 将用户的 session ID 存储进表
浏览器的 sessionid 值对应数据库中的 session_key
登录
在 views.py 中创建用户登录:
from django.contrib.auth import login, authenticate
from django.contrib.auth.models import User
from django.http import HttpRequest
def loginPage(request: HttpRequest):
if request.method == "POST":
print(request.POST)
username = request.POST["username"]
password = request.POST["password"]
try:
user = User.objects.get(username=username)
except:
# 这里可以改为 message.error(request, 'User not exists!')
# 官方文档: https://docs.djangoproject.com/en/4.2/ref/contrib/messages/#adding-a-message
print("User not exists!")
# 通过用户名和密码获取用户实例
user = authenticate(request, username=username, password=password)
if user is not None:
# 将 session 存储进数据库, 并让浏览器保存 session id
login(request, user)
return redirect("profiles")
else:
print("Username or password is incorrect")
return render(request, "users/login_register.html")登出
让用户登出:
from django.contrib.auth import logout
def logoutUser(request: HttpRequest):
logout(request)
return redirect("profiles")限制访问
如果是基于函数的 views.py 的代码
可以通过 login_required 修饰器来限制未授权访问
from django.contrib.auth.decorators import login_required
@login_required(login_url='login')
def createSomthing(request):
...
return render('somthing')
注册
使用内置的表单构建类
from django.contrib.auth.forms import UserCreationForm
def registerUser(request: HttpRequest):
page = "register"
form = UserCreationForm()
context = {"page": page, "form": form}
if request.method == "POST":
form = UserCreationForm(request.POST)
if form.is_valid():
# commit = False 暂时不提交
user: User = form.save(commit=False)
user.username.lower()
user.save()
messages.success(request, "User account was created!")
login(request, user)
return('profiles')
return render(request, "users/login_register.html", context)<!-- 渲染表单模板 -->
{{ form.as_p }}自定义注册表单
可以通过 {{ for field in form }} 循环 Form 对象来取消掉 UserCreationForm 上的多余消息
但在模板中无法修改 Form 的 class 类名和后缀, 需要到数据模型那去修改
{% for field in form %}
<!-- 帮助文本 -->
{{ field.help_text }}
<!-- 错误列表, 使用时需循环 -->
{% field.errors %}- whitenoise 并不管理用户上传的文件 ↩