0%

Django框架

创建Django项目

打开cmd命令行,进入到存放Django项目的文件夹,例如我这里进入这个路径:D:\学习笔记\Web开发\test

输入以下代码

1
django-admin startproject django_demo

输入完成后可以看到在当前文件夹下面生成了一个django_demo文件夹,这个文件夹即为我们创建的Django工程。

使用Pycharm打开工程,可以看到Django项目的目录结构如下。

image-20220812112229804

相关文件的作用如下:

文件 说明
manage.py Django程序执行的入口
asgi.py 一个 ASGI 兼容的 Web 服务器的入口,以便运行你的项目。
settings.py Django总的配置文件,可以配置APP、数据库、中间件、模板等诸多选项
urls.py Django默认的路由配置文件,可以在其中使用include包含其他路径下的urls.py
wsgi.py Django实现的WSGI接口的文件,用来处理Web请求

运行项目

1
python manage.py runserver

可以看到服务器已经开始监听8000端口了。

image-20220812113122444

在浏览器中输入127.0.0.1:8000即可访问Django项目。

image-20220812113236102

并且,项目自动给我们生成了一个db.sqlite3数据库文件,Django默认使用这种小型数据库存取数据。也可以根据自己的实际情况在settings.py中进行修改为其他数据库,例如:Mysql等。

使用命令创建后台应用

Ctrl+C组合键关闭服务器,然后执行如下命令执行数据库迁移,生成数据表

1
python manage.py migrate

创建超级管理员用户

1
python manage.py createsuperuser

输入相关帐号、邮箱、密码完成注册。

再次启动服务,进入127.0.0.1/admin,即可进入后台登录界面

登录界面

image-20220812115539969

输入帐号密码,完成登录,进入后台管理界面。

image-20220812115558915

创建一个APP

Django项目中,推荐使用App来完成不同模块的任务,启用一个App非常简单,执行以下命令。

1
python manage.py startapp app1

运行完毕后,django_demo目录下又多了一个app1的目录。

image-20220812135556997

打开app1目录,其文件结构如下:

image-20220812135720639

文件 说明
migrations 执行数据库迁移生成的脚本
admin.py 配置Django管理后台的文件
apps.py 单独配置添加的每个App的文件
models.py 创建数据库数据模型对象的文件
tests.py 用来编写测试脚本的文件
views.py 用来编写视图控制器的文件

仅仅创建App还不能直接使用,还需要对其进行激活。激活的方式非常简单,在django_demo/settings.py配置文件中,找到INSTALLED_APPS列表,添加app1

image-20220812140621206

数据模型

