写在前面
Django是一个开放源代码Web应用程序框架,由Python编写。Django采用了Model-View-Controller(MVC)的软件设计模式,但最早实现并推广的是Django中的Model-View-Template(MVT)模式。
Django的主要目标是简化Web应用程序的开发,并降低与数据库、模板等方面相关的困难。它强调了松耦合,可重用组件的设计模式。Django还提供了一套框架API,用于管理HTTP请求和响应,表单验证、安全性、会话管理和用户管理等方面。因此,Django广泛用于Web开发领域中的许多方面,包括内容管理系统、新闻门户、社交网络和科学等领域。
Django的核心特性包括:
- Django 是一个全栈web框架
- 功能完善,要素齐全
- 完善的文档
- 强大的数据库访问API
- 灵活的路由系统
- 丰富的Template模板功能
- 自带后台管理应用admin
本文主要从实操的角度,简要介绍DJango路由,视图函数,模板,身份认证,后台系统,接入Bootstrap和Django的部署等,可以让刚刚接触DJango的同学有一个大体框架。
设计模型
MVC设计模型
MVC是一种常用的软件架构模式,它将应用程序分为三个相互独立的部分:模型(Model)、视图(View)和控制器(Controller),每个部分有不同的责任和职责。
- 模型(Model)
模型是应用程序中的数据和业务逻辑部分,它通常表示应用程序中的核心功能和数据。模型负责处理应用程序的数据,并对其进行逻辑操作。模型与具体的数据存储方式无关,可以使用各种不同的数据存储方式,如关系型数据库、非关系型数据库、文件系统等。 - 视图(View)
视图是应用程序中的用户界面部分,它负责呈现模型数据给用户,并处理用户输入。视图通常由HTML、CSS、JavaScript等技术实现,并将模型的数据呈现给用户。视图可以根据用户的不同需求和设备类型,以不同的方式呈现模型数据。 - 控制器(Controller)
控制器是应用程序中的业务逻辑部分,它负责接收和处理用户的输入,并更新模型和视图。控制器负责将视图和模型连接起来,并协调它们的工作。控制器通常由代码实现,可以响应用户的请求,并将结果返回给视图。
MTV设计模型
MTV是Model-Template-View的简称,是一种Web应用程序设计模型,类似于MVC(Model-View-Controller)模型。它是Django框架的核心设计思想之一,用于组织和管理Web应用程序的不同部分。
MTV模型中的三个部分如下:
- 模型(Model)
模型负责与数据库进行交互,定义数据的结构和行为,并提供查询和修改等方法。在Django中,模型通常使用ORM(Object-Relational Mapping)进行实现,即将数据库中的表映射为Python对象,方便使用和管理。 - 模板(Template)
模板是用于呈现数据的视图组件,它将数据和HTML等页面元素组合起来,呈现给用户。模板通常包括各种模板标签和模板过滤器等,用于控制页面的显示和格式。 - 视图(View)
视图是Web应用程序的核心处理逻辑,负责处理用户请求和数据响应等。视图接收用户请求,根据请求的不同,调用模型进行数据查询和修改,并将结果呈现给模板进行渲染和显示。视图通常包括请求处理函数和视图类等,用于实现各种业务逻辑和处理方式。
MTV模型中还有一些其他的概念和组件:- URL路由(URL Routing)
URL路由是将用户请求与视图函数或类进行匹配的过程,它根据请求的URL地址,将请求转发给相应的视图进行处理。在Django中,URL路由通常通过URLconf(URL Configuration)进行配置和管理。 - 中间件(Middleware)
中间件是位于请求和响应之间的一组处理函数,它可以在请求被处理之前和之后进行一些预处理和后处理操作。中间件可以用于请求日志、错误处理、权限验证等方面。 - 表单(Form)
表单是用于在视图中处理用户输入的数据的组件,它提供了一种方便的方式来接收、验证和处理用户提交的数据。在Django中,表单通常通过Form类进行定义和实现。 - 静态文件(Static Files)
静态文件是Web应用程序中用于呈现页面的一些资源文件,如CSS、JavaScript、图片等。Django提供了一种方便的方式来管理和呈现静态文件,可以通过STATIC_URL和STATICFILES_DIRS等设置来进行管理。
- URL路由(URL Routing)
开始第一个hello world
首先pip install Django
创建第一个项目
Django整体目录介绍
开始项目开发前,需要了解Django项目的构成,如下图是一个已有的项目,除了静态文件,模板外,其余的为项目和APP,my_site与项目同名,内部包含Django的一些配置,除了my_site,templates,static外其他的为app,在Django中一个app实现某个具体功能
由此可见Django中项目和app的关系:
- 一个project是配置文件和多个app的集合,这些app组合成整个站点;
- 一个project可以包含多个app;
上图中的project(my_site)的目录结构如下:
project_name/
manage.py
project_name/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
-
manage.py
:Django命令行工具,用于执行与项目相关的任务,例如运行开发服务器、创建数据库等。 -
project_name/settings.py
:Django项目的设置文件,包含配置项目的所有设置,例如数据库、静态文件路径、应用程序、中间件等。 -
project_name/urls.py
:Django项目的URL配置文件,包含URL模式和视图函数的映射关系。 -
project_name/asgi.py
:用于ASGI(异步服务器网关接口)服务器的入口点,通常用于生产环境。 -
project_name/wsgi.py
:用于WSGI(Web服务器网关接口)服务器的入口点,通常用于生产环境。
开始第一个hello world
- 创建一个project,
django-admin startproject myproject
- 创建一个app,
python manage.py startapp testapp
- 将app加入到setting中
- 编写app的view
- project和app进行关联,编写路由
- 启动项目进行访问,
python .\manage.py runserver 8080
通常上面的例子,对Django有了简要的理解,下面是工作中常用到的Django命令:
Django常用命令
- 创建项目:
django-admin startproject projectname
,用于创建一个新的Django项目。 - 创建应用:
python manage.py startapp appname
,用于创建一个新的Django应用程序。 - 启动服务器:
python manage.py runserver
,用于启动Django服务器,以便在本地环境中测试和调试Web应用程序。 - 数据库迁移:
python manage.py makemigrations
和python manage.py migrate
,用于在数据库中创建新的表或更改现有表的结构。 - 清空数据库:
python manage.py flush
,用于清空整个数据库中的所有数据,谨慎使用。 - 查看路由表:
python manage.py show_urls
,用于查看当前项目的路由表和视图函数。 - 运行单元测试:
python manage.py test
,用于运行项目的单元测试,以确保项目的稳定性和正确性。 - 创建管理员命令:
python manage.py create_command
,用于创建自定义的管理命令,方便对Web应用程序进行管理和操作。 - 收集静态文件:
python manage.py collectstatic
,用于将项目中的静态文件收集到指定的目录中,以便于部署和发布Web应用程序。 - 显示当前安装的Django版本:
python -m django version
,用于显示当前安装的Django版本号。
Django数据模型
后端接口开发中与数据库打交道是一个重要的部分,数据模型主要处理与数据库打交道,在创建模型前需要了解models中的字段类型和方法中使用到的参数,以下为常用字段类型和关键字。
字段类型和关键字
- 常用的字段类型映射关系,字段类型
- IntegerField : 整型,映射到数据库中的int类型。
- CharField: 字符类型,映射到数据库中的varchar类型,通过max_length指定最大长度。
- TextField: 文本类型,映射到数据库中的text类型。
- BooleanField: 布尔类型,映射到数据库中的tinyint类型,在使用的时候,传递True/False进去。如果要可以为空,则用NullBooleanField。
- DateField: 日期类型,没有时间。映射到数据库中是date类型, 在使用的时候,可以设置DateField.auto_now每次保存对象时,自动设置该字段为当前时间。
- DateTimeField: 日期时间类型。映射到数据库中的是datetime类型,在使用的时候,传递datetime.datetime()进去。
- Field的常用参数:
- primary_key: 指定是否为主键。
- unique: 指定是否唯一。
- null: 指定是否为空,默认为False。
- blank: 等于True时form表单验证时可以为空,默认为False。
- default: 设置默认值。
- DateField.auto_now: 每次修改都会将当前时间更新进去
- DateField.auto_now_add: 第一次添加进去,都会将当前时间设置进去。以后修改,不会修改这个值
数据迁移示例
- 首先创建模型的代码
- 配置seting文件中的数据库信息
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'blog', #你的数据库名称 数据库需要自己提前建好
'USER': 'root', #你的数据库用户名
'PASSWORD': '', #你的数据库密码
'HOST': '', #你的数据库主机,留空默认为localhost
'PORT': '3306', #你的数据库端口
}
}
- 生成迁移文件
python manage.py makemigrations
- 进行迁移
python manage.py migrate
- 如下命令查看具体转换成的表:
python .\manage.py sqlmigrate testapp 0001
- 如下命令查看具体转换成的表:
- 去数据库检查看到表信息同步到了数据库
Django模型数据的增删改查
- 新增
def orm_add(request):
# 第一种方式
TestModel.objects.create(name="张三",age=18)
# 第二种方式
obj = TestModel(name='李四', age=20)
obj.save()
# 第三种方式
dict1={'name':'王五','age':30}
TestModel.objects.create(**dict1)
return HttpResponse("数据添加成功!")
将该方法加入到路由中将得到如下的结果:
2. 更新
def orm_update(request):
# 第一种
obj = TestModel.objects.get(id=1)
obj.name = 'dapeng'
obj.save()
# 第二种
TestModel.objects.filter(id=2).update(name='test')
return HttpResponse("数据修改成功!")
- 查询
def orm_get(request):
# 查所有
all_list = TestModel.objects.all()
# 查单条
all_list = TestModel.objects.get(id=1)
all_list = TestModel.objects.get(name="test")
# filter
all_list = TestModel.objects.filter(name="张三")
all_list = TestModel.objects.filter(name="张三")[:2]
# 排序
# 使用-倒叙排序
all_list =TestModel.objects.order_by('-id')
all_list = TestModel.objects.filter(name="张三").order_by('-id')
res = ""
for var in all_list:
res += var.name + " "
return HttpResponse("<p>"+res+"</p>")
如下图是从查询张三的结果中提取头两个数据:
4. 删除
def orm_delete(request):
obj = TestModel.objects.get(id=1)
obj.delete()
return HttpResponse("数据删除成功!")
- 其他
如果没有获取数据则返回404
def orm_get_object(request):
get_object_or_404(TestModel,id=20)
如果没有获取数据则创建
def orm_get_create(request):
TestModel.objects.get_or_create(name="sunpeng")
return HttpResponse("如果数据不存在则新建")
- 复杂查询
一般我们在Django程序中查询数据库操作都是在QuerySet里进行进行,例如下面代码:
Book.objects.filter(price__gte=70, title__startswith="J")
随着我们的程序越来越复杂,查询的条件也跟着复杂起来,这样简单的通过一个filter()来进行查询的条件将导致我们的查询越来越长。当我们在查询的条件中需要组合条件时(例如两个条件“且”或者“或”)时。我们可以使用Q()查询对象。例如下面的代码:
from django.db.models import Q
q1 = Q(price__gte=70)
q2 = Q(title__startswith="J")
这样就生成了一个Q()对象,我们可以使用符号&(且)或者|(或)或者~(非)多个Q()对象组合起来传递给filter(),exclude(),get()等函数。当多个Q()对象组合起来时,Django会自动生成一个新的Q()。例如下面代码就将两个条件组合成了一个:
Q(price__gte=70) | Q(title__startswith="J")
多个Q()对象之间的关系Django会自动理解成“且(and)”关系,例如下面的代码:
Book.objects.filter(Q(id__gt=6), Q(price__gte=70) | Q(title__startswith="J"))
此外,Q()对象可以结合关键字参数一起传递给查询函数,不过需要注意的是要将Q()对象放在关键字参数的前面,例如下面的代码:
Book.objects.filter(Q(id__gt=6), Q(price__gte=70) | Q(title__startswith='J'), author__icontains='jack')
以下为常用的语法说明:
Django路由
在Django中请求通过中间件转发送给URL分发器,URL转发给View。View从Model中获取数据,直接返回或者通过Template返回,然后借助中间件返回结果。
常用的做法是项目的根路由分发给各自独立的App,APP根据规则分发给View,View从Model中获取数据直接返回或者通过Template返回给中间件。
Django 路由在 urls.py 配置,urls.py 中的每一条配置对应相应的处理方法。一个路由配置模块就是一个urlpatterns列表,列表的每个元素都是一项path,每一项path都是以path()的形式存在。path()方法可以接收4个参数,其中前2个是必须的:route和view,以及2个可选的参数:kwargs和name。
路由语法
路由规则
- 在Django中,可以通过为路由规则指定一个名称来命名该路由规则。例如:
from django.urls import path
from . import views
urlpatterns = [
path('blog/', views.blog_list, name='blog_list'),
path('blog/<int:pk>/', views.blog_detail, name='blog_detail'),
]
在上面的例子中,name
参数为路由规则指定了别名。需要使用时,可以使用该名称找到对应的路由,例如:
def goto(request):
if request.method=='GET':
# 重定向到外链
return redirect('https://www.baidu.com')
elif request.method=='POST':
# 重定向到内部路由
return redirect('blog_detail')
else:
HttpResponse("xxx")
在上面的例子中,reverse
函数根据名称生成URL。参数args
表示传递的动态参数。在这里,生成的URL是/blog/1/
。
- 使用正则表达式
在Django中,路由规则是使用正则表达式进行匹配的。可以使用正则表达式的语法来定义路由规则。例如:
from django.urls import path
from . import views
urlpatterns = [
path('blog/<int:year>/<int:month>/', views.blog_detail, name='blog_detail'),
]
在上面的例子中,使用了正则表达式的语法来定义路由规则。<int:year>
和<int:month>
是动态参数,表示传递一个整数类型的参数到blog_detail
视图函数中。
- 使用通配符
在Django中,可以使用通配符来匹配任意字符。通配符用*
表示。例如:
from django.urls import path
from . import views
urlpatterns = [
path('blog/*/', views.blog_list, name='blog_list'),
]
在上面的例子中,使用通配符*
来匹配URL中的任意字符。这意味着所有以/blog/
开头的URL都将被匹配到。
视图和路由的对应
- 在视图函数中获取参数
在Django中,可以在视图函数中通过参数来获取路由中的动态参数。例如:
from django.shortcuts import render
def blog_detail(request, year, month, slug):
# 使用year、month和slug参数来查询博客文章
#
路由转发
通常,建议是在每个app里,各自创建一个urls.py路由模块,然后从根路由出发,将app所属的url请求,全部转发到相应的urls.py模块中。
Django视图函数
视图函数,简称视图,本质上是一个Python函数,它接受Web请求并且返回Web响应。
Django View视图层:Request对象
request对象请求相关的常用属性
- method 表示请求中使用的HTTP方法的字符串,用大写表示
- GET 类似于字典的对象,包含所有给定的HTTP GET参数
- POST 类似字典的对象,包含所有给定的HTTP POST参数,前提是请求包含表单数据
- path_info 返回用户访问url,不包括域名
- body 请求体(bytes类型),request.POST的数据就是从body里面提取到的
Django View视图层:redirect()重定向方法
语法:redirect(to, args, permanent=False, *kwargs),根据传递进来的url参数,返回HttpResponseRedirect。
def goto(request):
if request.method=='GET':
# 重定向到外链
return redirect('https://www.baidu.com')
Template模板和过滤器
Django 模板是一个简单的标记语言,用于定义 HTML 页面的结构和布局。
Django 模板定义了一个基于变量和标签的语法,可以通过加载和填充数据来生成最终输出的 HTML 页面。其中,变量代表了在视图中定义的数据,而标签则代表了一些特殊的操作,例如循环、条件判断等。
Django 模板支持多重继承,允许开发者定义基础模板并在其基础上扩展其他模板。同时,它还提供了一些内置的标签和过滤器,用于处理常见的任务,例如日期格式化、字符串操作、数学计算等。
创建一个模板
- 配置时首先在setting中配置template的路径,如下图所示
- 编写视图代码时,使用render函数指向对应的模板,如下为render函数的简单示例:
其中render函数有三个必填参数 ,request固定参数, 模板的路径,和上下文信息。
def helloworld(request):
# 访问数据库,获取所有信息
all_list = TestModel.objects.all()
# 将信息放在context中
context = {
"datas": all_list
}
# render有三个必填参数,request,模板的路径,和上下文信息
return render(request, "testapp/helloworld.html", context)
- 对应testapp/helloworld.html文件如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>孙大鹏的模板</title>
</head>
<body>
<!--for 标签-->
<!--<ul>-->
<!-- {%for data in datas%}-->
<!-- <li style="color: brown;">-->
<!-- {{data.name}}-->
<!-- </li>-->
<!-- {% endfor %}-->
<!--</ul>-->
<!--if 标签-->
<ul>
{%for data in datas%}
{% if forloop.counter|divisibleby:"2" %}
<li style="color: red;">
{{data.name|length}}
</li>
{% else %}
<li style="color: blue;">
{{data.name}}
</li>
{% endif %}
{% endfor %}
</ul>
</body>
</html>
在如上的示例中,除了html的基本语法,还涉及到变量的引用,标签语法,过滤器。
引用变量时使用{{}}包裹需要引用的变量,如下示例,data是从数据库获取的对象,name是data对象的name属性。
{{data.name}}
过滤器可以理解为获取参数并通过函数对其进行处理并返回,过滤器语法为 | 加上过滤器名称,如下示例为获取data对应的name属性,并通过length过滤器函数计算name的长度。
{{data.name|length}}
如下示例为标签语法,标签语法为{%%}并在中间加上逻辑判断,如if for等函数,标签语法和html标签一样,通常为成对出现。
{%for data in datas%}
{% endfor %}
回到helloworld.html示例,上面示例的实现的是,如果所属序列为偶数,则以红色显示name的长度,如果为奇数,则显示name为绿色,启动服务后前端渲染的页面如下:
模板的继承
templates中的index.html继承base.html中的内容,如下为base.html的内容:
<!DOCTYPE html>
<html lang="en">
<head>
<title>{% block title %}测试平台{% endblock %}</title>
</head>
<body>
<h1>页头:logo</h1>
<hr/>
<div id="sidebar">
{% block sidebar %}
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog/">Blog</a></li>
</ul>
{% endblock %}
</div>
<div id="content">
{% block content %}{% endblock %}
</div>
<hr/>
<h1>页脚:联系我们</h1>
</body>
</html>
如下为index.html的内容
{% extends 'base.html' %}
{% block title %}孙大鹏的测试{% endblock %}
{% block content %}
<h1>我是子模板页面-修改后的内容</h1>
{% endblock content %}
上面的示例,{% extends ‘base.html’ %} 继承base模板中的内容,{% block title %} {% endblock %},{% block content %} {% endblock content %}是可以被替换掉的内容。
Django模板中的块(blocks)是一个常见的概念,它允许页面的不同部分可以在同一个模板文件中被添加或替换掉。块由两个部分组成:块标志和块内容。Django模板中,一般有两个主要的块:标题块(block title)和内容块(block content)。
块标题(block title)是定义在模板中并带有一个名字的HTML标记,例如。这个标记会被插入到一个页面的头部,提供一个标题给这个页面。在每个页面中,标题块可以被重定义,以显示不同的标题。
块内容(block content)是一个定义在模板中的块标记,它允许页面中某个区域的内容被添加或替换掉。
自定义标签和过滤器
djano中自带的标签或者过滤器可能无法满足我们的需求,这时就需要自定义标签或者过滤器,如下在项目的目录下,添加了一个py文件,并使用@register.filter,@register.simple_tag装饰自定义的方法
register = template.Library()
@register.filter(name='cut')
def cut(value, arg):
"""将value中的所有arg部分切除掉"""
return value.replace(arg, '')
@register.simple_tag
def current_time(format_string):
return datetime.datetime.now().strftime(format_string)
如下为在html文件中使用该标签和过滤器
<!DOCTYPE html>
<html lang="en">
{% load tags %}
<head>
<meta charset="UTF-8">
<title>测试开发技术</title>
</head>
<body>
<ul>
{% for data in datas %}
{% if forloop.counter|divisibleby:"2" %}
<li style="color:Red">
{{data.id}} -{{data.name|cut:"t"}}-{{data.age}}-{{data.create_time}}
</li>
{% else %}
<li style="color:blue">
{{data.id}} -{{data.name| cut:"t"}}-{{data.age}}-{{data.create_time}}
</li>
{% endif %}
{% endfor %}
{% current_time "%Y-%m-%d %H:%M:%S" as time %}
<h1>当前时间为:{{time}}</h1>
</ul>
</body>
</html>
如上代码使用过滤器获取data.name,并去除字符串中的t字符,将current_time 显示为%Y-%m-%d %H:%M:%S,并以h1的格式显示。
下图中应该显示为litest,经过处理显示为lies。
用户登录体系以及身份认证
添加身份认证相关组件
首先需要在项目的setting文件中对身份认证的app和中间件进行设置,如下所示:
INSTALLED_APPS = [
'django.contrib.admin',
# 身份认证的相关组件
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'testapp',
'blog',
'django.contrib.admindocs',
'rest_framework',
]
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',
]
用户名和密码的创建和修改
-
创建用户的方法
- 通过命令行的方式
python manage.py createsuperuser - 通过代码方式
def adduser(request): # User.objects.create_user(username='sundapeng2', password='123456') # User.objects.create(username='sundapeng2', password='123456') User.objects.create_superuser(username='sundapeng2', password='123456') return HttpResponse('创建用户成功')
- 通过命令行的方式
-
更改密码的方法
- 通过命令行的方式
python manage.py changepassword username - 通过代码方式
def change_pwd(request): user = User.objects.get(username='sundapeng') user.set_password('testtesttest') user.save() return HttpResponse('修改密码成功')
- 通过命令行的方式
身份认证的实现
身份认证使用auth.authenticate实现,使用auth.authenticate校验请求中的用户名和密码,然后加入判断逻辑,如下为伪代码:
def auth_user(request):
user = auth.authenticate(username='testadmin', password='123456')
if user is not None:
if user.is_active:
msg = "用户激活,验证成功!"
else:
msg = '用户未激活,为禁用状态'
else:
msg = "用户不存在或者密码错误"
return HttpResponse(msg)
Django中获取用户名和密码
在Django中,可以通过request对象获取用户的用户名和密码。具体方法如下:
- 获取用户名在视图函数中,通过request对象的user属性获取当前登录用户的信息,其中包括用户名。示例代码如下:
def my_view(request):
if request.user.is_authenticated:
# 如果用户已经登录,获取当前登录用户的用户名
username = request.user.username
return HttpResponse('Hello, {}'.format(username))
else:
return HttpResponse('Please login first.')
在上面的代码中,如果用户已经登录,则通过request.user.username属性获取当前登录用户的用户名,然后返回一个包含用户名的响应。
- 获取密码
在Django中,用户密码是加密存储的,无法直接获取。通常情况下,我们只需要知道用户是否输入了正确的密码,而不需要获取真实的密码值。
在身份验证过程中,我们可以通过Django的验证框架来验证用户提供的密码是否正确。示例代码如下:
from django.contrib.auth import authenticate
def my_login(request):
if request.method == 'POST':
# 获取POST请求中的用户名和密码
username = request.POST['username']
password = request.POST['password']
# 验证用户输入的用户名和密码是否正确
user = authenticate(request, username=username, password=password)
if user is not None:
# 如果用户名和密码正确,登录用户并重定向到首页
login(request, user)
return redirect('home')
else:
# 如果用户名和密码不正确,返回登录页面并显示错误消息
error_msg = 'Invalid username or password.'
return render(request, 'login.html', {'error_msg': error_msg})
else:
# 如果是GET请求,返回登录页面
return render(request, 'login.html')
在上面的代码中,我们首先从POST请求中获取用户输入的用户名和密码,然后通过Django的authenticate函数验证用户名和密码是否正确。如果用户名和密码正确,就调用login函数登录用户并重定向到首页;否则,就返回登录页面并显示一个错误消息。
页面跳转
为了限制匿名用户的访问,使用login_required装饰器,限制只有登陆后才能访问该url,否则跳转到登陆页面
@login_required(login_url='/user/login')
def my_index(request):
pass
Cookie的介绍和须知
Cookie是通过浏览器和服务器之间的 HTTP 通信生成的。当用户在访问一个网站时,服务器可以通过在响应头中设置一个包含信息的 Cookie,将数据存储在用户的浏览器中。接着,当用户再次访问同一网站时,浏览器可以在请求头中发送此 Cookie,以便服务器了解用户的过去交互情况。 Cookie 可以存储用户的身份验证信息、购物车中的商品信息等等,以提供更好的用户体验。
Django中的Cookie
如下为如何设置cookie并获取cookie的伪代码:
def set_cookie(request):
resp = HttpResponse("返回一个空响应")
resp.set_cookie("username", "admin", 3600)
return resp
def get_cookie(request):
cookie = request.COOKIES.get('username')
return HttpResponse(f"当前的cookie;{cookie}")
Session的介绍和须知
session和cookie的最大区别是数据存储位置不同:Cookie是存储在客户端浏览器中的文本文件,而Session是存储在服务器端的内存或磁盘上的数据,也就是说cookie控制权交给了浏览器,session的控制权交给了服务器。
Django中的Session
在setting文件中设置django session相关的组件和中间件:
INSTALLED_APPS = [
'django.contrib.admin',
# 身份认证的相关组件
'django.contrib.auth',
'django.contrib.contenttypes',
# session相关组件
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'testapp',
'blog',
'django.contrib.admindocs',
'rest_framework',
'userapp',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
# session相关的中间件
'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 session相关的伪代码:
def set_sessions(request):
request.session['usernametest'] = 'dapeng'
value = request.session.get('usernametest')
return HttpResponse(f"{value}")
定制开发Admin管理后台
可以按照如下的步骤开发Admin管理后台
- 创建管理员账户
python manage.py createsuperuser - 创建数据模型
在创建管理平台之前,需要创建数据模型,对数据进行存储。在真实环境中,存储数据是在多张表中,不同表之间也通过各种键进行关联。
以下是为博客管理平台设计的后台管理系统,分为文章分类,文章标签,文章列表,文章列表和标签,用户,分类等进行关联。
class BlogCategory(models.Model):
"""
Category 只需要一个简单的分类名 name 就可以了。
CharField 指定了分类名 name 的数据类型,CharField 是字符型,
CharField 的 max_length 参数指定其最大长度,超过这个长度的分类名就不能被存入数据库。
然后给name设置了一个'分类'的名称
"""
name = models.CharField('文章分类', max_length=100)
class Meta:
verbose_name = '文章分类'
verbose_name_plural = '文章分类'
def __str__(self):
return self.name
class BlogTags(models.Model):
name = models.CharField('文章标签', max_length=100)
class Meta:
verbose_name = '文章标签'
verbose_name_plural = '文章标签'
def __str__(self):
return self.name
class BlogArticleList(models.Model):
title = models.CharField('标题', max_length=70)
intro = models.TextField('摘要', max_length=200, blank=True)
#规定一篇文章只能对应一个分类,但是一个分类下可以有多篇文章,所以我们使用的是 ForeignKey,即一对多的关联关系
category = models.ForeignKey(BlogCategory, on_delete=models.CASCADE, verbose_name='分类', default='1')
#对于标签来说,一篇文章可以有多个标签,同一个标签下也可能有多篇文章,所以我们使用ManyToManyField
tags = models.ManyToManyField(BlogTags, blank=True)
body = models.TextField()
# 文章作者,这里 User 是从 django.contrib.auth.models 导入的。
# django.contrib.auth 是 Django 内置的应用,专门用于处理网站用户的注册、登录等流程,User 是 Django 为我们已经写好的用户模型。
# 这里我们通过 ForeignKey 把文章和 User 关联了起来。
# 因为我们规定一篇文章只能有一个作者,而一个作者可能会写多篇文章,因此这是一对多的关联关系,和 Category 类似。
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='作者')
created_time = models.DateTimeField('发布时间', auto_now_add=True)
class Meta:
verbose_name = '文章列表'
verbose_name_plural = '文章列表'
def __str__(self):
return self.title
值得注意的是以下两点:
a. Class Meta是定义模型属性,具体解释如下:
在Django中,每个模型都是一个Python类,继承自django.db.models.Model。其中的一个子类是Meta,它用于定义模型属性。
Meta类允许你定义模型的元数据,例如模型的排序方式、模型的数据库表名或者模型与其它模型之间的关系等。在Meta类中定义的属性通常会影响模型的行为而不是模型表现出来的特征。
常见的Meta属性包括ordering(排序方式)、verbose_name(单数)、verbose_name_plural(复数)、db_table(数据库表名)、unique_together(唯一性约束)等等。
b. 重写__str__(self)用于定义返回,如果没有添加,则在后端添加数据时返回一个对象
下图为没有重写 str内置方法
下图为重写了方法
3. 配置模型到管理员
如下为写到对应app下面admin.py中的代码
admin.site.register(BlogTags)
admin.site.register(BlogCategory)
# 显示的header
admin.site.site_header = '孙大鹏的blog'
# 显示的title
admin.site.site_title = '孙大鹏的blog'
# 注册文章列表,并自定义样式
@admin.register(BlogArticleList)
class BlogArticleListAdmin(admin.ModelAdmin):
# 显示model中对应的信息
list_display = ['id', 'title', 'category', 'body', 'user', 'created_time']
# 每页显示的条目数
list_per_page = 3
# 排序规则:按照创建时间倒序排序
ordering = ('-created_time',)
# 前端可以编辑的字段
list_editable = ['title']
# 可以搜索的字段
search_fields = ['title']
- 启动服务并访问后台管理系统,http://127.0.0.1:8085/admin(我是以8085作为端口启动服务),登陆账号为创建超级用户时候的账号。
- 快速生成管理后台文档
Django Admindocs是Django框架提供的文档生成工具,可以为项目自动生成文档,并且能够嵌入到admin管理后台中。
下面是使用Django Admindocs生成文档,并嵌入到admin管理后台的步骤:- 在settings.py中开启Admindocs应用:
INSTALLED_APPS = [
'django.contrib.admindocs',
]
- 在urls.py中添加文档路由:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('admin/doc/', include('django.contrib.admindocs.urls')),
]
-
安装Python的docutils模块(pip install docutils),然后可以重启服务
-
在admin中访问文档:在管理后台中的任何页面上,都可以查看文档。在页面底部有一个“文档”的链接,点击即可打开文档页面。
构建接口测试服务
1.开发接口时,需要符合Restful的规范
- 使用HTTP动词来描述操作。例如,使用POST来创建资源,GET来获取资源,PUT来更新资源,DELETE来删除资源。
- 使用URI来标识资源。URI应该简洁明了,符合逻辑。使用名词进行命名,不要使用动词。
- 使用HTTP状态码来传递服务器的响应状态。使用合适的状态码来表示操作的结果,例如200 OK表示成功,404 Not Found表示资源不存在,500 Internal Server Error表示服务器发生错误等等。
- 返回JSON格式的数据。JSON格式数据通常比XML格式更简洁易懂。
- 对于API的版本号,建议将其放到URI路径中,而不是放在请求头部。
- 对于安全性和身份验证,建议使用HTTPS协议来保护数据传输,同时使用合适的身份验证方式,例如OAuth2.0。
- 对于错误信息的返回,需要清晰明了,包含有用的信息,如错误类型、错误消息等等。
- 对于API文档的编写,需要简单易懂,符合RESTful风格,可以使用Swagger等工具来生成API文档。
2.对于返回的JSON格式数据,通常有三种方式返回,其中第一种,第二种是直接返回json的数据,第三种是跟对象映射,并返回对应的数据,第三种方式更安全和规范
fake = Faker(locale='zh_CN')
datas = {
'name': fake.name(),
'ssn': fake.ssn(),
'phone': fake.phone_number(),
'address': fake.address(),
'imageurl': fake.image_url(),
}
# 第一种方式
def test_json(request):
return HttpResponse(json.dumps(datas),content_type='application/json')
# 第二种方式
def test_json_v2(request):
return JsonResponse(datas,status=200)
# 第三种方式
def api_article(request):
objs = ArticleAPIModel.objects.all()
serializers = ArticleAPIModelSerializers(objs, many=True)
return JsonResponse(serializers.data,status=200,safe=False)
实现序列化借助DRF,使用pip install djangorestframework
安装,DRF项目地址:https://www.django-rest-framework.org/
序列化和反序列化是两个概念,序列化是指将对象转换为字节流或字符串,以便存储或传输,反序列化则是将字节流或字符串转换回对象的过程。
序列化和反序列化在计算机网络和分布式系统中广泛应用,例如客户端和服务器之间的通信、数据持久化等场景。常见的序列化格式包括JSON、XML、Protobuf等。
在序列化时,对象需要满足一定的条件,如实现Serializable接口(Java)、DataContract Attribute(C#)等,在反序列化时,需要保证序列化的格式和版本一致,否则会造成解析错误。
如下为对应的序列化的模型:
class ArticleAPIModelSerializers(serializers.ModelSerializer):
class Meta:
model = ArticleAPIModel
fields = [
'id',
'title',
'body'
]
代码中ArticleAPIModel对应的model:
class ArticleAPIModel(models.Model):
title = models.CharField('标题', max_length=200)
body = models.TextField('内容', max_length=2000, blank=True)
created = models.DateTimeField('创建时间',auto_now_add=True)
updated = models.DateTimeField('更新时间',auto_now_add=True)
如下示例是使用了序列化和反序列化查询和新增数据,通过序列化模型规定的返回和请求的数据包含的字段,可以限制字段的返回,从而更加安全。
def api_article_v2(request):
if request.method == 'GET':
articles = ArticleAPIModel.objects.all()
serializer = ArticleAPIModelSerializers(articles, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = ArticleAPIModelSerializers(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Django接入BootStrap
BootStrap
Bootstrap是一个流行的开源框架,用于开发响应式、移动端优先的网站和应用程序。该框架使用HTML、CSS和JavaScript构建,提供了大量的样式、布局和组件,可以帮助开发人员快速构建美观且具有一致性的界面。
Bootstrap的主要特点包括:
- 响应式设计:可以自适应不同尺寸的设备屏幕,从而让用户在任何设备上浏览网站时都能得到更好的体验。
- 组件丰富:提供了一系列常见的UI组件,如导航栏、模态框、卡片、表格等等,使得开发界面变得更加方便和快速。
- 样式可定制化:可以通过自定义样式来满足特定项目的需求并获得多样化的设计风格。
- 兼容性好:支持所有现代浏览器,并且可以适配旧版本的浏览器。
由于Bootstrap易于使用、强大、高效且可自定义,因此已成为众多开发人员和组织的首选框架,获得了广泛的支持和社区。
Bootstrap官网:https://v4.bootcss.com/
接入到自己的项目
要在Django项目中使用Bootstrap,请遵循以下步骤:
-
从Bootstrap官网下载所需的CSS和JavaScript文件。
-
在Django项目中创建一个名为“static”的文件夹,并将Bootstrap下载的CSS和JS代码放到该目录下面
-
在Django项目的settings.py文件中,在静态文件配置中添加STATICFILES_DIRS,告知django的静态文件指向的是哪一个文件夹。
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static"), ]
-
写好代码的模块,并在具体的实例中继承它
- footer.html
<!--加载静态资源--> {% load static %} <!-- Footer --> <div> <br><br><br> </div> <!--将静态资源中的样式添加到footer中--> <footer class="py-3 bg-dark fixed-bottom"> <div class="container"> <p class="m-0 text-center text-white">test</p> </div> </footer>
- header.html
<!-- 定义导航栏 --> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <div class="container"> <!-- 导航栏商标 --> <a class="navbar-brand" href="#">我的个人博客</a> <!-- 导航入口 --> <div> <ul class="navbar-nav"> <!-- 条目 --> <li class="nav-item"> <a class="nav-link" href="#">全部文章</a> </li> </ul> </div> </div> </nav>
- base.html,base文件中引用header和footer,形成整体框架
<!-- 载入静态文件 --> {% load static %} <!DOCTYPE html> <!-- 网站主语言 --> <html lang="zh-cn"> <head> <!-- 网站采用的字符编码 --> <meta charset="utf-8"> <!-- 预留网站标题的位置 --> <title>{% block title %}test{% endblock %}</title> <!-- 引入bootstrap的css文件 --> <link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}"> </head> <body> <!-- 引入导航栏 --> {% include 'header.html' %} <!-- 预留具体页面的位置 --> {% block content %}{% endblock content %} <!-- 引入注脚 --> {% include 'footer.html' %} <!-- bootstrap.js 依赖 jquery.js 和popper.js,因此在这里引入 --> <script src="{% static 'jquery/jquery-3.3.1.js' %}"></script> <script src="{% static 'popper/popper-1.14.4.js' %}"></script> <!-- 引入bootstrap的js文件 --> <script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script> </body> </html>
- list.html
<!-- extends表明此页面继承自 base.html 文件 --> {% extends "base.html" %} {% load static %} <!-- 写入 base.html 中定义的 title --> {% block title %} 测试平台-首页 {% endblock title %} <!-- 写入 base.html 中定义的 content --> {% block content %} <!-- 定义放置文章标题的div容器 --> <div class="container"> <div class="row mt-2"> {% for blog in blogs %} <!-- 文章内容 --> <div class="col-4 mb-4"> <!-- 卡片容器 --> <div class="card h-100"> <!-- 标题 --> <h4 class="card-header">{{ blog.title }}</h4> <!-- 摘要 --> <div class="card-body"> <p class="card-text">{{ blog.body|slice:'100' }}...</p> </div> <!-- 注脚 --> <div class="card-footer"> <a href="#" class="btn btn-primary">阅读本文</a> </div> </div> </div> {% endfor %} </div> </div> {% endblock content %}
-
最终效果
DjangoToolBar调试工具
-
安装 Django tool bar
pip install django-debug-toolbar -
在settings.py中添加
#settings.py
INSTALLED_APPS = [
# ...
'debug_toolbar', # 添加到 INSTALLED_APPS
# ...
]
MIDDLEWARE = [
# ...
'debug_toolbar.middleware.DebugToolbarMiddleware', # 添加到 MIDDLEWARE
# ...
]
#必须允许 IP 地址访问,例如 127.0.0.1
INTERNAL_IPS = ['127.0.0.1']
3.路由中添加debug
path('__debug__/',include(debug_toolbar.urls)),
- 运行 Django 项目,浏览器打开工具条
运行 Django 项目,在浏览器中访问项目,点击出现的调试工具条即可。
django toolbar 官方文档:https://django-debug-toolbar.readthedocs.io/en/latest/
Nginx+ uWSGI部署DJango
Nginx是一种轻量级的Web服务器和反向代理服务器,它具有占用资源少、配置简单、性能出色等优点。而uWSGI是一个全栈的WSGI(web服务器网关接口)实现,它可以将Python应用程序连接到各种Web服务器,并提供高性能的生产级别的Web应用程序服务器解决方案。
要在Nginx上部署Django应用程序,需要先安装和配置uWSGI并启动Django应用程序。下面是一个简单的步骤。
步骤1:安装和配置uWSGI1.使用pip安装uWSGI
pip install uwsgi
2.创建uwsgi配置文件uwsgi.ini
[uwsgi]
;项目的根目录
chdir = /usr/myproject
;加载wsgi里面的application模块
module = myproject.wsgi:application
;对外开放端口
socket = 127.0.0.1:8000
;主进程
master = true
;子进程数
workers = 4
;退出、重启时清理文件
vacuum = true
3.更改Django文件的配置文件
Debug改成False,ALLOWED_HOSTS的白名单设置
# DEBUG = True
DEBUG = False
# ALLOWED_HOSTS = [*]
ALLOWED_HOSTS = ['*']
注意:以上配置文件的路径需根据自己的服务器环境调整。
3.使用uWSGI启动Django应用程序
uwsgi --ini /path/to/your/project/uwsgi.ini
步骤2:配置Nginx
1.在Nginx配置文件中添加以下内容:
server {
location / {
# 包含uwsgi的请求参数
include uwsgi_params;
# 转交给uwsgi
uwsgi_pass 127.0.0.1:8000
}
}
2.重启Nginx服务器:
service nginx restart
现在,您的Django应用程序已成功部署在Nginx上,并且可以通过浏览器访问。
下面是搭建环境遇到的一些问题可参考:
- 在阿里云服务器搭建的时候需要另外安装python3环境,可参考 https://zhuanlan.zhihu.com/p/460216030 ,安装后重启阿里云,本地python可以切换到python3
- 搭建服务时候涉及到数据库的搭建可以参考 https://blog.csdn.net/wcy1900353090/article/details/119537984
- debug=False 的情况下尝试访问8000端口没办法直接访问,需要通过nginx访问
wsgi和uwsgi的区别
UWSGI是一个Web服务器,它实现了WSGI协议,它是一个通用的Web服务器接口,可用于Python的应用程序部署。用户应用程序使用WSGI协议与UWSGI通信,并将请求传递给UWSGI,然后UWSGI将请求传递给应用程序。UWSGI具有高效的工作模式,可与多种Web服务器和反向代理服务器配合使用。
WSGI是一个Python应用程序和Web服务器之间的接口规范,它定义了应用程序和服务器之间的通信方法。WSGI接口定义了如何将HTTP请求和响应转换为Python函数调用。这种方式使得Python应用程序可以与多种Web服务器平台集成。WSGI还定义了如何处理HTTP请求和响应头,并提供了一些函数用于处理HTTP请求和响应。