会议室预定

会议室预定介绍

1. 目标:会议室预定


2. 业务流程:
  - 用户登录
  - 预定会议室
  - 退订会议室
  - 选择日期:今日以及以后日期


3. 数据库表设计:
  - 用户表
  - 会议室表
  - 关系表:
    用户ID    会议室ID    时间       时间段
    1        1      2017-12-11    1

 

from django.db import models


class UserInfo(models.Model):
    name = models.CharField(verbose_name='用户姓名', max_length=32)
    password = models.CharField(verbose_name='密码', max_length=32)


class MeetingRoom(models.Model):
    title = models.CharField(verbose_name='会议室', max_length=32)


class Booking(models.Model):
    user = models.ForeignKey(verbose_name='用户', to='UserInfo')

    room = models.ForeignKey(verbose_name='会议室', to='MeetingRoom')

    booking_date = models.DateField(verbose_name='预定日期')
    # time_choices = (
    #     (1, '8:30 - 9:00'),
    #     (2, '9:00 - 9:30'),
    #     (3, '9:30 - 10:00'),
    #     (4, '10:00 - 10:30'),
    #     (5, '10:30 - 11:00'),
    #     (6, '11:00 - 11:30'),
    #     (7, '11:30 - 12:00'),
    #     (8, '12:00 - 12:30'),
    #     (9, '12:30 - 13:00'),
    #     (10, '13:00 - 13:30'),
    #     (11, '13:30 - 14:00'),
    #     (12, '14:00 - 14:30'),
    #     (13, '14:30 - 15:00'),
    #     (14, '15:00 - 15:30'),
    #     (15, '15:30 - 16:00'),
    #     (16, '16:00 - 16:30'),
    #     (17, '16:30 - 17:00'),
    #     (18, '17:00 - 17:30'),
    #     (19, '17:30 - 18:00'),
    #     (20, '18:00 - 18:30'),
    #     (21, '18:30 - 19:00'),
    #     (22, '19:00 - 19:30'),
    #     (23, '19:30 - 20:00'),
    #     (24, '20:00 - 20:30'),
    # )

    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'),
    )
    booking_time = models.IntegerField(verbose_name='预定时间段', choices=time_choices)

    class Meta:
        unique_together = (
            ('booking_date', 'booking_time', 'room')
        )
models.py

 

 

 

 

登陆验证

class LoginForm(Form):
    name = fields.CharField(
        required=True,
        error_messages={'required': '用户名不能为空'},
        widget=widgets.TextInput(attrs={'class': 'form-control', 'placeholder': '用户名', 'id': 'name'})
    )
    password = fields.CharField(
        required=True,
        error_messages={'required': '密码不能为空'},
        widget=widgets.PasswordInput(attrs={'class': 'form-control', 'placeholder': '密码', 'id': 'password'})
    )
    rmb = fields.BooleanField(required=False, widget=widgets.CheckboxInput(attrs={'value': 1}))


def md5(val):
    import hashlib
    m = hashlib.md5()
    m.update(val.encode('utf-8'))
    return m.hexdigest()


def auth(func):
    def inner(request, *args, **kwargs):
        user_info = request.session.get('user_info')
        if not user_info:
            return redirect('/login/')
        return func(request, *args, **kwargs)

    return inner


def login(request):
    """
    用户登录
    """
    if request.method == "GET":
        form = LoginForm()
        return render(request, 'login.html', {'form': form})
    else:
        form = LoginForm(request.POST)
        if form.is_valid():
            rmb = form.cleaned_data.pop('rmb')
            form.cleaned_data['password'] = md5(form.cleaned_data['password'])
            user = models.UserInfo.objects.filter(**form.cleaned_data).first()
            if user:
                request.session['user_info'] = {'id': user.id, 'name': user.name}
                if rmb:
                    request.session.set_expiry(60 * 60 * 24 * 30)
                return redirect('/index/')
            else:
                form.add_error('password', '密码错误')
                return render(request, 'login.html', {'form': form})
        else:
            return render(request, 'login.html', {'form': form})

 

涉及知识点:

 

1. hashlib模块  ----密码密文处理