App中添加数据模型(models

1
2
3
4
5
6
7
8
9
10
from django.db import models

class Person(models.Model): # 继承CreateUpdate基类
"""
编写Person模型类,数据模型应该继承于models.Model或其子类
"""
# 第一个字段使用models.CharField类型
first_name = models.CharField(max_length=30)
# 第二个字段使用models.CharField类型
last_name = models.CharField(max_length=30)

Person模型中每一个属性都指明了models下面的一个数据类型,代表了数据库中的一个字段。

上面的类在数据库中会创建如下的表。

1
2
3
4
5
CREATE TABLE myapp_person(
"id" serial NOT NULL PRIMARY KEY;
"first_name" varchar(30) NOT NULL;
"last_name" varchar(30) NOT NULL;
)

对于一些公有的字段,为了优雅的简化代码,可以使用如下的实现方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from django.db import models

# Create your models here.
class CreateUpdate(models.Model): # 创建抽象数据模型,同样要继承于models.Model
# 创建时间,使用models.DataTimeField
created_at = models.DateTimeField(auto_now_add=True)
# 修改时间,使用models.DateTimeField
updated_at = models.DateTimeField(auto_now=True)
class Meta: # 元数据,除了字段意外的所有属性
# 设置model为抽象类。指定该表不应该在数据库中创建
abstract = True

class Person(CreateUpdate): # 继承CreateUpdate基类
"""
编写Person模型类,数据模型应该继承于models.Model或其子类
"""
# 第一个字段使用models.CharField类型
first_name = models.CharField(max_length=30)
# 第二个字段使用models.CharField类型
last_name = models.CharField(max_length=30)

class Order(CreateUpdate): # 继承CreateUpdate基类
"""
编写Order模型类,数据模型应该继承于models.Model或其子类
"""
order_id = models.CharField(max_length=30, db_index=True)
order_desc = models.CharField(max_length=30)

这时候需要创建日期和修改日期的数据模型都可以继承于CreateUpdate类。

在上面创建表时使用了2个字段类型:CharFieldDateTimeField,它们分别为字符串值类型和日期时间类型。此外,django.db.models还提供了很多常见的字段类型,如下表所示。

字段类型 说明
AutoField 一个id自增的字段,但在创建表过程中,Django会自动添加一个自增的主键字段
BinaryField 一个保存二进制源数据的字段
BooleanField 一个布尔值字段,应该指明默认值,在管理后台中默认呈现为CheckBox形式
NullBooleanField 可以为None的布尔值字段
CharField 字符串值字段,必须指明参数max_length值,在管理后台中默认呈现为TextInput形式
TextField 文本域字段,对于大量文本应该使用TextField。在管理后台中默认呈现为Textarea形式
DateField 日期字段,代表Pythondatetime.date的实例。在管理后台中默认呈现为TextInput形式
DateTimeField 日期时间字段,代表Python中的datetime.datetime实例。在管理后台中默认呈现TextInput形式。
EmailField 邮件字段,是CharField的实现,用于检查该字段值是否符合邮件地址格式。
FileField 上传文件字段,在管理后台中默认呈现为ClearableFileInput形式
ImageField 图片上传字段,是FileField的实现。在管理后台中默认呈现为ClearableFileInput形式
IntegerField 整数值字段,在管理后台中默认呈现为NumberInput或者TextInput形式
FloatField 浮点数值字段,在管理后台中默认呈现为NumberInput或者TextInput形式
SlugField 只保存字母数字下划线连接符,用于生成URL的短标签
UUIDField 保存一般统一标识符的字段,代表PythonUUID的实例,建议提供默认值default
ForeignKey 外键关系字段,需提供外键的模型参数和on_delete参数(指定当该模型实例删除时,是否删除关联模型),如果要外键的模型出现在当前模型后面,需要在第一个参数中使用单引号'Manufacture'
ManyToManyField 多对多关系字段,与ForeignKey类似
OneToOneField 一对一关系字段,常用于扩展其他模型

执行数据库迁移

完成数据模型后,开始做数据库迁移。如果不使用Django默认自带的sqlite数据库,而是使用当下比较强大的MySQL数据库,那么,需要在django_demo/setting.py配置文件中进行如下修改。

原始内容:

1
2
3
4
5
6
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}

修改为(注:要使用MySQL数据库首先需要自己在本地进行数据库的安装,并创建好数据库django_db):

1
2
3
4
5
6
7
8
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_db', # 数据库名称
'USER': 'root', # 数据库用户名
'PASSWORD': '123456' # 数据库密码
}
}

然后在django_demo/__init__.py文件中,添加以下代码

1
2
3
4
5
import pymysql

# 为了使pymysql发挥最大的数据库操作性能
pymysql.install_as_MySQLdb()

然后在控制台中执行以下代码,将数据库迁移至MySQL

1
2
python manage.py makemigrations  # 生成迁移文件
python manage.py migrate # 迁移数据库,创建新表
  • 生成迁移文件

    image-20220812150902666

    app1/migrations下生成了一个迁移文件,如下图所示

    image-20220812151736480

  • 迁移数据库,创建新表

    image-20220812150928228

打开数据库可视化软件Navicat可以看到数据库中生成很多表格

image-20220812151015292

Django会默认按照App名称+下划线+模型类名称小写的形式创建数据表。

如上图中的:

  1. app1_order
  2. app1_person

在这里有人可能就有疑问了,我们在models数据模型中定义了三个数据类,为什么这里只生成了两个,CreateUpdate为什么没有生成表格?

是因为我们在数据类定义过程中,在CreateUpdate中加上了以下代码,将其设置为抽象类,该表不会在数据库中进行创建。

1
2
class Meta:
abstract = True

image-20220812151501651

了解Django数据API

启用交互式命令行

cmd控制台中输入:python manage.py shell启动交互式命令行。

image-20220812151837212

接下来就在交互式命令行中输入相关代码对数据库中的数据进行操作。

要操作数据库,首先需要将数据模型导入进来

1
from app1.models import Person, Order

接下来使用相关命令对数据库中的表格进行增删改查。

创建数据

首先使用数据模型创建一个数据实例,然后调用实例对象的save()方法进行数据的存储。

1
2
3
# 在Person表格中插入first_name='luo', last_name='ming'
p = Person(first_name='luo', last_name='ming')
p.save()

打开表格可以看到,当前数据已经被插入到数据库中

