1.案例介绍

设计介绍

  • 本示例完成“图书-英雄“信息的维护,需要存储两种数据:图书、英雄
  • 图书表结构设计:
  • 表名:BookInfo
  • 图书名称:btitle
  • 图书发布时间:bpub_date
  • 英雄表结构设计:
  • 表名:HeroInfo
  • 英雄姓名:hname
  • 英雄性别:hgender
  • 英雄简介:hcontent
  • 所属图书:hbook
  • 图书-英雄的关系为一对多

2.数据库配置

数据库配置

  • setting.py文件中,通过DATABASES项进行数据库设置
  • django支持的数据库包括:sqlite、mysql等主流数据库
  • Django默认使用SQLite数据库

创建应用

  • 在一个项目中可以创建一到多个应用,每个应用进行一种业务处理
  • 创建应用的命令:
python manage.py startapp booktest

创建应用后文件目录如图:

django 项目集成prometheus_python

定义数据库模型

定义模型类

  • 有一个数据表,就有一个模型类与之对应
  • 打开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			# 按照提示输入用户名、邮箱、密码

django 项目集成prometheus_hg_02

管理界面本地化

  • 编辑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
                  })