接上篇:Django入门-项目创建与初识子应用
这里我们先使用sqlite类型的数据库,后面在进行改变
名词:
ORM(Object Ralational Mapping,对象关系映射)用来把对象模型表示的对象映射到基于S Q L 的关系模型数据库结构中去。
这样,我们在具体的操作实体对象的时候,就不需要再去和复杂的 SQ L 语句打交道,只需简单的操作实体对象的属性和方法。
一对多关系:外键写在多的一端
book:hero = 1:n
本示例完成“图书-英雄”信息的维护,需要存储两种数据:图书、英雄
图书表结构设计: 表名: Book
图书名称: title
图书发布时间: pub_date
英雄表结构设计: 表名: Hero
英雄姓名: name
英雄性别: gender
英雄简介: hcontent
所属图书: hbook
图书-英雄的关系为一对多
# bookApp/models.py
from django.db import models
"""
名词:
ORM(Object Ralational Mapping,对象关系映射)用来把对象模型表示的对象映射到基于S Q L 的关系模型数据库结构中去。
这样,我们在具体的操作实体对象的时候,就不需要再去和复杂的 SQ L 语句打交道,只需简单的操作实体对象的属性和方法。
一对多关系:外键写在多的一端
book:hero = 1:n
"""
# Create your models here.
# 类对应数据库表, 表名称默认为bookApp_book.
class Book(models.Model):
# 属性对应数据库表的列名,默认会添加id这一列。
name = models.CharField(max_length=40, verbose_name="书籍名称")
pub_date = models.DateField(verbose_name="出版日期")
# 魔术方法,字符串友好展示, 便于调试代码
def __str__(self):
return self.name
class Meta:
# 单数时显示的名称
verbose_name = "图书管理"
# 复数时显示的名称
verbose_name_plural = verbose_name
"""
更多查询操作请参考网址: https://docs.djangoproject.com/zh-hans/3.1/topics/db/queries/
"""
# 类对应数据库表, 表名称默认为bookApp_hero.
class Hero(models.Model):
# 属性对应数据库表的列名,默认会添加id这一列。
gender_choice = [
(1, "男"),
(2, "女")
]
name = models.CharField(max_length=20, verbose_name="人物名称")
# 性别只能选择男(1)或者女(2)
gender = models.IntegerField(choices=gender_choice, verbose_name="性别") # 1, 2
content = models.TextField(max_length=1000, verbose_name="人物描述")
# 外键关联, 如果删除书籍时,相关hero对应的书籍设置为空。
book_id = models.ForeignKey(Book, on_delete=models.SET_NULL,null=True, verbose_name="书籍id")
def __str__(self):
return self.name
# Meta选项的更多使用请参考网址: https://docs.djangoproject.com/zh-hans/3.1/ref/models/options/
class Meta:
# 单数时显示的名称
verbose_name = "人物管理"
# 复数时显示的名称
verbose_name_plural = verbose_name
激活模型:编辑 settings.py 文件,将应用加入到 INSTALLED_APPS 中
python manage.py makemigrations
python manage.py migrate
python manage.py shell
from bookApp.models import Hero, Book
Book.objects.all()
>>> from datetime import date
>>> b1 = Book()
>>> b1.name = "西游记"
>>> d1 = date(2000,1,1)
>>> b1.pub_date = d1
>>> b1.save()
>>> Book.objects.all()
>>> b2 = Book(name="红楼梦",pub_date=date(1784, 2, 1))
>>> b2.save()
>>> Book.objects.all()
<QuerySet [<Book: 西游记>, <Book: 红楼梦>]>
>>> b1 = Book.objects.filter(name="西游记").first()
>>> b1
<Book: 西游记>
>>> b1.pub_date
datetime.date(2000, 1, 1)
>>> b1.delete()
>>> # 书籍的创建
>>> book = Book(name="倚天屠龙记",pub_date=date(2000,1,1))
>>> book.save()
>>> # 人物的创建
>>> hero1 = Hero(name="周芷若", gender=2,content="info....")
>>> hero1.save()
>>> hero1.book_id = book
>>> hero1.book_id
<Book: 倚天屠龙记>
book.hero_set.all()
>>> books = Book.objects.filter(name__contains="红")
>>> books
<QuerySet [<Book: 红楼梦>]>
打开 bookApp/admin.py 文件,注册模型
from django.contrib import admin
from bookApp.models import Book,Hero
# 自定义后台站点管理的拓展阅读: https://docs.djangoproject.com/zh-hans/3.1/ref/contrib/admin/
# Register your models here.
admin.site.register([Book,Hero])
# bookApp/models.py
class Meta:
# 单数时显示的名称
verbose_name = "图书管理"
# 复数时显示的名称
verbose_name_plural = verbose_name
from django.contrib import admin
from bookApp.models import Book,Hero
# 自定义后台站点管理的拓展阅读: https://docs.djangoproject.com/zh-hans/3.1/ref/contrib/admin/
# Register your models here.
class HeroInline(admin.StackedInline):
model = Hero
extra = 3
class BookAdmin(admin.ModelAdmin):
# 列表页展示的设置
list_display = ['id', 'name', 'pub_date']
list_filter = ['pub_date']
search_fields = ['name']
list_display_links = ['name']
list_per_page = 5
inlines = [HeroInline]
class HeroAdmin(admin.ModelAdmin):
# 列表页展示的设置
list_display = ['id', 'name', 'gender']
list_filter = ['gender']
search_fields = ['name', 'content']
list_display_links = ['name']
list_per_page = 5
# 增加和编辑页的设置
fieldsets = [('必填信息', {'fields': ['name', 'book_id']}),
('选填信息', {'fields': ['gender', 'content']}), ]
admin.site.register(Book, BookAdmin)
admin.site.register(Hero, HeroAdmin)
最终效果展示
list_display:显示字段,可以点击列头进行排序
list_filter:过滤字段,过滤框会出现在右侧
search_fields:搜索字段,搜索框会出现在上侧
list_per_page:分页,分页框会出现在下侧
fields:属性的先后顺序
fieldsets :属性分组, 注意: fields和fieldsets 只能设置一个.
fieldsets = [('必填信息', {'fields': ['name', 'book_id']}),
('选填信息', {'fields': ['gender', 'content']}), ]
对于 Hero 模型类,有两种注册方式
class HeroInline(admin.StackedInline):
model = Hero
extra = 3
class BookAdmin(admin.ModelAdmin):
list_display = ['pk', 'title', 'pub_date']
# .......此处省略部分重复代码
inlines = [HeroInline]
主配置文件配置如下, 已经配置过, 可以忽略此步骤:
# BookManage/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
# 当用户访问的url地址以book开头, 请访问bookApp.urls这个url配置文件进行匹配并执行对应
的视图函数.
path('book/', include('bookApp.urls')),
]
bookApp 子应用的子配置文件如下:
# bookApp/urls.py
urlpatterns = [
# 当用户访问bookApp应用的主页时, 执行视图函数index,反向根据名称获取url地址;
path(r'', views.index, name='index'),
# 显示书籍的详情页, 接收一个int值并赋值给id
path(r'/' , views.detail, name='detail'),
]
# bookApp/views.py
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
return HttpResponse("图书管理系统")
访问http://127.0.0.1/book查看效果
编辑 views.py 文件,在方法中调用模板 :
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
from bookApp.models import Book
# 视图:对用户的请求(request)进行业务逻辑操作,最总返回给用户响应(reponse)
def index(request):
books = Book.objects.all()
#print("用户请求的路径:",request.path)
#return HttpResponse(books)
# 渲染:将上下文context{'books':books}填充到book/index.html代码中
return render(request,'book/index.html',{'books':books})
def detail(request, id):
"""书籍详情页信息"""
book = Book.objects.filter(id=id).first()
heros = book.hero_set.all()
return render(request, 'book/detail.html',
{'book': book, 'heros': heros})
等待模板的代码完善后, 再进行测试。
第三步: 模板管理实现好看的HTML页面
作为Web 框架, Django 需要一种很便利的方法以动态地生成HTML。最常见的做法是使用模板。
模板包含所需HTML 输出的静态部分,以及一些特殊的语法,描述如何将动态内容插入。
(1) 模板引擎配置
创建模板的目录如下图:
# index.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 style="color:red">图书管理系统</h1>
</body>
</html>
再次访问测试
这里我们不能只是出现一个名字。我们要出现数据列表
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 style="color:red">图书管理系统</h1>
<ul>
{% for book in books %}
<li>{{ book.name }}</li>
{% endfor %}
</ul>
</body>
</html>
(2) 模板语法: 变量
变量输出语法
{ { var } }
当模版引擎遇到一个变量,将计算这个变量,然后将结果输出。
变量名必须由字母、数字、下划线(不能以下划线开头)和点组成。
当模版引擎遇到点("."),会按照下列顺序查询:
(3) 模板语法: 常用标签
语法
{ % tag % }
作用
for标签
{% for ... in ... %}
循环逻辑
{% endfor %}
if标签
{% if ... %}
逻辑1
{% elif ... %}
逻辑2
{% else %}
逻辑3
{% endif %}
comment标签
{% comment %}
多行注释
{% endcomment %}
include标签
加载模板并以标签内的参数渲染
{% include "base/left.html" %}
url :反向解析
{% url 'name' p1 p2 %}
csrf_token 标签
用于跨站请求伪造保护
{% csrf_token %}
(4) 主页与详情页前端HTML设计
定义 index.html 模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 style="color: blueviolet">图书管理系统</h1>
<ul>
{% for book in books %}
<li><a href="/book/{{ book.id }}/">{{ book.name }}</a></li>
{% endfor %}
</ul>
</body>
</html>
定义 detail.html 模板
在模板中访问对象成员时,都以属性的方式访问,即方法也不能加括号
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{book.name}}</h1>
<h1>{{book.pub_date}}</h1>
<h1>{{heros}}</h1>
</body>
</html>
访问下面的链接, 测试运行是否成功:
http://127.0.0.1:8000/book/
wsgi : 封装请求后交给后端的web框架( Flask、Django )。
请求中间件: 对请求进行校验或在请求对象中添加其他相关数据,例如: csrf、
request.session 。
路由匹配: 根据浏览器发送的不同 url 去匹配不同的视图函数。
视图函数: 在视图函数中进行业务逻辑的处理,可能涉及到: ORM、Templates 。
响应中间件: 对响应的数据进行处理。
wsgi : 将响应的内容发送给浏览器。
本系统基本功能已经完成, 前端页面可以搜索好看的 html 进行替换。
安装配置 django 运行的环境
编写模型,使用简单 API 与数据库交互
使用 Django 的后台管理中维护数据
通过 视图 接收请求,通过模型获取数据,展示出来
调用模板完成展示