django基础
Django
1.URL组成部分详解
URL 是Uniform Resource Locator 的简写, 统一资源定位符。
一个URL由以下几部分组成:
# scheme://host:port/path/?query-string=xxx#anchor
scheme: 代表的是访问的协议, 一般为http 或者 https 以及ftp 等
host: 主机名,域名,比如www.baidu.com
port: 端口号。 HTTP 协议是80 端口, HTTPS 协议是443端口
path: 查找路径。比如 www.123.com/threading/now , 后面的threading/now 就是path。
query-string: 查找字符串, 比如: www.baidu.com/s?wd=python, 后面的 wd=python 就是查询字符串。
anchor: 锚点, 后台一般不用管, 前端用来做页面定位的。
注意: URL中的所有字符都是 ASCII字符集, 如果出现非ASCII 字符, 比如中文, 浏览器会进行编码再进行传输。
2.第一个Django 项目
创建django 项目有两种方式
一种命令行的方式, 一种使用 pycharm 的方式
命令行的方式:
- 创建项目: 打开终端,使用命令: django-admin startproject [项目名称] 即可创建,比如 django-admin startproject first_project
- 创建应用(app) : 一个项目类似于一个架子, 但是真正起作用的还是 app。在终端进入到项目所在的路径,然后执行 python manage.py startapp [app名称] 创建一个 app。
- 运行项目的方式: 进入到 项目目录下 : 执行 python manage.py runserver
Microsoft Windows [版本 10.0.26100.4061]
(c) Microsoft Corporation。保留所有权利。
D:\python_project>django-admin startproject firstProject
D:\python_project>dir
驱动器 D 中的卷是 software
卷的序列号是 B632-C09B
D:\python_project 的目录
2025/05/24 17:05 <DIR> .
2025/05/24 17:05 <DIR> firstProject
2025/04/23 11:36 <DIR> flaskProject
2025/05/17 23:09 <DIR> flask_learning
2024/04/28 00:00 <DIR> leetcode
2025/05/23 15:59 <DIR> Q&A_platform
0 个文件 0 字节
6 个目录 595,187,142,656 可用字节
D:\python_project>cd firstProject
D:\python_project\firstProject>python manage.py startapp firstApp
D:\python_project\firstProject>dir
驱动器 D 中的卷是 software
卷的序列号是 B632-C09B
D:\python_project\firstProject 的目录
2025/05/24 17:06 <DIR> .
2025/05/24 17:05 <DIR> ..
2025/05/24 17:06 <DIR> firstApp
2025/05/24 17:06 <DIR> firstProject
2025/05/24 17:05 690 manage.py
1 个文件 690 字节
4 个目录 595,187,130,368 可用字节
D:\python_project\firstProject>tree
卷 software 的文件夹 PATH 列表
卷序列号为 B632-C09B
D:.
├─firstApp
│ └─migrations
└─firstProject
└─__pycache__
D:\python_project\firstProject>
- pycharm 方式, 选择新建项目,选择 django 类型,选择解释器环境。
命令行和 pycharm 运行 django 项目的方法
命令行:进入到 项目目录下 : 执行 python manage.py runserver
pycharm 方式
项目结构介绍
1.manage.py : 以后和项目交互基本上都是基于这个文件, 一般都是在终端输入 python manage.py [子命令]。可以输入 python manage.py help 看下能做什么事情。 除非你知道你自己在做什么, 一般情况下不应该编辑这个文件。
2.settings.py: 本项目的设置项, 以后所有和项目相关的配置都是放置这个里面。
3.urls.py: 这个文件是用来配置URL 路由的。比如访问http://127.0.0.1/new/是访问新闻列表页,这些东西就需要在这个文件中完成。
4.wsgi.py: 项目与 WSGI协议兼容的web服务器入口, 部署的时候需要用到的, 一般情况下也是不需要修改的。
project 和 app 的关系
app 是 django 项目的组成部分。一个app 代表项目中的一个模块,所有URL请求的响应都是由app 来处理。比如豆瓣,里面有图书,电影, 音乐,同城等许许多多的模块,如果站在django 的角度来看, 图书,电影这些模块就是app, 图书,电影这些app 共同组成豆瓣这个项目。因此这里要有一个概念,django 项目由许多app 组成, 一个app 可以被用到其他项目, django 也能拥有不同的app。
# 可以通过如下命令在终端来创建 app
# python manage.py startapp app名称
# 例如 python manage.py startapp app01
3.URL 和视图的映射
# urls.py
"""
URL configuration for djangoProject project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.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
from django.shortcuts import HttpResponse
# https://www.baidu.com/s?wd=python
# URL 与视图的映射
# /s(URL) 和视图函数的映射
# 通过 浏览器访问相关的url 来 调用相关的视图函数
def index(request):
return HttpResponse("hello")
urlpatterns = [
path('admin/', admin.site.urls),
# 前面不需要加 /, django 框架自动给添加了
path('', index),
]
# 访问 http://localhost:8000/ 可以看到 hello 字符串
4.URL的两种传参方式
# app 下的 view.py 中书写视图函数
# 在URL中携带参数
# 1.通过查询字符串(query string): https://www.baidu.com/s?wd=python&a=1&b=2
# 2.在path中携带:http://127.0.0.1:8000/book/2
# 1. 查询字符串: http://127.0.0.1:8000/book/?id=3&name="心经“
def book_detail_query_string(request):
# request.GET = {"id":3}
book_id = request.GET.get('id')
book_name = request.GET.get('name')
return HttpResponse(f"您查找的图书id是:{book_id}, 图书名称是:{book_name}")
# http://127.0.01:8000/book/1
def book_detail_path(request, book_id):
return HttpResponse(f"您查找的图书id是:{book_id}")
# 项目目录下同项目名的文件夹下的url.py 中写 url 和视图函数的映射关系
urlpatterns = [
path('admin/', admin.site.urls),
# 前面不需要加 /, django 框架自动给添加了
path('', index),
# http://127.0.0.1:8000/book?id=1
path("book", views.book_detail_query_string),
# http://127.0.0.1:8000:/book/1
# 在 path 中指定类型有什么好处?
# 1.以后在浏览器中,如果book_id 输入的是一个非整型, 那么会出现404错误: /book/abc
# 2. 在视图函数中, 得到的book_id 就是一个整型,否则,默认是str类型
path('book/<int:book_id>', views.book_detail_path)
]
5.path函数详解
项目目录下同项目名称的文件夹下有一个urls.py ,可以在 urlpatterns 列表中定义 url 和视图的映射关系,关于其中的path函数
path 函数的定义为: path(route, view, name=None, kwargs=None)。以下对这几个参数进行讲解。
- route 参数: url 的匹配规则, 这个参数中可以指定url 中需要传递的参数, 比如在访问文章详情页的时候,可以传递一个id,传递参数的时候,可以指定这个参数的类型,比如文章的id 都是int类型,那么可以写成 '<int: id>', 以后匹配的时候,就只会匹配到id 为int 类的url,而不会匹配其他的url, 并且在视图函数中获取这个参数的时候,就已经被转化成一个int 类型了。其中还有几种常见的类型。
- str: 非空的字符串类型, 默认的转换器。但是不能包含斜杆
- int: 匹配任意的零或者正数的整型。 到视图函数中就是一个int类型。
- slug: 由英文的横杆-, 或者下划线连接英文字符或者数组而成的字符串。
- uuid: 匹配uuid 字符串
- path: 匹配非空的英文字符串, 可以包含/
# app 下的 view.py 中书写视图函数
def book_str(request, book_id):
return HttpResponse(f"您查找的图书id是:{book_id}")
def book_slug(request, book_id):
return HttpResponse(f"您查找的图书id是:{book_id}")
def book_path(request, path1):
return HttpResponse(f"图书路径为:{path1}")
# # 项目目录下同项目名的文件夹下的url.py 中写 url 和视图函数的映射关系
urlpatterns = [
path('admin/', admin.site.urls),
path('book/str/<str:book_id>', views.book_str),
path('book/slug/<slug:book_id>', views.book_slug),
path('book/path/<path:path1>', views.book_path)
]
2.views 参数: 可以为一个视图函数或者l类视图.as_view() 或者django.urls.include() 函数的返回值.
3. name: 这个参数是给这个url 取个名字,
# 项目目录下同项目名的文件夹下的url.py 中写 url 和视图函数的映射关系
urlpatterns = [
path('admin/', admin.site.urls),
path('book/str/<str:book_id>', views.book_str),
path('book/slug/<slug:book_id>', views.book_slug,name="url_slug"),
path('book/path/<path:path1>', views.book_path, name="url_path")
]
6.路由模块化
URL 中包含另外一个urls模块。
在我们的项目中, 有可能不只有一个app, 如果把所有的app的views中的视图函数都放在urls.py中进行映射,肯定会让代码显得非常乱,
因此, django 给我们提供了一个方法, 可以在app 内部包含自己的url匹配规则,而在项目的url.py 中再统一包含这个app 的urls,使用这个技术需要借助include函数。
在 app 中创建一个新的urls.py, 将这个 app 的 url 和视图函数的映射关系,写到 自己app 下的urls.py 中, 然后在 项目名文件夹下的urls.py 中 指定相关的 path
# app02/urls.py
from django.urls import path
from . import views
# 指定应用名称:(应用命名空间)
# 防止不同 app 中 视图函数的name 重复
app_name = "app02"
urlpatterns = [
path("movie_list", views.movie_list, name='movie_list'),
path("movie_detail/<int:movie_id>", views.movie_detail, name="movie_detail")
]
# 项目名文件夹/urls.py
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('movie/', include("app02.urls"))
]
7.路由反转
通过django.urls中的 reverese 函数 传递 视图函数的 name 属性, 可以获得视图函数的路径, 带命名空间的视图函数,反转的时候, 需要加上 命名空间
from django.contrib import admin
from django.urls import path, include
from django.shortcuts import HttpResponse
from app01 import views
from django.urls import reverse
def index(request):
print(reverse("book_detail_query_string"))
# 通过 视图函数 name 反转的到URL 拼接参数
print(reverse('book_str', kwargs={"book_id": 1}))
# book?id=1: 如果是查询字符串的方式传参, 那么就只能通过字符串拼接的方式实现
print(reverse("book_detail_query_string") + "?id=1")
# 带命令空间的 路由,反转时需要加上命名空间
print(reverse("app02:movie_list"))
return HttpResponse("hello")
urlpatterns = [
path('admin/', admin.site.urls),
# 前面不需要加 /, django 框架自动给添加了
path('', index, name='index'),
# http://127.0.0.1:8000/book?id=1
path("book", views.book_detail_query_string, name="book_detail_query_string"),
path('book/str/<str:book_id>', views.book_str, name="book_str"),
]
# 访问 根路径,终端打印
/book
/book/str/1
/book?id=1
# 带命令空间的 路由,反转时需要加上命名空间
/movie/movie_list
8.模版渲染初步
在之前的章节中,视图函数只是直接返回文本,而在实际生产环境中其实很少这样用, 因为实际的页面大多是带有样式的HTML 代码, 这可以让浏览器渲染出非常漂亮的页面。目前市面上有非常多的模版系统,其中知名最好用的就是DTL 和jinja2, DTL 是Django Template Language 三个单词的缩写, 也就是Django 自带的模版语言。当然也可以配置Django 支持jinja2等其他模版引擎,但是作为Django 内置的模版语言, 和Django可以达到无缝衔接而不会产生一些不兼容的情况。
DTL模版和普通的HTML文件的区别
- DTL模版是一种带有特殊语法的HTML文件, 这个HTML文件可以被Django 编译, 可以传递参数进去, 实现数据动态化。在编译完成后, 生成一个普通的HTML 文件,然后发送给客户端
# 在app 下的 views.py 中写一个视图函数,在项目目录下的templates文件夹下写一个html 文件 index.html
from django.shortcuts import render, HttpResponse
def try_template(request):
return render(request, "index.html")
# 在项目下,同项目名文件夹下的 urls.py 中定义视图函数 和 url 的映射关系, 或者在 app 下的urls.py 中定义关系映射,然后, 将app 中的 urls include 到 项目/项目名文件夹/urls.py中, 路由模块化的知识。
# 项目/项目名文件夹/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path("try_template", views.try_template)
]
9.模版查找路径配置
10.模版变量渲染
# app 下的 views.py 定义视图函数, 将 各种变量传递到 html 模版中使用 context参数
def info(request):
username = "pox"
book = {"name": "水浒传", "author": "施耐庵"}
books = [
{"name": "水浒传", "author": "施耐庵"},
{"name": "三国演义", "author": "罗贯中"}
]
class Person:
def __init__(self, realname):
self.realname = realname
person = Person(realname="ooo")
context = {
"name": "mpx",
"book": book,
"username": username,
"books": books,
"person": person
}
return render(request, "info.html", context=context)
# 项目/项目名文件夹/urls.py 定义视图映射
urlpatterns = [
path('admin/', admin.site.urls),
path("info", views.info, name="info")
]
<!--info.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ name }}
{{ username }}
{{ book.name }} {{ book.author }}
<p>列表中下标为0的图书的名称:{{ books.0.name }}</p>
<p>姓名为:{{ person.realname }}</p>
</body>
</html>
11.模版常用标签
12.模版常用过滤器
13.模版结构(include 和extend)
-
include 模版
有时候一些代码是在许多模版中都用到的。如果我们每次都重复去拷贝代码那肯定不符合项目的规范,一般我们可以把这些重复性的代码抽取处出来,就类似于python 中的函数一样,以后想要使用这些代码的时候, 就通过include 包含进来。这个标签就是include。
模版继承
14.静态文件加载配置
15.Django连接数据库配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_1',
# 连接mysql数据库的用户名
'USER': 'root',
# 连接mysql 数据库的密码
'PASSWORD': 'root',
# mysql 数据库的主机地址
'HOST': '127.0.0.1',
# mysql 数据库的端口号
'PORT': '3306',
}
}
# 使用django 封装好的connection对象, 会自动读取settings.py 中数据库的配置信息
from django.db import connection
def get_message(request):
# 获取游标对象
cursor = connection.cursor()
# 拿到游标对象后执行sql 语句
cursor.execute("select * from book")
# 获取所有的数据
rows = cursor.fetchall()
# 遍历查询到的数据
for row in rows:
print(row)
return HttpResponse("查找成功")
16.ORM 模型创建与映射
# 在 app下的 models.py 中定义模型类
from django.db import models
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=100)
author = models.CharField(max_length=20)
pub_time = models.DateTimeField(auto_add_now=True)
price = models.FloatField(default=0)
# 首先做好如上图的一些配置, 然后在终端执行下面两天命令
# python manage.py makemigrations
# python manage.py migrate
17.ORM 实现基本CURD操作
# app01\views.py
from app01.models import Book
def add_book(request):
book = Book(name="三国演义", author="罗贯中", price=100)
book.save()
return HttpResponse("图书插入成功!")
#app01\models.py
from django.db import models
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=100)
author = models.CharField(max_length=20)
pub_time = models.DateTimeField(auto_now_add=True)
price = models.FloatField(default=0)
# 视图函数映射关系写在 项目目录下/项目名文件夹下的urls.py 中了(没有写在自己 app下的url.py)
# orm 数据添加
path("orm_add_book", views.add_book, name="add_book")
# 访问 http://localhost:8000/orm_add_book
#app01/views.py
from app01.models import Book
def query_book(request):
books = Book.objects.all()
for book in books:
print(book.id, book.name, book.pub_time, book.price)
return HttpResponse("查找成功")
# urls.py
# orm数据查找
path("book/query", views.query_book, name="book_query")
# 访问 http://localhost:8000/book/query
18.模型常见的Field
# app/models.py
class Author(models.Model):
is_active = models.BooleanField()
username = models.CharField(max_length=200)
date_joined = models.DateTimeField(auto_now_add=True)
email = models.EmailField()
visit_count = models.IntegerField()
profile = models.TextField()
website = models.URLField()
# 将 数据表映射到 数据库中(配置项之前配置好)
python manage.py makemigrations
python manage.py migrate
19.Field的常用参数
20.模型中Meta的配置
21.外键和表的关系
# article(app)/urls.py
from django.urls import path
from . import views
# 应用命名空间
app_name = 'article'
urlpatterns = [
path('test', views.article_test, name='article_test')
]
# article(app)/models.py
from django.db import models
# Create your models here.
class User(models.Model):
username = models.CharField(max_length=20)
password = models.CharField(max_length=100)
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
# author, 外键
author = models.ForeignKey('User', on_delete=models.CASCADE)
# article(app)/views.py
from django.shortcuts import HttpResponse
from .models import User, Article
# Create your views here.
def article_test(request):
# user = User(username="知了", password="1111")
# user.save()
# user = User.objects.first()
# article = Article(title="如何观测自己内心的变化", content="静下心来好好看下", author=user)
# article.save()
article = Article.objects.first()
return HttpResponse(article.title)
class Comment(models.Model):
content = models.TextField()
# 二级评论, 引用自身数据表做外键
origin_comment = models.ForeignKey("self", on_delete=models.CASCADE, null=True)
22.表之间的三种关系
# article(app)/views.py
def one_to_many(request):
user = User.objects.first()
articles = user.article_set.all()
for article in articles:
print(article.title)
return HttpResponse("查找数据成功!")
# 如果不想使用 user.article_set.all() 可以在外键字段中加一个 related_name 参数, 可以使用 related_name 键对应的值来获取
# article(app)/models.py
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
# author, 外键
author = models.ForeignKey('User', on_delete=models.CASCADE, related_name="articles")
# article(app)/ view.py
def one_to_many(request):
user = User.objects.first()
articles = user.articles.all()
for article in articles:
print(article.title)
return HttpResponse("查找数据成功!")
一对一,提供了一个OneToOneField 来进行一对一的限制
class User(models.Model):
username = models.CharField(max_length=20)
password = models.CharField(max_length=100)
class UserExtension(models.Model):
birthday = models.DateTimeField()
university = models.CharField(max_length=200)
user = models.OneToOneField('User', on_delete=models.CASCADE)
表的多对多的场景,django 提供了一个专门的Field ,叫做 ManyToManyField
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
# author, 外键
author = models.ForeignKey('User', on_delete=models.CASCADE, related_name="articles")
tags = models.ManyToManyField('Tag', related_name="articles")
class Tag(models.Model):
name = models.CharField(max_length=100)
执行上面的多对多的模型映射到数据库, 会多一个中间表 article_article_tags
23.查询操作
# article(app)/view.py
def query1(request):
article = Article.objects.filter(id__exact=1)
# 查询结果.query 可以看到底层查询的 sql 语句
print(article.query)
print(article)
return HttpResponse("查询成功")
def query1(request):
article = Article.objects.filter(title__iexact="如何观测自己内心的变化")
# 查询结果.query 可以看到底层查询的 sql 语句
print(article.query)
print(article)
return HttpResponse("查询成功")
def query2(request):
article = Article.objects.filter(title__contains="观测")
print(article.query)
print(article)
return HttpResponse("查询成功2")
24.聚合函数
# 创建一个新的 APP ,用来测试聚合函数
from django.db import models
# Create your models here.
class Author(models.Model):
""" 作者模型"""
name = models.CharField(max_length=100)
age = models.IntegerField()
email = models.EmailField()
class Meta:
db_table = "app03_author"
class Publisher(models.Model):
# 出版社模型
name = models.CharField(max_length=300)
class Meta:
db_table = "app03_publisher"
class Book(models.Model):
# 图书模型
name = models.CharField(max_length=300)
pages = models.IntegerField()
price = models.FloatField()
rating = models.FloatField()
author = models.ForeignKey(Author, on_delete=models.CASCADE)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
class Meta:
db_table = "app03_book"
class BookOrder(models.Model):
# 图书订单模型
book = models.ForeignKey("Book", on_delete=models.CASCADE)
price = models.FloatField()
class Meta:
db_table = "app03_book_order"
# app03(app)/views.py
from django.shortcuts import HttpResponse
from django.db.models import Avg
from .models import Book
# Create your views here.
def test(request):
# result = Book.objects.aggregate(Avg('price'))
result = Book.objects.aggregate(my_avg=Avg('price'))
print(result)
return HttpResponse("查询成功")
def test2(request):
result = Book.objects.aggregate(book_num=Count('id'))
return HttpResponse(f"一共有{result['book_num']}本书")
def test3(request):
result = Author.objects.aggregate(Max('age'), Min('age'))
print(result)
return HttpResponse(f"作者的年龄的最大值是{result['age__max']}, 作者的年龄最小值是{result["age__min"]}")
from django.shortcuts import HttpResponse
from django.db.models import Avg, Count, Max, Min, Sum
from .models import Book, Author, BookOrder
# Create your views here.
def test4(request):
result = Book.objects.annotate(total=Sum("bookorder__price")).values("name", "total")
print(result)
return HttpResponse("查询数据完成")
25.F表达式和 Q表达式
from django.db.models import Avg, Count, Max, Min, Sum, F
def test5(request):
Book.objects.update(price=F('price') - 10)
return HttpResponse("f_view")
def test6(request):
# 查询图书表中价格大于 90 的 或者 排名小于2 的, 使用 Q 表达式实现 或 操作, 二者满足其一
books = Book.objects.filter(Q(price__gte=90) | Q(rating__lt=2)).all()
for book in books:
print(book.name)
return HttpResponse("查询成功!")
26.表单概述
# app 下的 form.py 中定义 form 表单类
from django import forms
# 留言板的表单
class MessageBoardForm(forms.Form):
title = forms.CharField(min_length=2, max_length=20, label="标题",
error_messages={
"min_length": "标题最小长度不能少于2!",
"max_length": "标题最大不能超过20"
})
content = forms.CharField(widget=forms.Textarea, lable="内容")
email = forms.EmailField(lable="邮箱")
# app 下的views.py 中定义相关的视图函数
from .forms import MessageBoardForm
# 对视图函数的请求方法进行限制
from django.views.decorators.http import require_http_methods
# 请求的method
# 1. GET: 用来从服务器上获取数据的
# 2. POST: 用来向服务器提交数据
# 3. 有 PUT/DELETE/HEAD 等等各种各样的请求
@require_http_methods(['GET', "POST"])
def test_form(request):
# 如何用 GET请求, 那么就直接返回一个页面
if request.method == 'GET':
form = MessageBoardForm()
return render(request, "test_form.html", context={"form":form})
# 对用POST请求提交上来的数据,用表单验证是否满足要求
else:
form = MessageBoardForm(request.POST)
if form.is_valid():
title = form.cleaned_data.get("title")
content = form.cleaned_data.get("content")
email = form.cleaned_data.get('email')
return HttpResponse(f"{title}, {content}, {email}")
else:
print(form.errors)
return HttpResponse("表单验证失败!")
<!-- test_form.html 模版文件-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello</title>
</head>
<body>
<p>这是一个新的页面</p>
<form action="" method="POST">
{{ form }}
<input type="submit", value="提交">
</form>
</body>
</html>
27.表单验证
# app03(app)/forms.py 定义验证表单类
from django.core import validators
class RegisterForm(forms.Form):
telephone = forms.CharField(validators=[validators.RegexValidator(r'1[345678]\d{9}', message="手机号码格式不符合条件")])
# app03(app)/views.py 定义相关的视图函数
from .forms import RegisterForm
from django.views.decorators.http import require_http_methods
@require_http_methods(["GET", 'POST'])
def test_valid(request):
if request.method == "GET":
return render(request, "test_valid.html")
else:
form = RegisterForm(request.POST)
if form.is_valid():
telephone = form.cleaned_data.get("telephone")
return HttpResponse(telephone)
else:
print(form.errors)
return HttpResponse("表单验证失败!")
<!--test_valid.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="POST">
<input type="text" name="telephone">
<input type="submit" value="提交">
</form>
</body>
</html>
# app03(app)/ forms.py
class RegisterForm(forms.Form):
telephone = forms.CharField(validators=[validators.RegexValidator(r'1[345678]\d{9}', message="手机号码格式不符合条件")])
pwd1 = forms.CharField(min_length=8, max_length=100)
pwd2 = forms.CharField(min_length=8, max_length=100)
def clean_telephone(self):
telephone = self.cleaned_data.get('telephone')
# 从数据库中查找telephone 是否存在, 如果存在,那么抛出错误。
if telephone == "18888888888":
raise forms.ValidationError("手机号码已经存在!")
else:
return telephone
def clean(self):
cleaned_data = super().clean()
pwd1 = cleaned_data.get("pwd1")
pwd2 = cleaned_data.get("pwd2")
if pwd1 != pwd2:
raise forms.ValidationError("两次密码不一致!")
else:
return cleaned_data
<!--test_valid.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="POST">
<div>
<input type="text" name="telephone" placeholder="请输入手机号码">
</div>
<div>
<input type="password" name="pwd1" placeholder="请输入密码">
</div>
<div>
<input type="password" name="pwd2" placeholder="请重复输入密码">
</div>
<input type="submit" value="提交">
</form>
</body>
</html>
28.ModelForm
# app03(app)/ models.py
from django.db import models
from django.core import validators
class Article1(models.Model):
title = models.CharField(max_length=200, validators=[validators.MinLengthValidator(limit_value=2)])
content = models.TextField(validators=[validators.MinLengthValidator(limit_value=3)])
create_time = models.DateTimeField(auto_now_add=True)
# app03(app)/ forms.py
# form 验证继承所有的 models 类中的字段
from .models import Article1
class Article1Form(forms.ModelForm):
class Meta:
model = Article1
fields = "__all__"
# app03(app)/views.py
@require_http_methods(['GET', 'POST'])
def article1_view(request):
if request.method == 'GET':
return render(request, "article1_view.html")
else:
form = Article1Form(request.POST)
if form.is_valid():
# 获取 title 和 conten 以及create_time, 然后创建article 模型对象,再存储到数据中
title = form.cleaned_data.get("title")
content = form.cleaned_data.get("content")
return HttpResponse(f"{title}, {content}")
else:
print(form.errors)
return HttpResponse("表单验证失败!")
<!-- article1_view.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="POST">
<div>
<input type="text" name="title" placeholder="请输入标题">
</div>
<div>
<textarea name="content" placeholder="请输入内容" id="" cols="30" rows="10"></textarea>
</div>
<div>
<input type="submit" value="提交">
</div>
</form>
</body>
</html>
29.cookie和session 原理
30.在Django 中操作cookie 和session
# app03(app)/ views.py
from django.shortcuts import HttpResponse
def add_cookie(request):
response = HttpResponse("设置cookie")
# 7 天以后过期
max_age = 60 * 60 * 24 * 7
response.set_cookie("username", "mpx", max_age=max_age)
return response
设置时区, 这个东西和 cookie 的过期时间有关
# 删除 cookie
def delete_cookie(request):
response = HttpResponse("删除cookie")
response.delete_cookie("username")
return response
# 获取 cookie
def get_cookie(request):
username = request.COOKIES.get("username")
return HttpResponse(username)
def add_session(request):
# 如果没有设置 session 的过期时间, 默认是两周的时间
request.session['user_id'] = "mpx"
# 如果 session 设置成0 的话, 那么浏览器关闭后,session 就会过期
request.session.set_expiry(0)
return HttpResponse("session add")
def get_session(request):
username = request.session.get("user_id")
print(username)
return HttpResponse(username)
31.CSRF攻击原理和防御
# app03(app)/views.py
from django.shortcuts import render, HttpResponse
from django.views.decorators.http import require_http_methods
@require_http_methods(["GET", "POST"])
def login(request):
if request.method == "GET":
return render(request, "login.html")
else:
print(request.POST)
print(request.COOKIES)
return HttpResponse("登录")
<!--login.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="POST">
<table>
<tbody>
<tr>
<td>邮箱:</td>
<td><input type="email" name="email"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="登录"></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
在上面的 login.html 中的form 标签中没有加csrf token, csrf 验证失败, 访问url 报403 错误。
加入 csrf token 的 form 表单如下, 两种添加csrf 的方式
<!-- 第一种方式-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="POST">
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
<table>
<tbody>
<tr>
<td>邮箱:</td>
<td><input type="email" name="email"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="登录"></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
<!-- 第二种方式-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="POST">
{% csrf_token %}
<table>
<tbody>
<tr>
<td>邮箱:</td>
<td><input type="email" name="email"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="登录"></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>