1.案例介绍
设计介绍
- 本示例完成“图书-英雄“信息的维护,需要存储两种数据:图书、英雄
- 图书表结构设计:
- 表名:BookInfo
- 图书名称:btitle
- 图书发布时间:bpub_date
- 英雄表结构设计:
- 表名:HeroInfo
- 英雄姓名:hname
- 英雄性别:hgender
- 英雄简介:hcontent
- 所属图书:hbook
- 图书-英雄的关系为一对多
2.数据库配置
数据库配置
- 在
setting.py
文件中,通过DATABASES项进行数据库设置 - django支持的数据库包括:sqlite、mysql等主流数据库
- Django默认使用SQLite数据库
创建应用
- 在一个项目中可以创建一到多个应用,每个应用进行一种业务处理
- 创建应用的命令:
python manage.py startapp booktest
创建应用后文件目录如图:
定义数据库模型
定义模型类
- 有一个数据表,就有一个模型类与之对应
- 打开
models.py
文件,定义模型类 - 引入包
from django.db import models
- 模型类继承
models.Model
类 - 说明:不需要定义主键列,在生成时会自动添加,并且值为自动增长
- 当输出对象时,会调用对象的str方法
from django.db import models
# Create your models here.
class BookInfo(models.Model):
# 默认会有主键,为id并且自增
# 书籍名称:字符串区域
btitle = models.CharField(max_length=50)
# 书籍的出版日期,相当于datetime.date.today()
bpub_date = models.DateField()
def __str__(self):
return '%s' % (self.btitle)
class HeroInfo(models.Model):
hname = models.CharField(max_length=30)
# 0:男 1:女
hgender = models.BooleanField()
hcontent = models.TextField()
# 如果是Django1.x版本,models.ForeignKey(BookInfo)
# 如果是Django2.x版本,models.ForeignKey(BookInfo)
# models.CASCADE:级联删除,如果书籍删除了,书籍里面的英雄也就删除了
# models.DO_NOTHING:当删除有关联的数据库内容是会报错
# models.SET_NULL:不是级联删除,如果书籍删除,那么英雄所属的书籍为Null
# models.SET_DEFAULT:不是级联删除,如果书籍删除,那么英雄所属的书籍为默认值
hbook = models.ForeignKey(BookInfo, on_delete=models.CASCADE)
def __str__(self):
return '%s' % (self.hname)
生成数据表
- 激活模型:编辑
setting.py
文件,将booktest应用加入到installed_apps中,如图:
- 生成迁移文件:根据模型类生成sql语句
python manage.py makemirgrations
- 执行迁移,执行sql语句生成数据表
python manage.py migrate
测试数据操作
- 进入python shell,进行简单的模型API练习
python manage.py shell
- 进入shell后提示如下:
- 引入需要的包:
from booktest.models import BookInfo,HeroInfo
from django.utils import timezone
from datetime import *
- 传入数据:
- 方法一:
- 方法二:
- 方法一:
- 查询图书信息:
BookInfo.objects.all() # 所有图书信息
BookInfo.objects.first() # 第一条图书信息
BookInfo.objects.get(pk=1) # 按照索引查找图书信息
- 删除图书信息:
b.delete()
- 关联对象的操作
服务器
- 运行如下命令可以开启服务器
python manage.py runserver
- 这是一个纯python编写的轻量级web服务器,仅在开发阶段使用
- 服务器成功启动后,提示如下信息:
- 默认端口是8000,可以修改端口
python manage.py runserver 8080
- 打开浏览器,输入
127.0.0.1:8000
可以打开默认页面 - 如果修改文件不需要重启服务器,如果增删文件需要重启服务器
- 通过ctrl+c停止服务器
后台管理
- 站点分为"内容发布"和"公共访问"两部分
- "内容发布"的部分负责添加、修改、删除内容,开发这些重复的功能是一件单调乏味、缺乏创造力的工作。为此,Django会根据定义的模型类完全自动地生成管理模块
使用django的管理
- 创建一个管理员用户
python manage.py createsuperuser # 按照提示输入用户名、邮箱、密码
管理界面本地化
- 编辑
setting.py
文件,设置编码、时区
LANGUAGE_CODE = 'zh-Hans'
TIME_ZONG = 'Asia/Shanghai'
数据库配置
详细情况可查:数据库配置
- django默认为sqlite3
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
- 配置为mysql数据库
需要在Django0401/Django0401/__init__.py
中添加如下内容:
import pymysql
pymysql.install_as_MySQLdb()
setting.py
中:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'Book',
'USER': 'root',
'PASSWORD': 'redhat',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
向admin注册booktest的模型
- 打开
booktest/admin.py
文件,注册模型
from django.contrib import admin
# Register your models here.
from booktest.models import BookInfo
admin.site.register(BookInfo)
- 刷新管理页面,可以对BookInfo的数据进行增删改查操作
- 问题:如果在str方法中返回中文,再修改和添加时会报ascii的错误
- 解决:在str()方法中,将字符串末尾添加’.encode(‘utf-8’)’
列表页属性(在Django0401/booktest/admin.py中)
- list_display:显示字段,可以点击列头进行排序
- list_fiter:过滤字段,过滤框会出现在右侧
- search_fields:搜索字段,搜索框会出现在上侧
- list_per_page:分页,分页框会出现在下侧
添加、修改页属性(在Django0401/booktest/admin.py中)
- fields:属性的先后顺序
- fieldset:属性分组
关联对象
- 对于HeroInfo模型类,有两种注册方式
- 方式一:与BookInfo模型类相同
- 方式二:关联注册
- 按照BookInfo的注册方式完成HeroInfo的注册
- 接下来实现关联注册
from django.contrib import admin
# Register your models here.
# admin设置该APP后台管理的文件
from booktest.models import BookInfo, HeroInfo
class HeroInfoAdmin(admin.ModelAdmin):
list_display = ['hname', 'hgender', 'hbook', 'hcontent']
list_filter = ['hbook', 'hgender']
search_fields = ['hname', 'hcontent']
list_per_page = 5
# 添加英雄时需要设置的属性及先后顺序
# fields = ['hname','hcontent', 'hgender']
# 添加分组
fieldsets = [
('必填内容', {'fields': ['hname', 'hbook']}),
('选填内容', {'fields': ['hgender', 'hcontent']})
]
# 创建书籍是内嵌的显示设置,这里是表格的内联
class HeroInfoInline(admin.TabularInline):
model = HeroInfo
extra = 2
class BookInfoAdmin(admin.ModelAdmin):
inlines = [HeroInfoInline]
# 修改站点的头部信息和标题
admin.site.site_header = "个人博客系统管理"
admin.site.site_title = "博客"
admin.site.register(BookInfo, BookInfoAdmin)
admin.site.register(HeroInfo, HeroInfoAdmin)
布尔值的显示
- 发布性别的显示不是一个直观的结果,可以使用方法进行封装
models.py
中:
from django.utils.html import format_html
def gender(self):
if self.hgender: # hgender=1
# 设置性别字段的颜色;
return format_html('<span style="color:red">女</span>')
else:
return format_html('<span style="color:green">男</span>')
gender.short_description = '性别'
admin.py
中:
list_display = ['hname', 'gender', 'hbook', 'hcontent']
URL设置
在Django0401/Django0401/urls.py
中:
from django.contrib import admin
from django.urls import path, re_path
from booktest.views import index, detail
urlpatterns = [
path('admin/', admin.site.urls),
path('index/',index),
# 命名匹配,Django2.X才有这种匹配方式
# int, str, path, slug, uuid
path('detail/<int:id>',detail),
# 使用正则表达式,Django2.X版本的用法
re_path('de/(?P<id>\d+)/',detail)
]
视图函数
from django.http import HttpResponse
from django.shortcuts import render
# render_template
from booktest.models import BookInfo, HeroInfo
# Create your views here.
# Flask默认有request对象,存储请求的所有信息
# Django里面,所有的视图函数,必须传一个参数(request对象)
def index(request):
# 主页希望显示所有的图书信息
books = BookInfo.objects.all()
# return HttpResponse(books) # 如何返回字符串
return render(request, 'booktest/index.html',
context={
'books': books
})
# /detail/1/
# /detail/2/
def detail(request, id):
b = BookInfo.objects.get(id=id)
heros = b.heroinfo_set.all()
# return HttpResponse("detail %s" %(id))
return render(request, 'booktest/detail.html',
context={
'heros': heros,
'book': b
})