目录
3.2请求对象: HttpRequest 对象(简称 request 对象)包含浏览器的请求信息
Django介绍
Django是一个遵循 MVC 设计模式的框架,MVC是Model、View、Controller三个单词的简写,分别代表模型、视图、控制器。
Django其实也是一个MTV 的设计模式,MTV是Model、Template、View三个单词的简写,分别代表模型、模版、视图 。但是在Django中,控制器接受用户输入的部分由框架自行处理,所以 Django 里更关注的是模型(Model)、模板(Template)和视图(Views),它们各自的职责如下:
MTV 模型
-
M 表示模型(Model):编写程序应有的功能,负责业务对象与数据库的映射(ORM)。
-
T 表示模板 (Template):负责如何把页面(html)展示给用户。
-
V 表示视图(View):负责业务逻辑,并在适当时候调用 Model和 Template(通常是views.py:定义不同的函数,处理不同的请求)。
-
URL 分发器:将一个个 URL 的页面请求分发给不同的 View 处理,View 再调用相应的 Model 和 Template。(urls.py:用户请求的url和视图建立映射关系)
创建Django项目:
1.命令行方式:
terminal:切换到想建项目的目录,django-admin startproject 项目名称,会自动生成如下项目目录
terminal:conda activate 激活conda
2.Pycharm方式:
file ---> new project ---- 选择Django ---> 配置路径和项目名称 ---> 配置环境(默认用系统环境) ----> 点击create(完成创建)
项目目录介绍:
-
mydjango: 项目的容器。
-
manage.py: 一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。
-
mydjango/init.py:一个空文件,告诉 Python 该目录是一个 Python 包。
-
mydjango/asgi.py:一个 ASGI 兼容的 Web 服务器的入口,以便运行你的项目。
-
mydjango/settings.py: 该 Django 项目的设置/配置。
-
mydjango/urls.py: 该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录",保存url与视图的对应关系
-
mydjango/wsgi.py: 一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目。
根目录下新建statics文件夹放置css、js等静态文件
1.在 settings.py 文件的最下方配置添加以下配置:
STATIC_URL = '/static/' # 别名 STATICFILES_DIRS = [ os.path.join(BASE_DIR, "statics"), #自己建的文件名称statics ]
2.在 statics 目录下创建 css 目录,js 目录,images 目录,plugins 目录, 分别放 css文件,js文件,图片,插件。
3.在模板文件中:
-
<img src="/static/images/flower.jpg">
-
动态获取STARIC_URL,拼接静态文件路径:
{% load staticfiles %} //引入
<img src="{ % static ' images/flower.jpg' % }"> // 拼接
应用实例:在mydjango下新建视图views.py处理请求,在urls.py中urlpatterns里建立路径和视图的对应关系,启动项目。
创建应用:
一个项目可能有多个功能模块,一个功能模块对应一个应用APP
1.命令行模式创建应用:在 Terminal 中输入 python manage.py startapp 应用名
或者django-admin.exe startapp 应用名。
配置settings.py,将应用名字进行注册。
2.使用pycharm创建:file--->new project --> django ---> Location选择此项目,在More Settings 中Application name :app名字。
应用目录说明:
- myapp1:app名称
- myapp1/migrations:数据模型迁移记录
- myapp1/admin.py:自带的admin,后台管理
- myapp1/apps.py:app相关
- myapp1/modela.py:数据映射关系,模型类,和数据库相关
- myapp1/views.py:视图相关,定义不同(视图)函数,接收请求,进行处理,返回应答
运行项目:
1.命令行:和manage.py同级目录下,在终端 python manage.py runserver 127.0.0.1:8000
2.pycharm:Edit Configurations配置信息,绿色三角或者直接按 Ctrl+shift+F10
退出项目:Ctrl+C退出
一、模板
上例将数据与视图混合在一起,不符合 Django 的 MVC 思想。 Django 模板,用于分离文档的表现形式和内容
1.)根目录下新建templates文件夹放置模板文件(html页面)
2.)配置模板目录
修改mydjango/settings.py,修改 TEMPLATES 中的 DIRS 为 [BASE_DIR / "templates",]
或者
3)可以在templates为每个app应用建一个文件夹,放置每个应用的模板文件
使用模板文件:
- 加载模板文件:去模板目录获取HTML文件
- 定义模板上下文:向模板传递数据
- 模板渲染:得到一个标准的HTML内容
实例:数据与视图分离
1.变量
模板变量名由数字,字母,下划线和点组成,不能以下划线开头。字典.mydict,列表.mylist,对象.属性名
view:{"HTML变量名" : "views变量名"}
HTML:{{变量名}}
2.列表
view: context['list'] = list(range(1,5))
HTML:{% for i in list %}
<li>{{ i }}</li>
{% endfor %}
3.字典
4.过滤器
5.if/else标签
6.for标签
{% for book in books %}
{{ forloop.counter }}//得到循环次数1,2,3.。。。
<li>{{ book.title }}</li>
{% empty %}
内容为空
{% endfor %}
7.ifequal/ifnotequal标签
8.注释标签
{# 这是一个单行注释 #}
{% comment %}
多行注释
{% endcomment %}
9.include标签:
在模板中包含其他模板的内容 {% include "nav.html" %}
10.csrf_token标签
防止csrf:默认打开CSRF中间件,post提交时加上{% csrf_token %}标签
防御原理:
- 渲染模板时生成csrfmiddlewaretoken的隐藏域。
- 服务器交给浏览器保存一个名为csrftoken的cookie信息。
- 提交表单时,两个值都发给服务器,服务器对比,一样验证通过。
11.HTML转义
HTML默认标记是会被转义的,例如<会变为<,带格式显示需要关闭转义,才能解析为HTML格式。
1)safe过滤器关闭转义 2)autoescape关闭转义
12.自定义标签和过滤器
13.装饰器
有许多操作是用户登录之后才能进行的,比如修改密码,首页,都需要先判断用户是否登录,如果没有登录不能显示相应页面。
#登录判断的装饰器
def login_required(view_func):
def wrapper(request,*view_args,**view_kwargs):
#判断用户是否登录
if request.session.has_key('islogin'):
#用户已经登录
return view_func(request,*view_args,**view_kwargs)
else:
#用户未登录
return redirect('login')
return wrapper
#装饰器
@login_required
#修改密码
def change_pwd(request):
......
14.模板继承
问题:网页中有很多重复出现的内容,比如标题、导航栏等,每个页面都写冗余
解决:模板继承,重复的部分作为父模板,不同的部分在父模板中预留块,子模板继承父模板,重写预留块
【base.html】
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>父模板</title>
</head>
<body>
<div style="background-color: chocolate ;width: 900px;height: 100px">
<h2>导航栏</h2>
</div>
<div style="width: 900px;height: 300px">
{% block main %}
{% block main_left %}
<div style="float: left;width: 300px;height: 300px;background-color: limegreen"> <h5>父模块中左==左==左</h5></div>
{% endblock main_left %}
{% block main_right %}
<div style="float: right;width: 300px;height: 300px;background-color: red"> <h5>父模块中预留块右==右==右</h5></div>
{% endblock main_right %}
{% endblock main %}
</div>
<div style="height: 100px;width: 900px;background-color: darkorchid">
<h4>版权</h4>
</div>
</body>
</html>
【child.html】
{# 模板继承 #}
{% extends 'base.html' %}
{% block main_left %}
{# 显示父模板中内容 #}
{# {{ block.super }}#}
<div style="float: left;width: 200px;height: 200px;background-color: blue">
<h5>child模块中新加的内容</h5>
</div>
{% endblock main_left %}
二、模型
Django 对各种数据库提供了很好的支持,包括:PostgreSQL、MySQL、SQLite、Oracle。Django 为这些数据库提供了统一的调用API。,我们可以根据自己业务需求选择不同的数据库。
Django ORM
对象关系映射(Object Relational Mapping,简称 ORM )用于实现面向对象编程语言里不同类型系统的数据之间的转换。
ORM 在业务逻辑层和数据库层之间充当了桥梁的作用。
ORM 是通过使用描述对象和数据库之间的映射的元数据,将程序中的对象自动持久化到数据库中。通过类和对象就可以对数据表进行操作。
2.1mysql数据库配置
1.首先手动创建数据库(mysql数据库,可以利用数据库图形化软件创建)
2.settings.py 文件中找到 DATABASES 配置项,将其信息修改为:
DATABASES = {
'default':
{
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
'NAME': 'django_db', # 数据库名称
'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址 127.0.0.1
'PORT': 3306, # 端口
'USER': 'root', # 数据库用户名
'PASSWORD': '11111111', # 数据库密码
}
}
3.安装pymysql:pip install pymysql
4.告诉 Django 使用 pymysql 模块连接 mysql 数据库:
#在与 settings.py 同级目录下的 __init__.py 中引入模块和进行配置
import pymysql
pymysql.install_as_MySQLdb()
2.2定义模型
1.定义模型类 myapp1/models.py 文件(模型类==数据库表)
from django.db import models
# Create your models here.
#设计图书模型类,类名代表数据库表名,必须继承Model
class BookInfo(models.Model):
#类里的字段代表数据库表中的字段,
#图书名称,CharField字符串,长度20
title=models.CharField(max_length=20)
#出版日期,DataField日期类型
pub_data=models.DateField()
"""
属性命名限制:
1)不能是python保留关键字
2)不允许使用连续的下划线
3)定义属性时需要指定字段类型,属性名=models.字段类型()
"""
2.模型类生成数据表
terminal命令行中:
> python manage.py migrate # 创建表结构
1)生成迁移文件
> python manage.py makemigrations
2)执行迁移生成表
> python manage.py migrate # 创建表结构
执行后会在应用的migrations中生成迁移文件,数据库生成数据表。数据库表名组成结构为:应用(app)名_模型类名(如:myapp1_bookInfo)
2.3数据库操作
- 添加数据
先创建对象,再执行save()函数
\# 数据库操作
def testdb(request):
test1 = Test(name='runoob')
test1.save()
return HttpResponse("<p>数据添加成功!</p>")
- 获取数据
objects.all() #返回所有 ,返回值是模型类对象
objects.filter(查询条件) # 返回满足条件的数据 返回值是查询集 【模糊查询,范围查询,比较查询,日期查询】
object.exclude(查询条件) #返回不满足条件的数据 返回值是查询集
objects.get(查询条件)#返回一条数据,没有或者多条会抛异常 返回值是查询集
objects.order_by() #排序 返回值是查询集
【Q对象】:用于查询条件之间的逻辑关系,可以对Q对象进行&且,|或 ,~非
##导入Q对象
from django.db.models import Q
#查询id大于3 且 阅读量大于30的图书信息
Book.objects.filter(id__gt=3,read__gt=30)
Book.objects.filter(Q(id__gt=3)&Q(read__gt=30))
#查询id大于3 或 阅读量大于30的图书信息
Book.objects.filter(Q(id__gt=3)|Q(read__gt=30))
#查询id 不等于 5的图书
Book.objects.filter(~Q(id__gt=3))
【F对象】:用于类属性之间的比较
##导入F对象
from django.db.models import F
#查询图书阅读量大于评论量的图书信息
Book.objects.filter(read__gt=F('comment'))
【聚合】sum count avg max min
#导入聚合类
from django.db.models import Sum,Count,Max,Min,Avg
#要调用aggregate()函数来使用聚合,返回值是字典{{'类属性_聚合种类':结果}}
#查询所有图书的数目
Book.objects.aggregate(Count(id))#返回值{{'id_count':5}}
【查询集】
1>惰性查询:只在实际使用时查询
2>缓存:第一次查询结果缓存起来,第二次使用缓存中的数据
3>切片会产生一个查询集
Book.objects.order_by('name')[0:2] # 限制返回的数据 相当于 SQL 中的 OFFSET 0 LIMIT 2;
- 更新数据
save()
update()
- 删除数据
delete()
2.4模型类关系
【一对一关系】关系属性 models.OneToOneField 定义在哪个类中都可以
【一对多关系】关系属性 models.ForeignKey ( ) 定义在多的类
models.py
from django.db import models
# Create your models here.
#设计图书 模型类
class BookInfo(models.Model):
#图书名称,CharField字符串,长度20
title=models.CharField(max_length=20)
#出版日期,DataField日期类型
pub_data=models.DateField()
"""
图书和英雄是一对多的关系,在多的一方建立外键,
"""
#英雄人物 模型类
class HeroInfo(models.Model):
#名称
hname=models.CharField(max_length=10)
#性别,布尔类,default指定默认值
hgender=models.BooleanField(default=False)
#备注
hcomment=models.CharField(max_length=128)
#关系属性 hbook建立图书和英雄人物类之间一对多关系
#数据库表中关系属性的字段名:关系属性名_id,例如:hbook_id
hbook=models.ForeignKey('BookInfo',on_delete=models.DO_NOTHING)
"""on_delete=None, # 删除关联表中的数据时,当前表与其关联的field的行为
on_delete=models.CASCADE, # 删除关联数据,与之关联也删除
on_delete=models.DO_NOTHING, # 删除关联数据,什么也不做
django 升级到2.0之后,表与表之间关联的时候,必须要写on_delete参数,否则会报异常,
由于多对多(ManyToManyField)没有 on_delete 参数,
所以以上只针对外键(ForeignKey)和一对一(OneToOneField)"""
关联查询
#查询id为1的图书关联的英雄信息
b=BookInfo.objects.get(id=1)
heros=b.heroinfo_set.all()
#通过模型类查询
heros=HeroInfo.objects.filter(hbook__id=1)
#查询id为1的英雄关联的图书信息
h=HeroInfo.objects.get(id=1)
books=h.hbook
#通过模型类查询
books=BookInfo.object.filter(heroinfo__id=1)
"""
通过多类条件查询一类数据:
一类名.objects.filter(多类名小写__多类属性名_条件名)
通过一类条件查询多类类数据:
多类名.objects.filter(关联属性名__一类属性名_条件名)
"""
【多对多关系】关系属性 models.ManyToManyField ( ) 定义在哪个类都行
【自关联】特殊的一对多
2.5后台管理
在创建的应用中admin.py是后台管理文件
1)本地化
语言和时区的本地化,修改settings.py
2)创建管理员
命令行:python manage.py createsuperuser ,然后输入用户名,邮箱,密码
启动项目,地址栏http://127.0.0.1:8000/admin 登录
3)注册模型类
在应用下的admin.py中注册模型类,告诉Django框架根据注册的模型生成对应的表管理界面。<1>导入<2>注册
再登录管理界面就能看到BookInfo
4)自定义管理页面
想显示数据表更多的信息,需要自定义管理页面
list_display=[' id ' ]: 页面显示的列内容
list_per_page=10: 每页显示10条数据
list_filter=[ ' ' ]:列表右侧过滤栏
search_fields = [ ' ' ]:列表上方搜索框
三、视图
3.1视图层
一个视图函数,简称视图,是一个简单的 Python 函数,它接受 Web 请求并且返回 Web 响应。响应可以是一个 HTML 页面、一个 404 错误页面、重定向页面、XML 文档、或者一张图片...
无论视图本身包含什么逻辑,都要返回响应。代码写在哪里都可以,只要在 Python 目录下面,一般放在项目的 views.py 文件中。每个视图函数都负责返回一个 HttpResponse 对象,对象中包含生成的响应。
视图层中有两个重要的对象:请求对象(HttpRequest)与响应对象(HttpResponse)。
3.2请求对象: HttpRequest 对象(简称 request 对象)包含浏览器的请求信息
常用的request方法
1.request.GET 保存get方法提交的内容,类型是QueryDict
request.GET.get():返回字符串,如果该键对应有多个值,取出该键的最后一个值
def login_check(request):
#取得请求中的用户名
username=request.GET.get(" username'')
2.request.POST 保存post方法提交的内容,类型是QueryDict
get():返回字符串,如果该键对应有多个值,取出该键的最后一个值
def login_check(request):
#取得请求中的用户名
username=request.POST.get(" username'')
3.request.body
4.request.path 获取 URL 中的路径部分,不包括域名和参数,数据类型是字符串
5.request.method 返回request的请求类型,POST还是GET
3.3 响应对象:HttpResponse 对象
HttpResponse(): 返回文本,参数为字符串,字符串中写文本内容。如果参数为字符串里含有 html 标签,也可以渲染。
def runoob(request):
return HttpResponse("菜鸟教程")
return HttpResponse("<a href='http://https://www.runoob.com/>菜鸟教程</a>")
render(): 返回文本,第一个参数为 request,第二个参数为字符串(页面名称),第三个参数为字典(可选参数,向页面传递的参数:键为页面参数名,值为views参数名)
def runoob(request):
name ="菜鸟教程"
return render(request,"runoob.html",{"name":name})
redirect():重定向,浏览器再发起到另一个页面的请求。参数为字符串,字符串中填写页面路径。一般用于 form 表单提交后,跳转到新页面。
from django.http import HttpResponseRedirect
from django.shortcuts import render, redirect
#到login_check的请求重定向到index
def login_check(request):
#密码正确,重定向到首页index
#return HttpResponseRedirect('/index')
return redirect('/index')#简写形式
3.4 HTTP请求
【GET方法】:提交的参数在url中,可以看到请求内容
获取请求内容:request.GET[' input的name ']
<!--get请求,调用/search方法-->
<form action="/search" method="get">
<input type="text" name="q">
<input type="submit" value="搜索">
</form>
【POST方法】:提交的参数在请求头中
获取请求内容:request.POST[' input标签的name ']
<html>
<head>
<meta charset="utf-8">
<title>学习post方法</title>
</head>
<body>
<!-- post请求,调用search-post方法-->
<form action="/search-post" method="post">
{% csrf_token %}
<input type="text" name="q">
<input type="submit" value="Submit">
</form>
<p>{{ rlt }}</p>
</body>
</html>
表格后面有一个{% csrf_token %}的标签,csrf 全称是 Cross Site Request Forgery,这是Django提供的防止伪装提交请求的功能,POST 方法提交的表格,必须有此标签。 rlt 记号,为表格处理结果预留位置。
四、路由(urls.py )
路由简单的来说就是根据用户请求的 URL 链接来判断对应的处理程序,并返回处理结果,也就是 URL 与 Django 的视图函数建立映射关系。
Django 路由在 urls.py 配置,urls.py 中的每一条配置对应相应的处理方法。
Django 不同版本 urls.py 配置有点不一样:
Django1.1.x 版本
url() 方法:普通路径和正则路径均可使用,需要自己手动添加正则首位限制符号。
from django.conf.urls import url # 用 url 需要引入
urlpatterns = [
url(r'^admin/$', admin.site.urls),
url(r'^index/$', views.index), # 普通路径
url(r'^articles/([0-9]{4})/$', views.articles), # 正则路径
]
Django 2.2.x 之后的版本
-
path:用于普通路径,不需要自己手动添加正则首位限制符号,底层已经添加。
-
re_path:用于正则路径,需要自己手动添加正则首位限制符号。
from django.urls import re_path # 用re_path 需要引入
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index), # 普通路径
re_path(r'^articles/([0-9]{4})/$', views.articles), # 正则路径
]
4.1.正则路径中的分组
正则路径中的无名分组:无名分组按位置传参,一一对应。
正则路径中的有名分组:有名分组按关键字传参,与位置顺序无关。
4.2路由分发
存在问题:Django 项目里多个app目录共用一个 urls 容易造成混淆,后期维护也不方便。
解决:使用路由分发(include),让每个app目录都单独拥有自己的 urls。每当Django遇到时include(),它都会截断直到该处匹配的URL的任何部分,并将剩余的字符串发送到包含的URLconf中以进行进一步处理。
步骤:
-
1、在每个 app 目录里都创建一个 urls.py 文件。
-
2、在项目名称目录下的 urls 文件里,统一将路径分发给各个 app 目录。
**from** django.contrib **import** admin **from** django.urls **import** path,include # 从 django.urls 引入 include urlpatterns = [ path('admin/', admin.site.urls), path("app01/", include("app01.urls")), path("app02/", include("app02.urls")), ]
或者使用path()实例列表包括其他URL模块
myapp1 = [ path('reports/', myapp1_views.report), path('charge/', myapp1_views.charge), ] urlpatterns = [ path('', main_views.homepage), path('myapp1/', include(myapp1)), ] #这样也可以达到共用前缀myapp1,可以避免单个前缀冗余
- 3、在各自 app 目录下,写自己的 urls.py 文件,进行路径跳转。
app01 目录:
from django.urls import path,re_path
from app01 import views # 从自己的 app 目录引入 views
urlpatterns = [
re_path(r'^login/(?P<m>[0-9]{2})/$', views.index, ),
]
app02 目录:
from django.urls import path,re_path
from app02 import views # 从自己的 app 目录引入views
urlpatterns = [
re_path("^xxx/(?P[0-9]{4})/$", views.xxx),
]
- 4、在各自 app 目录下的 views.py 文件中写各自的视图函数。
4.3反向解析
随着功能的增加,路由层的 url 发生变化,就需要去更改对应的视图层和模板层的 url,非常麻烦,不便维护。这时我们可以利用反向解析,当路由层 url 发生改变,在视图层和模板层动态反向解析出更改后的 url,免去修改的操作。反向解析一般用在模板中的超链接及视图中的重定向。
普通路径
-
在 urls.py 中给路由起别名,name="路由别名"。
path("login1/", views.login, name="login")
-
在 views.py 中,从 django.urls 中引入 reverse,利用 reverse("路由别名") 反向解析:
return redirect(reverse("login"))
-
在模板 templates 中的 HTML 文件中,利用 {% url "路由别名" %} 反向解析。
<form action="{% url 'login' %}" method="post">
正则路径(无名分组)
-
在 urls.py 中给路由起别名,name="路由别名"。
re_path(r"^login/([0-9]{2})/$", views.login, name="login")
-
在 views.py 中,从 django.urls 中引入 reverse,利用 reverse("路由别名",args=(符合正则匹配的参数,)) 反向解析。
return redirect(reverse("login",args=(10,)))
-
在模板 templates 中的 HTML 文件中利用 {% url "路由别名" 符合正则匹配的参数 %} 反向解析。
<form action="{% url 'login' 10 %}" method="post">
正则路径(有名分组)
-
在 urls.py 中给路由起别名,name="路由别名"。
re_path(r"^login/(?P<year>[0-9]{4})/$", views.login, name="login")
-
在 views.py 中,从 django.urls 中引入 reverse,利用 reverse("路由别名",kwargs={"分组名":符合正则匹配的参数}) 反向解析。
return redirect(reverse("login",kwargs={"year":3333}))
-
在模板 templates 中的 HTML 文件中,利用 {% url "路由别名" 分组名=符合正则匹配的参数 %} 反向解析。
<form action="{% url 'login' year=3333 %}" method="post">
4.4命名空间
命名空间(英语:Namespace)是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。一个新的命名空间中可定义任何标识符,它们不会与任何重复的标识符发生冲突,因为重复的定义都处于其它命名空间中。
存在问题:路由别名 name 没有作用域,Django 在反向解析 URL 时,会在项目全局顺序搜索,当查找到第一个路由别名 name 指定 URL 时,立即返回。当在不同的 app 目录下的urls 中定义相同的路由别名 name 时,可能会导致 URL 反向解析错误。
解决:使用命名空间。
普通路径
-
定义命名空间(include 里面是一个元组)格式如下:
include(("app名称:urls","app名称"))
实例:项目名称目录下的 urls 文件里,统一将路径分发给各个 app 目录
path("app01/", include(("app01.urls","app01")))
path("app01/", include(("app02.urls","app02")))
-
在 app01/urls.py 中起相同的路由别名。
path("login/", views.login, name="login")
-
在 views.py 中使用名称空间,语法格式如下:
reverse("app名称:路由别名")
实例:
return redirect(reverse("app01:login")
-
在 templates 模板的 HTML 文件中使用名称空间,语法格式如下:
{% url "app名称:路由别名" %}
实例:
<form action="{% url 'app01:login' %}" method="post">
更多url知识:
https://blog.csdn.net/weixin_44870139/article/details/105565242
实例:
实现效果如下图,显示所有图书信息,点击图书展示图书中的英雄人物介绍。
实现步骤分析:
- 新建一个叫做booktest的应用,在settings.py中注册应用。
- 在templates模板文件夹中为booktest建一个文件夹放html,写页面。
- 在models.py中设计图书模型类和英雄模型类,一本书对应多个英雄,迁移生成数据库表,添加信息。
- views.py中定义视图函数,实现功能。
- 在urls.py中配置路由。