2. 用户登录验证

一般设置session或者cookie,如果是设置cookie,要用密文的方式

request.set_signed_cookie(key,value,salt='加密盐',...) 

查看更多

3.主动设置超时时间:

request.session.set_expiry(60 * 60 * 24 * 30)

 

- 判断用户是否已经登录

  - 装饰器,需要处理的函数较少,用装饰器即可
  - 中间件,需要处理的函数较多时采用

 

- 功能
  

- 获取并显示数据的两种方式

    - 模板渲染
    - 返回页面,ajax获取数据

- 发送数据的两种方式

    - Form表单提交
    - Ajax提交

 

前端页面

加载框的应用

基于bootstrap的datetimepicker时间插件

    function initDatepicker() {
        $('#datetimepicker11').datetimepicker({
            minView: "month",   //指定日历显示最小为月
            language: "zh-CN",   //汉化日历显示
            sideBySide: true,
            format: 'yyyy-mm-dd',   //指定显示格式
            bootcssVer: 3,
            startDate: new Date()    //指定起始日期
            //autoclose: true,  //确认日期即关闭日历
        }).on('changeDate', changeDate);    //绑定时间,日期改变则执行changeDate函数
    }

    //改变日期执行的函数
    function changeDate(ev) {
        CHOSEN_DATE = ev.date.Format('yyyy-MM-dd');
        initBookingInfo(CHOSEN_DATE);

    }

 

js方法扩展:

prototype 属性可以向对象添加自定义的属性和方法。

 

  String.prototype.xxx = function(arg){
  sdf
  }

  val ="asdf"
  val.xxx(arg)


  Date.prototype.Format = function (fmt){
  ...
  }
  v = new Date()
  v.Format('xx')

自定义Date的Format方法

Date.prototype.Format = 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 timeIndex = SELECTED_ROOM.add[roomId].indexOf(timeId);  //找到当前取消选中的在add[roomId]中的索引值,如果不存在索引值默认为-1

    if (timeIndex !== -1) {
                    SELECTED_ROOM.add[roomId].splice(timeIndex, 1);   //从列表中删除当前取消选中的timeId值

                }

 

JavaScript中的数组类似于Python中的列表

常见功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
obj.length          数组的大小
 
obj.push(ele)       尾部追加元素
obj.pop()           尾部获取一个元素
obj.unshift(ele)    头部插入元素
obj.shift()         头部移除元素
obj.splice(start, deleteCount, value, ...)  插入、删除或替换数组的元素
                    obj.splice(n,0,val) 指定位置插入元素
                    obj.splice(n,1,val) 指定位置替换元素
                    obj.splice(n,1)     指定位置删除元素
obj.slice( )        切片
obj.reverse( )      反转
obj.join(sep)       将数组元素连接起来以构建一个字符串
obj.concat(val,..)  连接数组
obj.sort( )         对数组元素进行排序

 

ajax发送数据时,如果需要发送json字符串但又希望能在request.POST里拿到值,可以采用发送字典的方式

 data: {date: CHOSEN_DATE, data: JSON.stringify(SELECTED_ROOM)}, //这样可以将部分数据json格式化,后端依然可以用request.POST接收数据

否则后端只能在request.body里取值,取出来时还需要先进行解码request.body.decode以后才能用dump.loads

 

前端发送日期到后端,后端把日期取出来是字符串格式,需要转换成时间对象

    current_date = datetime.datetime.now().date()   #将当前日期转换成年月日的形式

    if request.method == "GET":
        try:
            fetch_date = request.GET.get('date')    #此时的日期是字符串
            fetch_date = datetime.datetime.strptime(fetch_date, '%Y-%m-%d').date()  #将日期字符串转换成时间对象,用于比较时间
            if fetch_date < current_date:
                raise Exception('查询时间不能是以前的时间')

 

 

数据库查询、创建优化

点击查看更多

针对跨表查询优化:select_related、prefetch_related

booking_list = models.Booking.objects.filter(booking_date=fetch_date).select_related('user', 'room').order_by(
                'booking_time') #查询当前时间的预定信息,并按预定时间排序,且优化查询外键字段

 

