文章目录
- 路由系统 - urls.py
- 基本用法(完全匹配, 正则匹配, 别名, 子路由)
- 传参用法(位置参数, 关键字参数)
- 视图系统 - views.py
- FBV 和 CBV
- 给 CBV 加装饰器
- 直接返回 json 格式 - JsonResponse 模块
- template -- 模板系统
- 变量语法示例 - {{ }}
- 循环语法示例 - {% %}
- 配合路由别名使用 - {% url %}
- 母版和组件
- 使用实例
- 上传文件
- 多选示例
路由系统 - urls.py
基本用法(完全匹配, 正则匹配, 别名, 子路由)
- 总 urls.py
from django.urls import path, re_path, include
from main_page import views as main_page_views
from host import urls as host_urls
urlpatterns = [
# path 模块: 完全匹配, 包括最后的斜线
# name 参数: 为路由设置别名, 供 view 视图中 redirect(reverse()) 使用
# 路由结尾的斜线强烈建议写上, 否则可能会因为这个报错
path("index/", main_page_views.index, name="index"),
# re_path 模块: 根据正则规则匹配, 以 r 开头
re_path(r"^main_page/", main_page_views.main_page),
# include 方法: 引出子路由
re_path(r"^host/", include(host_urls)),
]
- 子 urls.py
from django.urls import path
from host import views
urlpatterns = [
# 匹配条目: host/add
path("add/", views.add),
]
- views.py
from django.shortcuts import render, redirect, HttpResponse
from django.urls import reverse
# Create your views here.
def index(request):
return HttpResponse("index")
def main_page(request):
# 此处对应路由系统中别名的使用
return redirect(reverse("index"))
传参用法(位置参数, 关键字参数)
- urls.py
# 必须使用 re_path 模块
from django.urls import re_path
urlpatterns = [
# 位置参数
re_path(r"re1/(\d+)/(\d+)/$", views.re_1),
# 关键字参数, 按变量名传参
# 第一个位置的变量名是 num2, 第二个位置的变量名是 num1
re_path(r"^re2/(?P<num2>\d+)/(?P<num1>\d+)", main_page_views.re_2),
]
- views.py
# 接收位置参数
def re_1(request, x, y):
# 参数拿过来的时候, 类型都是 string
r = int(x) + int(y)
return HttpResponse(r)
# 接收关键字参数
def re_2(request, num1, num2):
# 是根据传过来的参数的变量名
return HttpResponse(num1+num2)
视图系统 - views.py
FBV 和 CBV
- urls.py
urlpatterns = [
# FBV 和 CBV 的示例
re_path("^FBV$", main_page_views.fbv),
re_path("^CBV$", main_page_views.CBV.as_view()),
]
- views.py
# 需要导入 views 模块
from django import views
# FBV, Function
def fbv(request):
return HttpResponse("FBV")
# CBV, Class, 继承 views.View
class CBV(views.View):
# 常用的 4 种请求方式
def get(self, request):
return HttpResponse("CBV - get")
def post(self, request):
return HttpResponse("CBV - post")
def put(self, request):
return HttpResponse("CBV - put")
def delete(self, request):
return HttpResponse("CBV - del")
给 CBV 加装饰器
from django.utils.decorators import method_decorator
# 这是个装饰器
def wrapper(func):
def inner(*args, **kwargs):
ret = func(*args, **kwargs)
return ret
return inner
class Asset(views.View):
def get(self, request):
pass
# 使用 method_decorator装饰器, 并且将需要使用的装饰器作为参数传给它
@method_decorator(wrapper)
def post(self, request):
pass
直接返回 json 格式 - JsonResponse 模块
- views.py
# 需要导入 JsonResponse 模块
# django 实现序列化, 默认只支持字典
# safe = False 时可以返回其他类型
from django.http import JsonResponse
# 第一种, 默认情况下, 只有是 dict 类型才能使用 JsonResponse 返回, 返回其他类型会报错
def json1(request):
r = {"a": 1, "b": 2}
return JsonResponse(r)
# 如果想返回其他类型, 需要加 safe=False 的参数
def json2(request):
r = [1, 2, 3, 4]
return JsonResponse(r, safe=False)
template – 模板系统
- 在 templates 目录下寻找 html 文件
- 查找顺序: 项目 templates 目录 --> app 内 templates 目录
变量语法示例 - {{ }}
- views.py
# 为了配合演示, 将视图系统中的数据做展示
def index(request):
# 做假数据
name = "Tim" # 单纯的变量
score1 = {"math": 99, "chinese": 98} # dict
score2 = ["math", "chinese"] # list
english_score1 = "" # 空值
english_score2 = "默认值 - 不是空值" # 空值
filesize = 10240000 # 文件大小
link = "<a href=http://www.baidu.com>baidu</a>" # 超链接
return render(request, "test.html", {
"name": name,
"score1": score1,
"score2": score2,
"english_score1": english_score1,
"english_score2": english_score2,
"today": today,
"filesize": filesize,
"link": link,
{{ today|date:"Y-m-d H:m:s" }}
# 也可以用这个方式将内部所有变量进行返回
"data": locals()}
)
- test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ name }}<br>
{{ score1.math }}<br>
{{ score2.0 }}<br>
{{ english_score1|default:"数据暂时为空" }}<br>
{{ english_score2|default:"数据暂时为空" }}<br>
{{ filesize|filesizeformat }}<br>
{{ today|date:"Y-m-d H:m:s" }}<br>
{{ link }}<br>
{{ link|safe }}<br>
</body>
</html>
- 结果
循环语法示例 - {% %}
- views.py
def index(request):
l1 = [100, 200, 300, "", 500]
l2 = []
return render(request, "test.html", {"data": locals()})
- test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
l1 结果:<br>
{% for i in data.l1 %}
<!-- 循环的序号 -->
序号:
{{ forloop.counter }}
<!-- 判断, 如果不是最后一个, 需要换行 -->
值:
{% if forloop.last %}
{{ i|default:"空值" }}
{% else %}
{{ i|default:"空值" }}<br>
{% endif %}
{% empty %}
"数据整个为空"
{% endfor %}
<br>==========<br>
l2 结果:<br>
{% for i in data.l2 %}
<!-- 循环的序号 -->
序号:
{{ forloop.counter }}
<!-- 判断, 如果不是最后一个, 需要换行 -->
值:
{% if forloop.last %}
{{ i|default:"空值" }}
{% else %}
{{ i|default:"空值" }}<br>
{% endif %}
{% empty %}
"数据整个为空"
{% endfor %}
</body>
</html>
- 图示
配合路由别名使用 - {% url %}
- urls.py
from django.contrib import admin
from django.urls import path, re_path, include
from index import views as index_views
from host import urls as host_urls
urlpatterns = [
path('admin/', admin.site.urls),
path("login", index_views.login, name="denglu"),
re_path(r"^login1/(\d+)/", index_views.login1, name='denglu1'),
re_path(r"^login2/(?P<pk>\d+)/", index_views.login2, name='denglu2'),
]
- view.spy
def login(request):
return render(request, "login.html")
def login1(request, arg1):
return render(request, "login1.html")
def login2(request, pk):
return render(request, "login2.html")
- html
<!-- login.html, 不带参数-->
{% url "denglu" data %}
<!-- login1.html, 带位置参数 -->
{% url "denglu1" data %}
<!-- login2.html, 带关键字参数 -->
{% url "denglu2" data %}
母版和组件
- 母版文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>
{% block page_title %}
标题的位置
{% endblock %}
</title>
<link href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
{% block page_css %}
单页面引入 css 文件位置
{% endblock %}
</head>
<body>
<div class="row">
<div>
</div>
</div>
<div class="container">
<div class="row" style="margin-top: 70px">
{% block page_main %}
页面代码位置
{% endblock %}
</div>
</div>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="/static/jQuery/jQuery3.4.1.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
{% block page_js %}
单页面引入 js 文件位置
{% endblock %}
</body>
</html>
- 组件, 文件名为 zujian.html
<p> 这是一个组件文件 </p>
- 引入母版和组件
# 引入母版文件
{% extends "base.html" %}
# 填充非公用代码
{% block page_title %}
主页
{% endblock %}
{% block page_main %}
<p><a href="/index/">主页</a></p>
# include 引入组件, 导入文件名即可
{% include "zujian.html" %}
{% endblock %}
使用实例
上传文件
- views.py
class Upload(views.View):
def get(self, request):
return render(request, "test.html")
def post(self, request):
# 保存文件
file_obj = request.FILES.get("code")
# 拿到文件名
filename = file_obj.name
with open(filename, "wb") as f:
# 往文件句柄中写入
# chunk()是 django 自带的方法, 更加标准
for i in file_obj.chunks():
f.write(i)
return HttpResponse("上传成功")
- test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 上传文件的时候一定要写明 enctype -->
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="code">
<input type="submit" value="提交">
</form>
</body>
</html>
多选示例
- views.py
class AuthorEdit(views.View):
def get(self, request, id):
author = models.Author.objects.filter(id=id).first()
books = models.Book.objects.all()
return render(request, "author_edit.html", {"author": author, "books": books})
def post(self, request, id):
name = request.POST.get("author")
# getlist 表示取多选数据
books = request.POST.getlist("books")
author_obj = models.Author.objects.filter(id=id).first()
author_obj.name = name
author_obj.books.set(books)
author_obj.save()
return redirect("/author_list/")
- author_edit.html
{% extends "mom.html" %}
{% block html_title %}
编辑作者
{% endblock %}
{% block html_main %}
<form action="" method="post">
{% csrf_token %}
<p>
作者:
<input type="text" name="author" value="{{ author.name }}">
</p>
<p>
书名:
<select name="books" multiple>
{% for foo in books %}
{% if foo in author.books.all %}
# selected 表示选中
<option selected value="{{ foo.id }}">{{ foo.title }}</option>
{% else %}
<option value="{{ foo.id }}">{{ foo.title }}</option>
{% endif %}
{% endfor %}
</select>
{% for i in books %}
{% if i in author.books.all %}
# checked 表示选中
<p><input checked type="checkbox" name="books" value="{{ i.id }}">{{ i.title }}</p>
{% else %}
<p><input type="checkbox" name="books" value="{{ i.id }}">{{ i.title }}</p>
{% endif %}
{% endfor %}
</p>
<p><input type="submit" value="修改"></p>
</form>
{% endblock %}