image-20220812152619764

此外还可以只插入一个字段名称,例如:只设置first_name='L'

1
2
p = Person(first_name='L')
p.save()

image-20220812153051848

查询数据

查询所有数据

调用Person.onjects.all()方法

1
Person.objects.all()

image-20220812153143970

查询单个数据

调用Person.objects.get()方法,注意该方法必须返回一个确定的值,当条件匹配到了多条值的时候就会报错。

1
Person.objects.get(id=1)

image-20220812153409182

查询指定条件的数据

调用Person.objects.filter()方法

  • 查找指定first_name字段值,例如:luo
1
Person.objects.filter(first_name__exact='luo')

image-20220812153628375

  • 查找id值大于1的数据
1
Person.objects.filter(id__gt=1)

image-20220812153741630

条件符号汇总:

符号 意义
__exact 精确等于
__iexact 精确等于(忽略大小写)
__contains 包含
__icontains 包含(忽略大小写)
__gt 大于
__gte 大于等于
__lt 小于
__lte 小于等于
__in 存在于一个list范围内
__startswith 以…开头
__istartswith 以…开头(忽略大小写)
__endswith 以…结尾
__iendswith 以…结尾(忽略大小写)
__range 在…范围内
__year 日期字段的年份
__month 日期字段的月份
__day 日期字段的日
__isnull 是否为空

查看具体的数据内容

前面我们查询到的所有数据,都是QuerySet格式,无法看到具体内容,我们可以调用其values()方法,查看具体数据。

1
Person.objects.filter(id__gt=1).values()

image-20220812154021568

当不传入任何参数到values()中时,返回所有的字段数据。

当我们只想输出指定字段时,可以在values()方法中进行指定。例如:只要查询出来的first_namelast_name字段。

1
Person.objects.filter(id__gt=1).values(first_name, last_name)

image-20220812154228987

修改数据

修改之前需要先查询到对应的数据,再使用类似于属性修改的方式进行赋值,最后同样调用save()属性进行提交。

  • first_name=L的数据last_name改为M
1
2
3
p = Person.objects.get(first_name='L')
p.last_name='M'
p.save()

image-20220812160204242

删除数据

删除数据同样需要先查找到对应的数据,然后调用delete()方法进行删除,代码如下:

1
Person.objects.get(first_name='luo').delete()

image-20220812160531862

打开数据库发现该条记录已被删除

image-20220812161419429

管理后台

定义好数据模型,就可以配置管理后台了,按照如下代码编辑app1admin.py文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from django.contrib import admin  # 导入admin模块

# Register your models here.
from app1.models import Person, Order # 引入数据模型类

class PersonAdmin(admin.ModelAdmin):
"""
创建PersonAdmin类,继承于admin.ModelAdmin
"""
# 配置展示列表,在Person板块下的列表展示
list_display = ('created_at', 'updated_at', 'first_name', 'last_name')

# 配置过滤查询字段,在Person板块下的右侧过滤框
list_filter = ('first_name', 'last_name')

# 配置可搜索字段,在Person板块下的右侧搜索框
search_fields = ('first_name')

# 配置只读字段展示,设置后该字段不可编辑
readonly_fields = ('created_at', 'updated_at')

# 绑定Person模型到PersonAdmin管理后台
admin.site.register(Person, PersonAdmin)

配置完成后,进入http://127.0.0.1:8000/admin

单击App1 $\rightarrow$ Person效果如下图所示

image-20220812163557589

路由

Django路由(urls)系统的作用就是使views中处理数据的函数与请求的URL建立映射关系。使请求到来之后,根据urls.py中的关系条目,查找到与请求对应的处理方法,从而返回给客户端HTTP页面数据。

app1目录下创建urls.py文件,并定义路由规则,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
from django.urls import path, re_path

from app1 import views as views

urlpatterns = [
path('', views.index), # 根目录
path('index', views.index), # 精确匹配
path('article/<int:id>', views.article), # 匹配一个参数
# 匹配两个参数和一个slug
path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
# 正则匹配4个字符的年份
re_path('articles/(?P<year>[0-9]{4}/)', views.year_archive)
]

定义每个路由的视图规则,在app1目录下的views.py文件中编写视图函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from django.http import HttpResponse
from django.shortcuts import render

# Create your views here.
def index(request):
return HttpResponse("Hello world")

def article(request, id):
content = f"this articles id is {id}"
return HttpResponse(content)

