一、目标及业务流程
期望效果:
业务流程:
- 用户登录
- 预定会议室
- 退订会议室
- 选择日期;今日以及以后日期
二、表结构设计和生成
1、models.py(用户继承AbstractUser)
from django.db import models # Create your models here. from django.db import models from django.contrib.auth.models import AbstractUser class UserInfo(AbstractUser): """用户信息表""" tel = models.CharField(max_length=32) class Room(models.Model): """会议室表""" caption = models.CharField(max_length=32) # 会议室名字 num = models.IntegerField() # 会议室容纳人数 def __str__(self): return self.caption class Book(models.Model): """会议室预订信息""" user = models.ForeignKey("UserInfo", on_delete=models.CASCADE) # CASCADE级联删除 room = models.ForeignKey("Room", on_delete=models.CASCADE) date = models.DateField() # 日期 time_choices = ( # 时段 (1, '8:00'), (2, '9:00'), (3, '10:00'), (4, '11:00'), (5, '12:00'), (6, '13:00'), (7, '14:00'), (8, '15:00'), (9, '16:00'), (10, '17:00'), (11, '18:00'), (12, '19:00'), (13, '20:00'), ) time_id = models.IntegerField(choices=time_choices) # 存数字,choices参数 class Meta: unique_together = ( # 三个联合唯一,防止有人重复预定 ('room', 'date', 'time_id'), ) def __str__(self): return str(self.user) + "预定了" + str(self.room)
注意:
(1)Django中提供了AbstractUser类,可以用来自由定制需要的model
from django.contrib.auth.models import AbstractUser class UserInfo(AbstractUser): """用户信息表""" tel = models.CharField(max_length=32)
如上所示,即可在Django的基础上添加我们所需要的信息。
(2)设置model的时候,设置三个字段联合唯一
class Book(models.Model): """会议室预订信息""" .... class Meta: unique_together = ( # 三个联合唯一,防止有人重复预定 ('room', 'date', 'time_id'), )
存的是key 显示的是value,且只能存key。
2、修改配置文件settings.py,覆盖默认的User模型
Django允许你通过修改setting.py文件中的 AUTH_USER_MODEL 设置覆盖默认的User模型,其值引用一个自定义的模型。
AUTH_USER_MODEL = "app01.UserInfo"
上面的值表示Django应用的名称(必须位于INSTALLLED_APPS中)和你想使用的User模型的名称。
注意:在创建任何迁移或者第一次运行 manager.py migrate 前设置 AUTH_USER_MODEL。
设置AUTH_USER_MODEL数据库结构有很大的影响。改变了一些会使用到的表格,并且会影响到一些外键和多对多关系的构造。在你有表格被创建后更改此设置是不被 makemigrations 支持的,并且会导致你需要手动修改数据库结构,从旧用户表中导出数据,可能重新应用一些迁移。
3、数据迁移及创建超级用户
$ python3 manage.py makemigrations $ python3 manage.py migrate
这里遇到了一个问题:创建项目时没有创建应用,手动通过manage.py startapp user创建子项目,修改AUTH_USER_MODEL后执行makemigrations一直报错,找不到app01。
创建两个超级用户:
MacBook-Pro:MRBS hqs$ python3 manage.py createsuperuser Username: yuan Password:yuan1234 MacBook-Pro:MRBS hqs$ python3 manage.py createsuperuser Username: alex Password:alex1234
三、系统登录login
urls.py:
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.login), path('index/', views.index), path('book/', views.book), ]
简单login.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="" method="post"> 用户名:<input type="text" name="user"> 密码:<input type="password" name="pwd"> <input type="submit"> </form> </body> </html>
login视图函数:
from django.shortcuts import render, redirect # Create your views here. from django.contrib import auth def login(request): if request.method == "POST": user = request.POST.get("user") pwd = request.POST.get("pwd") user = auth.authenticate(username=user, password=pwd) if user: # 登录成功 auth.login(request, user) # 注册request.user,可以拿到登录用户对象所有信息 redirect("/index/") return render(request, "login.html")
注意:auth模块的authenticate()方法,提供了用户认证,如果认证信息有效,会返回一个 User 对象;如果认证失败,则返回None。
四、index部分
1、引入admin组件(后台数据管理组件)并完成admin注册
admin.py:
from django.contrib import admin # Register your models here. from app01.models import * admin.site.register(UserInfo) admin.site.register(Book) admin.site.register(Room)
2、在数据库添加数据
3、index视图函数数据处理和index.html模板渲染
注意:
(1)数据处理还是在后台更加方便,前台渲染后台传递来的标签字符串
<table class="table table-bordered table-striped"> <thead> <tr> <th>会议室时间</th> {% for time_choice in time_choices %} {# 在元组中取第二个值 #} <th>{{ time_choice.1 }}</th> {% endfor %} </tr> </thead> <tbody> {# 由于模板语法功能不够强大,因此数据处理还是放在后台,在这里渲染后台传递来的标签字符串 #} {{ htmls|safe }} </tbody> </table>
由于模板语法功能不够强大,因此数据处理还是放在后台,在这里渲染后台传递来的标签字符串。
(2)视图函数字符串处理,运用format格式化函数
def index(request): # 拿到预定表中的时间段 time_choices = Book.time_choices # 拿到所有的会议室 room_list = Room.objects.all() # 构建标签 htmls = "" for room in room_list: # 第一列td完成后,还有其他td标签需要添加,因此此处没有闭合tr htmls += "<tr><td>{}({})</td>".format(room.caption, room.num) return render(request, "index.html", locals())
显示效果:
这是Python2.6后新增了一种格式化字符串的函数 str.format(),它增强了字符串格式化的功能。基本语法是通过 {} 和 : 来代替以前的 % 。format 函数可以接受不限个参数,位置可以不按顺序。
>>>"{} {}".format("hello", "world") # 不设置指定位置,按默认顺序 'hello world' >>> "{0} {1}".format("hello", "world") # 设置指定位置 'hello world' >>> "{1} {0} {1}".format("hello", "world") # 设置指定位置 'world hello world'
还可以设置参数:
print("网站名:{name}, 地址 {url}".format(name="菜鸟教程", url="www.runoob.com")) # 通过字典设置参数 site = {"name": "菜鸟教程", "url": "www.runoob.com"} print("网站名:{name}, 地址 {url}".format(**site)) # 通过列表索引设置参数 my_list = ['菜鸟教程', 'www.runoob.com'] print("网站名:{0[0]}, 地址 {0[1]}".format(my_list)) # "0" 是必须的
(3)循环会议室生成行,循环时段生成列,标签字符串拼接处理
def index(request): # 拿到预定表中的时间段 time_choices = Book.time_choices # 拿到所有的会议室 room_list = Room.objects.all() # 构建标签 htmls = "" for room in room_list: # 有多少会议室生成多少行, # 每行仅生成了第一列。还有其他td标签需要添加,因此此处没有闭合tr htmls += "<tr><td>{}({})</td>".format(room.caption, room.num) for time_choice in time_choices: # 有多少时段就生成多少列 # 一次循环就是一个td标签 htmls += "<td></td>" # 循环完成后闭合tr标签 htmls += "</tr>" return render(request, "index.html", locals())
比如会议室有3个,循环会议室生成三行,且拿到会议室名称和人数限制生成首列;再循环时段,这里有13个时段,因此生成13列,13个td标签依次添加进一个tr中,显示效果如下:
(4)