10.14 预订会议室的小Demo
2018-10-14 17:12:32
越努力,越幸运.永远不要高估自己!
网上修改一下博客网站样式,做个仿qq空间的!
放上github连接 :https://github.com/TrueNewBee/pythonDemo/blob/master/%E9%A2%84%E5%AE%9A%E4%BC%9A%E8%AE%AE%E5%AE%A4.rar
整体实现不难:
预定会议室功能实现:
1.登入后 /login/ 后 可以看到所有人的预订
2.绿色为当前登录人的预订
3.点击某单元删除和添加预订,如果选择了重复则有提示
4.通过了Ajax请求,去掉了crsf跨站请求伪造
放上源码:
views.py
from django.shortcuts import render, redirect, HttpResponse from django.contrib import auth from .models import * from django.db.models import Q import json import datetime # 超级用户 root root1234 # zhen zhen1234 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 return redirect("/index/") return render(request, "login.html") def index(request): # 获取当前日期 date = datetime.datetime.now().date() # 查看特定日期下的book book_date = request.GET.get("book_date",date) time_choices = Book.time_choices room_list = Room.objects.all() # 找到该日期下的预订的会议室 book_list = Book.objects.filter(date=book_date) htmls = "" for room in room_list: htmls += "<tr><td>{}({})</td>".format(room.caption,room.num) for time_choice in time_choices: book = None flag = False for book in book_list: # 判断这个单元格的纵横坐标是否存在 if book.room.pk == room.pk and book.time_id == time_choice[0]: # 味这个单元格已被预定 flag = True break if flag: # 根据flog的变化 加上特定的class 在前端通过class来添加css if request.user.pk == book.user.pk: htmls += "<td class='active item' room_id={} time_id={}>{}</td>".format(room.pk, time_choice[0], book.user.username) else: htmls += "<td class='another_active item' room_id={} time_id={}>{}</td>".format(room.pk, time_choice[0], book.user.username) else: htmls+="<td room_id={} time_id={} class='item'></td>".format(room.pk,time_choice[0]) htmls += "</tr>" return render(request, "index.html", locals()) def book(request): print(request.POST) post_data = json.loads(request.POST.get("post_data")) # {"ADD":{"1":["5"],"2":["5","6"]},"DEL":{"3":["9","10"]}} choose_date = request.POST.get("choose_date") res = {"state": True, "msg" : None} try: # 添加预定 # post_data["ADD"] : {"1":["5"],"2":["5","6"]} book_list = [] for room_id, time_id_list in post_data["ADD"].items(): for time_id in time_id_list: book_obj = Book(user=request.user, room_id=room_id, time_id=time_id, date=choose_date) book_list.append(book_obj) Book.objects.bulk_create(book_list) # 删除预定 # post_data["DEL"]: {"2":["2","3"]} remove_book = Q() for room_id, time_id_list in post_data["DEL"].items(): temp = Q() for time_id in time_id_list: temp.children.append(("room_id", room_id)) temp.children.append(("time_id", time_id)) temp.children.append(("user_id", request.user.pk)) temp.children.append(("date", choose_date)) remove_book.add(temp, "OR") if remove_book: Book.objects.filter(remove_book).delete() except Exception as e: res["state"] = False res["msg"] = str(e) return HttpResponse(json.dumps(res))
index.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css"> <script src="/static/js/jquery-1.12.4.min.js"></script> <script src="/static/datetimepicker/bootstrap-datetimepicker.min.js"></script> <script src="/static/datetimepicker//bootstrap-datetimepicker.zh-CN.js"></script> <style> .active{ background-color: green!important; color: white; } .another_active{ background-color: #2b669a; color: white; } .td_active{ background-color: lightblue; color: white; } </style> </head> <body> <h3>会议室预定</h3> <div class="calender pull-right"> <div class='input-group' style="width: 230px;"> <input type='text' class="form-control" id='datetimepicker11' placeholder="请选择日期"/> <span class="input-group-addon"> <span class="glyphicon glyphicon-calendar"> </span> </span> </div> </div> <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> <button class="btn btn-success pull-right keep">保存</button> <script > // js 必会的 字符串 数组 object { } // 日期格式化方法 Date.prototype.yuan = function (fmt) { //author: meizz var o = { "M+": this.getMonth() + 1, //月份 "d+": this.getDate(), //日 "h+": this.getHours(), //小时 "m+": this.getMinutes(), //分 "s+": this.getSeconds(), //秒 "q+": Math.floor((this.getMonth() + 3) / 3), //季度 "S": this.getMilliseconds() //毫秒 }; if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); for (var k in o) if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); return fmt; }; var POST_DATA={ "ADD":{}, "DEL":{}, }; // 为td绑定单击事件 function BindTd() { $(".item").click(function () { var room_id=$(this).attr("room_id"); var time_id=$(this).attr("time_id"); // 取消预定 if($(this).hasClass("active")){ $(this).removeClass("active").empty(); if(POST_DATA.DEL[room_id]){ POST_DATA.DEL[room_id].push(time_id) }else { POST_DATA.DEL[room_id]=[time_id,] } } // 临时取消预定 else if ($(this).hasClass("td_active")){ $(this).removeClass("td_active"); POST_DATA.ADD[room_id].pop() } else{ // 添加预定 $(this).addClass("td_active"); if(POST_DATA.ADD[room_id]){ POST_DATA.ADD[room_id].push(time_id) }else { POST_DATA.ADD[room_id]=[time_id,] } } }) } BindTd(); // 日期 if (location.search.slice(11)){ CHOOSE_DATE = location.search.slice(11) } else { CHOOSE_DATE = new Date().yuan('yyyy-MM-dd'); } // 发送ajax $(".keep").click(function () { $.ajax({ url:"/book/", type:"POST", data:{ choose_date:CHOOSE_DATE, post_data:JSON.stringify(POST_DATA), }, dataType:"json", success:function (data) { console.log(data) if(data.state){ // 预定成功 location.href="" }else { alert("预定的房间已经被预定") location.href="" } } }) }); // 日历插件 $('#datetimepicker11').datetimepicker({ minView: "month", language: "zh-CN", sideBySide: true, format: 'yyyy-mm-dd', startDate: new Date(), bootcssVer: 3, autoclose: true, }).on('changeDate', book_query); function book_query(e) { CHOOSE_DATE=e.date.yuan("yyyy-MM-dd"); location.href="/index/?book_date="+CHOOSE_DATE; } </script> </body> </html>
models.py
from django.db import models from django.contrib.auth.models import AbstractUser # 需要在settings配置 AUTH_USER_MODEL = "app01.UserInfo" 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') room = models.ForeignKey('Room') 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) # 联合唯一 class Meta: unique_together = ( ('room','date','time_id'), ) def __str__(self): return str(self.user)+"预定了"+str(self.room)
urls.py
"""MRBS URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.11/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) """ from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^login/', views.login), url(r'^index/', views.index), url(r'^book/', views.book), ]
贴上笔记:
POST: 浏览器-------------------->server "请求首行\r\nContent-Type:url_encode\r\n\r\na=1&b=2" "请求首行\r\nContent-Type:application/json\r\n\r\n'{"a":1,"b":2}'" 在django的wsgi的request中: request.body:元数据'{"a":1,"b":2}' if 请求头中的Content-Type==url_encode: request.POST=解码a=1&b=2 Q: 方式1: q=Q() q.connection="or" q.children.append("pk",1) q.children.append("user_id",1) q.children.append("room_id",1) Book.objects.filter(q) 方式2: Book.objects.filter(Q(pk=1)|Q(user_id=1)|Q(room_id=1))