def article_detail(request, year, month, slug):
content = f"this year is {year}, this month is {month}, this slug is {slug}"
return HttpResponse(content)

def year_archive(request, year):
return HttpResponse(year)

app1中的路由加入到总路由【django_demo中的urls.py文件】中,只有加入后才能够通过URL地址进行访问。如果没有加到总路由中,会出现404错误。

1
2
3
4
5
6
7
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path('app1/', include('app1.urls'))
]
  • 访问:http://127.0.0.1:8000/app1/

image-20220812170044532

  • 访问:http://127.0.0.1:8000/app1/article/12

image-20220812170214205

  • 访问:http://127.0.0.1:8000/app1/articles/22/10/lm/

image-20220812170355400

  • 访问:http://127.0.0.1:8000/app1/articles/2022/

image-20220812170415140

表单

app1文件夹下创建一个表单(forms)文件forms.py,添加如下类代码。

1
2
3
4
from django import forms
class PersonForm(forms.Form):
first_name = forms.CharField(label='你的名字', max_length=20)
last_name = forms.CharField(label='你的姓氏', max_length=20)

PersonForm类将呈现为下面的HTML代码。

1
2
3
4
<label for='你的名字'>你的名字:</label>
<input id='first_name' type='text' name='first_name' maxlength="20" required />
<label for='你的姓氏'>你的姓氏:</label>
<input id='last_name' type='text' name='last_name' maxlength="20" required />

forms.Form表单类有一个is_valid()方法,可以在views.py中验证提交的表单是否符合规则。

对于提交的内容,在views.py增加如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def get_name(request):
# 判断请求方法是否为POST
if request.method == 'POST':
# 将请求数据填充到PersonForm实例中
form = PersonForm(request.POST)
# 判断form是否为有效表单
if form.is_valid():
# 使用form.cleaned_data获取请求的数据
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
# 响应拼接后的字符串
return HttpResponse(first_name + ' ' + last_name)
else:
return HttpResponseRedirect('/error/')
# 请求GET方法
else:
return render(request, 'name.html', {'form': PersonForm()})

注意:这里的视图函数与前面稍微有点不同,前面是直接返回HTTP响应,响应的文字内容是自己在函数中定义的。这里返回的是remder()函数对应的结果,这个函数会调用本地的静态HTML文件做为网页的显示内容。

例如:这里返回render(request, 'name.html', {'form': PersonForm()})意思是,返回页面为name.html文件,{'form': PersonForm()}意思是传入到name.html文件中的参数form值是通过表单类PersonForm()获取的。

并且html静态文件需要放入,app1目录下的templates文件夹中,这个文件夹初始是不存在的,需要自己手动创建。文件夹建立好后,创建HTML文件,文件内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/app1/get_name" method="post">{% csrf_token %}
{{form}}}
<button type="submit">提交</button>
</form>
</body>
</html>

其中{{form}},表示该参数需要通过后端获取。

此时工程文件目录如下:

视图函数和相关页面建立好后,还需要再urls中进行路由关联。

urlpatterns列表中加入path('get_name', app1.views.get_name)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from django.urls import path, re_path

import app1.views

urlpatterns = [
path('', views.index), # 根目录
path('index', views.index), # 精确匹配
path('article/<int:id>', views.article), # 匹配一个参数
# 匹配两个参数和一个slug
path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
# 正则匹配4个字符的年份
re_path('articles/(?P<year>[0-9]{4}/)', views.year_archive),
path('get_name', app1.views.get_name)
]
  • 访问:http://127.0.0.1:8000/app1/get_name

image-20220812172425655

输入名字和姓氏,点击提交。得到如下返回结果。

image-20220812172458181

视图

前面我们已经使用过了app1的路由和视图,并将它们两者进行了关联。路由用来获取用户的访问请求,获取到请求后将响应对应到视图中,让视图函数进行进一步处理并返回页面内容。

此外,我们还可以给根目录定义相关的视图。

需要在与app1同级的目录django_demo下创建views.py文件。

1
2
3
4
5
from django.http import HttpResponse

def index(request):
return HttpResponse('Hello Django!')

然后在总路由中进行关联。

1
2
3
4
5
6
7
8
9
10
11
from django.contrib import admin
from django.urls import path, include

from django_demo import views

urlpatterns = [
path('admin/', admin.site.urls),
path('app1/', include('app1.urls')),
path('', views.index)
]

关联后访问,根目录(http://127.0.0.1:8000/)就会出现以下页面内容。

image-20220812173227827

-------------本文结束感谢您的阅读-------------