Django 入门范例
1. Django 介绍
2. Django 环境搭建
3. 模型(Model)
4. 站点管理
5. 视图(View)
6. 模板(Template)
1. Django 介绍
MVC 模型
- 大部分开发语言中都有 MVC 开发模型。
- MVC 框架的核心思想是:解耦——降低各功能模块之间的耦合性,方便变更,更容易重构代码,最大程度上实现代码的重用。
- M 表示 Model,主要用于对数据库层的封装。
- V 表示 View,用于向用户展示结果。
- C 表示 Controller,是核心,用于处理请求、获取数据、返回结果。
MVT 模型
- Django 是一款 python 的 web 开发框架。
- 与 MVC 有所不同,属于 MVT 框架。
- M 表示 Model,负责与数据库交互。
- V 表示 View,是核心,负责接收请求、获取数据、返回结果。
- T 表示 Template,负责呈现内容到浏览器。
Django 开发流程范例
- 安装配置 Django 的运行环境。
- 创建项目、创建应用。
- 在应用的 model.py 定义模型类,执行迁移,生成对应的数据表(可使用简单 API 与数据库交互测试)。
- 使用 Django 的后台管理界面维护数据。
- 在应用的 views.py 定义视图,即处理核心逻辑的函数。
- 在项目目录下创建对应应用的模板目录,编写 html 页面。
- 在项目和应用的 urls.py 中配置 URL 与视图的映射。
- 通过视图接收指定 URL 的访问请求,通过模型操作数据,通过模板填充数据并完成页面展示。
2. Django 环境搭建
1)安装 Django
1.8.2 版本是一个稳定性高、使用广、文档多的版本:
pip.exe install django==1.8.2
进入 python shell,查看版本:
>>> import django >>> django.get_version() '1.8.2'
2)创建工程项目
执行如下命令:自定义项目名称并创建基本的工程目录
E:\>django-admin startproject DjangoDemo
项目名称 DjangoDemo 中的目录说明
- manage.py:一个命令行工具,可以使你用多种方式对 Django 项目进行交互。
- DjangoDemo:与我们命名的项目名称一致,真正的本项目 python 包。
- _init _.py:一个空文件,它告诉 python 这个目录应该被看做一个 python 包。
- settings.py:项目的配置。
- urls.py:项目的 url 声明。
- wsgi.py:项目与 wsgi 兼容的 web 服务器入口。
3)创建应用
在一个项目中可以创建一到多个应用,一个应用专门处理一种业务。
在项目根目录下,执行创建应用的命令:
python manage.py startapp hero_book
应用的目录结构如下图:
- migrations 包:根据模型类生成 SQL 语句,并作用到对应的数据库。
- admin.py:对本应用进行相关的管理。
- models.py:定义模型类(有多少个数据表,就有多少个模型类与之对应)。
- tests.py:Django 自带的测试模块。
- views.py:定义视图相关函数。
将创建的应用配置进项目的 settings.py 中:(当不需要迁移时则可不做此步配置)
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'hero_book' # 新增的应用 )
3. 模型(Model)
设计介绍
本示例完成“图书-英雄”两种信息的维护。“图书”、“英雄”的关系为一对多。
“图书”表结构设计:
- 表名:BookInfo
- 图书名称:btitle
- 图书发布时间:bpub_date
“英雄”表结构设计:
- 表名:HeroInfo
- 英雄姓名:hname
- 英雄性别:hgender
- 英雄简介:hcontent
- 所属图书:hbook
数据库配置
- 在 settings.py 文件中,通过 DATABASES 项进行数据库设置。
- Django 支持的数据库包括 SQLite、MySQL 等主流数据库。
- Django 默认使用自带的 SQLite 数据库。
定义模型类
步骤如下:
- 打开应用的 models.py 文件
- 引入包 from django.db import models
- 模型类继承 models.Model 类
- 说明:不需要定义主键列,在生成时会自动添加,并且值为自动增长
- 当输出对象时,会调用对象的 str 方法
1 from django.db import models 2 3 # 声明表名 4 class BookInfo(models.Model): 5 # 声明表字段 6 book_title = models.CharField(max_length=20) # 字符串类型且限定数据长度 7 book_public_date = models.DateTimeField() # 时间类型 8 9 def __str__(self): 10 return "%d" % self.pk # 返回主键列的值 11 12 13 class HeroInfo(models.Model): 14 15 name = models.CharField(max_length=20) 16 gender = models.BooleanField() # 布尔类型 17 content = models.CharField(max_length=100) 18 Book = models.ForeignKey('BookInfo') # 主/外键关联(BookInfo 加不加引号都行) 19 20 def __str__(self): 21 return "%d" % self.pk
迁移:生成数据表
1)激活模型:编辑 settings.py 文件,将 hero_book 应用加入到 installed_apps 中
2)生成迁移文件:根据模型类生成表结构的相关 sql 脚本(记录关于 models.py 的所有改动,但是还没有作用到数据库中)
python manage.py makemigrations
迁移文件被生成到应用的 migrations 目录,迁移文件中就是模型定义的对应 sql 脚本。
3)执行迁移:即执行 sql 脚本,生成数据表(将 models.py 的所有改动作用到数据库中)
python manage.py migrate
数据操作测试
进入 python shell,进行简单的模型 API 练习:
python manage.py shell
操作“图书”对象
# 引入需要的包 >>> from booktest.models import BookInfo,HeroInfo >>> from django.utils import timezone >>> from datetime import * # 查询所有图书数据 >>> BookInfo.objects.all() [] # 新建图书数据 >>> b = BookInfo() # 映射表名 >>> b.book_title = "射雕英雄传" # 映射表字段 >>> b.book_public_date = datetime(year=1990, month=1, day=10) >>> b.save() # 查找图书数据 >>> b = BookInfo.objects.get(pk=1) # 根据主键查找 # 输出图书数据 >>> b <BookInfo: 1> >>> b.id 1 >>> b.book_title '射雕英雄传' # 修改图书数据 >>> b.book_title = "天龙八部" >>> b.save() # 删除图书数据 >>> b.delete()
操作“英雄”对象:关联对象的操作
- 对于 HeroInfo 可以按照上面的操作方式进行。
- 注意添加关联对象(图书)。
>>> h = HeroInfo() >>> h.name = "郭靖" >>> h.gender = True >>> h.content = "降龙十八掌" >>> h.Book = b >>> h.save() # 获得关联集合:返回当前BookInfo对象的所有HeroInfo对象 >>> b.heroinfo_set.all() [<HeroInfo: 1>] # 有一个HeroInfo对象存在,就必须对应一个BookInfo对象 # 另一种创建关联的方式 >>> h = b.heroinfo_set.create(name="黄蓉", gender=False, content="打狗棒法") >>> h <HeroInfo: 2> >>> h.name '黄蓉'
4. 站点管理
1)服务器启停
运行如下命令可以开启服务器:
python manage.py runserver ip:port
修改端口:
python manage.py runserver 8080
- 可以不写 ip,默认端口为 8000。
- 这是一个纯 python 编写的轻量级 web 服务器,仅在开发阶段使用。
- 服务器成功启动后,提示如下信息:
E:\DjangoDemo>python manage.py runserver Performing system checks... System check identified no issues (0 silenced). March 31, 2021 - 21:23:43 Django version 1.8.2, using settings 'DjangoDemo.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CTRL-BREAK.
- 打开浏览器,输入网址“127.0.0.1:8000”可以打开默认页面。
- 修改文件后不需要重启服务器;如果是增删文件则需要重启服务器。
- 通过 ctrl+c 停止服务器。
2)管理操作
- 站点分为“内容发布”和“公共访问”两部分。
- “内容发布”的部分负责添加、修改、删除内容,开发这些重复的功能是一件单调乏味、缺乏创造力的工作。为此,Django 会根据定义的模型类完全自动地生成管理模块。
使用 django 的管理
- 执行以下命令创建一个管理员用户,按提示输入用户名、密码、邮件:
python manage.py createsuperuser
- 启动服务器,通过“127.0.0.1:8000/admin”访问,输入上面创建的用户名、密码完成登录;
- 进入管理站点,默认可以对 groups、users 进行管理。
管理界面本地化
- 编辑 settings.py 文件,设置中文编码和中国时区
LANGUAGE_CODE = 'zh-Hans' TIME_ZONE = 'Asia/Shanghai'
向 admin 注册 hero_info 的相关模型
- 打开 hero_book/admin.py 文件,注册模型
from django.contrib import admin from models import BookInfo admin.site.register(BookInfo) admin.site.register(HeroInfo)
- 刷新管理页面,可以对 BookInfo 的数据进行增删改查操作。
- 问题:如果要在 str() 方法中返回中文,在修改和添加时会报 ascii 的错误。
- 解决:在 str() 方法中,将字符串末尾添加“.encode('utf-8')”。
自定义管理页面
- Django 提供了 admin.ModelAdmin 类。
- 通过自定义 ModelAdmin 的子类,来定义模型在站点管理界面的显示方式。
列表页的相关属性
1 from django.contrib import admin 2 from .models import * 3 4 5 # 自定义ModelAdmin的子类,定义BookInfo模型在站点管理界面的显示方式 6 class BookInfoAdmin(admin.ModelAdmin): 7 list_display = ['pk', 'book_title', 'book_public_date'] # list_display:显示字段,可以点击列头进行排序 8 list_filter = ['book_title'] # list_filter:过滤字段,过滤框会出现在右侧 9 search_fields = ['book_title'] # search_fields:搜索字段,搜索框会出现在上侧 10 list_per_page = 10 # list_per_page:分页,分页框会出现在下侧 11 12 13 admin.site.register(BookInfo, BookInfoAdmin) # 将ModelAdmin子类与对应的模型类放一起 14 admin.site.register(HeroInfo)
界面效果:
添加/修改页的相关属性
1 from django.contrib import admin 2 from .models import * 3 4 5 # 自定义ModelAdmin的子类,定义BookInfo模型在站点管理界面的显示方式 6 class BookInfoAdmin(admin.ModelAdmin): 7 8 '''列表页属性''' 9 list_display = ['pk', 'book_title', 'book_public_date'] # list_display:显示字段,可以点击列头进行排序 10 list_filter = ['book_title'] # list_filter:过滤字段,过滤框会出现在右侧 11 search_fields = ['book_title'] # search_fields:搜索字段,搜索框会出现在上侧 12 list_per_page = 10 # list_per_page:分页,分页框会出现在下侧 13 14 '''添加、修改页属性''' 15 # fields:属性的先后顺序 16 # fields = ['book_public_date', 'book_title'] 17 # fieldsets:属性分组 18 fieldsets = [ 19 ('basic', {'fields': ['book_title']}), 20 ('more', {'fields': ['book_public_date']}), 21 ] 22 23 24 admin.site.register(BookInfo, BookInfoAdmin) # 将ModelAdmin子类与对应的模型类放一起 25 admin.site.register(HeroInfo)
页面效果:
3)关联对象
对于 HeroInfo 模型类,有两种注册方式:
- 方式一:与 BookInfo 模型类相同的注册方式
- 方式二:关联注册
接下来实现关联注册
1 from django.contrib import admin 2 from .models import * 3 4 5 # 自定义admin.StackedInline的子类,实现关联对象的注册 6 class HeroInfoInline(admin.StackedInline): 7 model = HeroInfo 8 extra = 2 9 10 11 # 自定义ModelAdmin的子类,定义BookInfo模型在站点管理界面的显示方式 12 class BookInfoAdmin(admin.ModelAdmin): 13 14 '''列表页的相关属性''' 15 list_display = ['pk', 'book_title', 'book_public_date'] # list_display:显示字段,可以点击列头进行排序 16 list_filter = ['book_title'] # list_filter:过滤字段,过滤框会出现在右侧 17 search_fields = ['book_title'] # search_fields:搜索字段,搜索框会出现在上侧 18 list_per_page = 10 # list_per_page:分页,分页框会出现在下侧 19 20 '''添加/修改页的相关属性''' 21 # fields:属性的先后顺序 22 # fields = ['book_public_date', 'book_title'] 23 # fieldsets:属性分组 24 fieldsets = [ 25 ('basic', {'fields': ['book_title']}), 26 ('more', {'fields': ['book_public_date']}), 27 ] 28 29 '''实现关联对象的方式二''' 30 inlines = [HeroInfoInline] 31 32 33 admin.site.register(BookInfo, BookInfoAdmin) # 将ModelAdmin子类与对应的模型类放一起 34 # admin.site.register(HeroInfo) # 实现关联对象的方式一
还可以将内嵌的方式改为表格,只需替换继承的父类:
class HeroInfoInline(admin.TabularInline)
4)布尔值的显示
发布性别的显示不是一个直观的结果,可以使用方法进行封装:
1 def gender(self): 2 if self.hgender: 3 return '男' 4 else: 5 return '女' 6 7 gender.short_description = '性别'
在 admin 注册中使用函数名 gender 代替类属性 gender:
class HeroInfoAdmin(admin.ModelAdmin): list_display = ['id', 'name', 'gender', 'content']
5. 视图(View)
views.py
- 在 Django 中,视图负责对 web 请求进行回应。
- 视图接收 reqeust 对象作为第一个参数,该参数包含了请求的信息。
- 视图就是一个 python 函数,被定义在 views.py 中。
1 from django.http import HttpResponse # 引入响应对象 2 3 # 定义访问主页时的响应 4 def index(request): # 视图函数的第一个参数必须是request(请求)对象 5 return HttpResponse("welcome index page!") # 视图函数返回的必须是HttpResponse(响应)对象或其子类 6 7 # 定义访问详情页时的响应 8 def detail(request, id): 9 return HttpResponse("detail:%s" % id)
定义完成视图后,需要配置 URLconf,否则无法处理请求。
URLconf
- 在 Django 中,定义 URLconf 包括两方面内容:配置正则表达式和视图。
- Django 使用正则表达式匹配请求 URL,一旦匹配成功,则调用对应的视图。
- 注意:只匹配路径部分,即除去域名、参数后的字符串。
- 在 DjangoDemo/urls.py 中新增 hero_book.urls,使主 URLconf 连接到 hero_book.urls 模块。
注意:django 2.0 起,urls 不支持正则表达式问题。如果需要使用正则,需要导入 re_path,使用方法如下:
from django.urls import path, re_path urlpatterns = [ path('admin/', admin.site.urls), re_path(r'^test-(\d+)-(\d+)/', views.test), path('index/', views.index), ]
示例
DjangoDemo/urls.py:
urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^', include('hero_book.urls')), # 关联hero_book包下的urls模块 ]
hero_book/urls.py:
1 from django.conf.urls import url 2 from . import views 3 4 5 urlpatterns = [ 6 url(r'^$', views.index), # URI不带多余字符时访问index函数 7 url(r'^book/([0-9]+)/$', views.detail), # URI带数字时访问detail函数 8 ]
页面效果
6. 模板(Template)
模板其实就是 html 页面,可以根据视图中传递的数据填充值。
(实际上,文件扩展名并不一定要是 html。只要文件中是 html 的内容,使用其他文件扩展名也可。)
创建模板目录
1)在项目目录下创建模板的目录,如下图:
为了清晰起见,一个模板目录对应一个应用,存放该应用的所有页面。
2)修改应用的 settings.py 文件,设置 TEMPLATES 的 DIRS 值:
'DIRS': [os.path.join(BASE_DIR, "templates")], # 关联到项目目录下的templates目录(BASE_DIR是setings.py中已定义好的变量)
定义模板
在模板中访问视图传递的数据的方式:
{{输出值,可以是变量,也可以是对象.属性}}
{%执行代码段%}
index.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>首页</title> 6 </head> 7 <body> 8 <h1>图书列表</h1> 9 <ul> 10 {%for book in booklist%} 11 <li> 12 <a href="book/{{book.id}}">{{book.book_title}}</a> 13 </li> 14 {%endfor%} 15 </ul> 16 </body> 17 </html>
detail.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>详情页</title> 6 </head> 7 <body> 8 <h1>编号:{{book.id}}</h1> 9 <ul> 10 {%for hero in book.heroinfo_set.all%} 11 <li>{{hero.name}}——{{hero.content}}</li> 12 {%endfor%} 13 </ul> 14 </body> 15 </html>
使用模板
编辑 views.py,在方法中调用对应的模板:
1 from django.shortcuts import render 2 from .models import BookInfo 3 4 # 首页 5 def index(request): 6 # 获取所有BookInfo对象 7 booklist = BookInfo.objects.all() 8 # render 参数2:指定模板文件;参数3:将booklist对象列表传递给模板页面中引用 9 return render(request, 'hero_book/index.html', {'booklist': booklist}) 10 11 # 详情页 12 def detail(request, id): 13 # 将url正则中的分组作为主键,获取对应的BookInfo对象 14 book = BookInfo.objects.get(pk=id) 15 return render(request, 'hero_book/detail.html', {'book': book})
页面效果