批量创建:bulk_create

 

 #增加记录
            add_booking_list = []
            for room_id, time_id_list in booking_info['add'].items():
                for time_id in time_id_list:
                    obj = models.Booking(
                        user_id=request.session['user_info']['id'],
                        room_id=room_id,
                        booking_time=time_id,
                        booking_date=booking_date
                    )
                    add_booking_list.append(obj)
            models.Booking.objects.bulk_create(add_booking_list)

 

 

获取某一天的预定
            current_date = "2017-11-11"
            current_date = datetime.datetime.strptime(current_date, '%Y-%m-%d').date()
            # 查询
            # select * from booking 
            models.booking.objects.filter(date=current_date)
            
            
            # 主动连表(join 连表查询有性能损耗)PS:大公司用空间换时间
            # select * from booking left join user on user.id = booing.user_id ...
            models.booking.objects.filter(date=current_date).select_related('user','room')
            
            
            # 不连表 (in)
            # select * from booing
            # 获取booking中取到的所有 user_id_list
            # select * from user where id in user_id_list
            models.booking.objects.filter(date=current_date).prefetch_related('user','room')
            models.booking.objects.filter(date=current_date).select_related('user','room')
            
            
            booking_list = [
                obj(id,user_id,room_id,time_id,date),
                obj(id,user_id,room_id,time_id,date),
                obj(id,user_id,room_id,time_id,date),
                obj(id,user_id,room_id,time_id,date),
            ]
            for item in booking_list:
                item.room_id, id.user.user

 

 

Q查询的用法

点击查看

#删除记录
            #因为我们需要将del字典里所记载的数据删除,每条需要删除的数据,在数据库匹配时要同时匹配user_id,booking_date,room_id,booking_time
            #四条个条件是AND关系,将每个纪律的查询都做出一个Q对象,然后放到另一个Q对象中,用OR连接,只有符合条件就删除
            remove_booking = Q()
            for room_id, time_id_list in booking_info['del'].items():
                for time_id in time_id_list:
                    temp = Q()
                    temp.connector = 'AND'
                    temp.children.append(('user_id', request.session['user_info']['id'],))
                    temp.children.append(('booking_date', booking_date,))
                    temp.children.append(('room_id', room_id,))
                    temp.children.append(('booking_time', time_id,))
                    remove_booking.add(temp, 'OR')
            if remove_booking: #如果有需要删除的,才删除
                models.Booking.objects.filter(remove_booking).delete()

 

 

 

 booking_list = models.Booking.objects.filter(booking_date=fetch_date).select_related('user',
                                                                                                 'room').order_by(
                'booking_time') #查询当前时间的预定信息,并按预定时间排序,且优化查询外键字段

            booking_dict = {}
            for item in booking_list:
                if item.room_id not in booking_dict:
                    booking_dict[item.room_id] = {item.booking_time: {'name': item.user.name, 'id': item.user.id}}
                else:
                    if item.booking_time not in booking_dict[item.room_id]:
                        booking_dict[item.room_id][item.booking_time] = {'name': item.user.name, 'id': item.user.id}
            """
            {
                room_id:{
                    time_id:{''},
                    time_id:{''},
                    time_id:{''},
                }
            }
            """

            room_list = models.MeetingRoom.objects.all()

            booking_info = []
            for room in room_list:
                temp = [{'text': room.title, 'attrs': {'rid': room.id}, 'chosen': False}]
                for choice in models.Booking.time_choices:
                    v = {'text': '', 'attrs': {'time-id': choice[0], 'room-id': room.id}, 'chosen': False}
                    if room.id in booking_dict and choice[0] in booking_dict[room.id]:
                        v['text'] = booking_dict[room.id][choice[0]]['name']
                        v['chosen'] = True
                        if booking_dict[room.id][choice[0]]['id'] != request.session['user_info']['id']:
                            v['attrs']['disable'] = 'true'
                    temp.append(v)
                booking_info.append(temp)

            ret['data'] = booking_info

要学习这样转换数据的结构的方式

posted @ 2017-12-13 08:17  听风。  阅读(299)  评论(0)    收藏  举报