先梳理一下我们的会议室预定是怎么做的

1、使用django自带的auth模块做用户认证

2、使用form表单生成登录的form表单

3、使用bookstrap做登录的css的渲染

4、设计会议室预定的model,用户表,我们不自己设计,使用django的user表,在设计一个会议室的表,最后在设计一个预定的表

5、会议室预定的前端的页面我们用table标签,通过bootstrap进行css渲染

6、通过ajax将预定的信息发送给后端,后端写入数据库后,前端重新加载页面,实现预定的效果

-----------------------------------------------------------------------------------------------------

一、登录相关的知识点梳理

1、首先先看下如何利用django自带的user表,和如何通过继承的方式扩展user表,因为user表中的字段是固定的,我们如果想扩展的话,就可以通过继承的方式,或者建立一张一对一的表两种方式来实现扩展user表

a、通过继承的方式扩展user表的字段

from django.contrib.auth.models import AbstractUser


class Userinfo(AbstractUser):
    iphone = models.CharField(max_length=11, null=True, blank=True)
    email = models.CharField(max_length=64, null=True, blank=True)
    create_time = models.DateTimeField(auto_now_add=True, blank=True)

    def __str__(self):
        return self.username

 

b、在settings中指明,django自带的auth模块要去我们新的userinfo表中去认证

AUTH_USER_MODEL = "app1.Userinfo"

 

c、还需要用到一个装饰器,就是校验用户是否登录的方法

这就是一个装饰器,可以用在任何需要登录的试图函数上

from django.contrib.auth.decorators import login_required

 

@login_required
def index(request):

 

这里还 要定义,如果用户没有登录,我要跳转到什么页面,这个也要在settings中设置,下面的意思就是如果没有登录,则跳转到登录页面

LOGIN_URL = "/app1/login/"

 

d、这里还有一个点要掌握,就是注销,auth模块自带的logout方法会删除session和cookies

def logout(request):
    auth.logout(request)
    return redirect("/app1/login/")

 

2、然后我们通过forms生成登录页面的form表单

a、首先导入用到的模块

from django import forms
from django.core.validators import RegexValidator
from django.forms import widgets
from django.contrib import auth
from django.contrib.auth.decorators import login_required

 

b、然后写forms的代码

class Loginclass(forms.Form):
    user_name = forms.CharField(
        label="用户名",
        label_suffix=":",
        max_length=12,
        min_length=5,
        validators = [
            RegexValidator(r'^\D{2}\d+\D+',code="checkfirst"),
        ],

        widget=widgets.Input(attrs={"placeholder":"请输入用户名","class":"form-control"}),
        error_messages= {
            "required":"用户名不能为空",
            "max_length":"用户名的最大长度为12",
            "min_length":"用户名的最小长度为5",
            "checkfirst":"用户名必须以2个非数字开头,中间为数字,以非数字结尾"
        }
    )
    user_pwd = forms.CharField(
        label="密码",
        label_suffix=":",
        max_length=12,
        min_length=5,
        widget=widgets.PasswordInput(attrs={"placeholder": "请输入密码","class":"form-control"},render_value=True),
        # validators = [
        #     RegexValidator(r'^\d+',code="checkfirst",message="密码必须全部为数字"),
        # ],
        error_messages= {
            "required":"密码不能为空",
            "max_length":"密码的最大长度为12",
            "min_length":"密码的最小长度为5"
        }
    )

 

c、然后就是登录的视图函数,这里我们会做两层的校验,首先forms表单会做一层校验,保证数据是符合条件的,第二层校验就是auth模块会去userinfo表中去校验用户名和密码是否正确

def login(request):
    method = request.method.lower()
    if method == "get":
        obj = Loginclass()
        return render(request,"book_login.html",{"obj":obj})

    else:
        obj = Loginclass(request.POST)
        if obj.is_valid():
            user = auth.authenticate(username=obj.cleaned_data["user_name"],password=obj.cleaned_data["user_pwd"])
            if user:
                auth.login(request,user)
                return redirect("/app1/index/")
            else:

                return redirect("/app1/login/")
        else:
            return render(request,"book_login.html",{"obj":obj})

 

这里有一段代码非常重要,下面这段代码就会在request添加一个属性就是request.user,这个的值就是当前登录的用户的对象

auth.login(request,user)

 

3、然后在看下登录页面的html的代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">

</head>
<body>
<h3>登陆页面</h3>
<form method="post" action="/app1/login/" novalidate>
    {% csrf_token %}
    <div class="form-group {% if obj.user_name.errors.0 %} has-error {% endif %}">
        <p>{{ obj.user_name.label }}{{ obj.user_name }}</p>
        <span class="help-block">{{ obj.user_name.errors.0 }}</span>
    </div>
    <div class="form-group {% if obj.user_pwd.errors.0 %} has-error {% endif %}">
        <p>{{ obj.user_pwd.label }}{{ obj.user_pwd }}</p>
        <span class="help-block">{{ obj.user_pwd.errors.0 }}</span>
    </div>
    <div class="form-group">
        <p><input type="submit" value="登陆" class="btn btn-success"></p>
    </div>
</form>


<script src="/static/jq/jquery-3.3.1.js"></script>
<script src="/static/jq/bootstrap.min.js"></script>
<script>


</script>
</body>
</html>

 

这里复习一下这个点,就是报错的的效果,如果某个字段有错误信息,则会有一个圈红的效果

    <div class="form-group {% if obj.user_name.errors.0 %} has-error {% endif %}">
        <p>{{ obj.user_name.label }}{{ obj.user_name }}</p>
        <span class="help-block">{{ obj.user_name.errors.0 }}</span>
    </div>

 

 

-----------------------------------------------------------------------------------------------------

二、这里我们主要看下表结构的设计

a、会议室表

class room(models.Model):
    rid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=64,verbose_name="会议室名称")
    num = models.SmallIntegerField()

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "会议室表"
        verbose_name_plural = verbose_name

 

b、预定表

class book(models.Model):
    bid = models.AutoField(primary_key=True)
    user_obj = models.ForeignKey(to=Userinfo,on_delete=models.CASCADE)
    room_obj = models.ForeignKey(to=room,on_delete=models.CASCADE)
    choices = (
        ("1","01:00"),
        ("2","02:00"),
        ("3","03:00"),
        ("4","04:00"),
        ("5","05:00"),
        ("6","06:00"),
        ("7","07:00"),
        ("8","08:00"),
    )
    time_id = models.CharField(choices=choices,max_length=64)
    book_time = models.DateTimeField(auto_now_add=True)

    # def __str__(self):
    #     return self.user_obj + "预定了" + self.room_obj

    class Meta:
        unique_together = ["user_obj","room_obj","time_id"]
        verbose_name = "预定表"
        verbose_name_plural = verbose_name

 

c、因为我们要通过admin去增加数据,所有我们需要在admin中注册我们的表结构,这一步不是必须的

from django.contrib import admin

# Register your models here.


from app1 import models
class rootclass(admin.ModelAdmin):
    list_display = ["rid","title","num"]

class bookclass(admin.ModelAdmin):
    list_display = ["bid","user_obj","room_obj","time_id","book_time"]

admin.site.register(models.room,rootclass)
admin.site.register(models.book,bookclass)

 

-----------------------------------------------------------------------------------------------------

三、在看下预定会议室的功能的实现

a、首先看下视图函数的get方式是如何处理的

@login_required
def index(request):
    import datetime
    current_time = datetime.datetime.now().date()
    # request.GET["book_time"] = "2018-12-02"
    check_time = request.GET.get("book_time",current_time)
    print(check_time)
    time_choice = models.book.choices
    room_list = models.room.objects.all()
    current_book_list = []
    book_list = models.book.objects.all()
    for i in book_list:
        if str(i.book_time.strftime("%Y-%m-%d")) == "2018-12-04":
            temp = (i.user_obj,i.room_obj.rid,i.time_id)
            current_book_list.append(temp)
    htmls = ""
    print(current_book_list)
    for room in room_list:
        temp_r = """<tr><td>{meetname}:(容量:{num}人)</td>""".format(meetname = room.title,num = room.num)
        for t in time_choice:
            if current_book_list:
                for book_room in current_book_list:
                    # print(str(book_room[1]),str(room.rid),str(book_room[2]),str(t[0]),sep="==================")
                    if str(book_room[1]) == str(room.rid) and str(book_room[2]) == str(t[0]):
                        current_login_user = request.user.username
                        print(current_login_user,book_room[0],sep="-------------")
                        if str(current_login_user) == str(book_room[0]):
                            temp_t = "<td room_id={rid} time_id={tid} class='checked item'>{name}</td>".format(rid=room.rid,tid=t[0],name=book_room[0])
                        else:
                            temp_t = "<td room_id={rid} time_id={tid} class='active_now item'>{name}</td>".format(rid=room.rid,
                                                                                                          tid=t[0],
                                                                                                          name=book_room[0])

                        break
                    else:
                        temp_t = "<td room_id={rid} time_id={tid} class='item'></td>".format(rid=room.rid, tid=t[0])
                    # temp_r = temp_r + temp_t
            else:
                temp_t = "<td room_id={rid} time_id={tid} class='item'></td>".format(rid=room.rid, tid=t[0])
            temp_r = temp_r + temp_t
        temp_r = temp_r + "</tr>"
        htmls = htmls + temp_r
    # print(htmls)
    return render(request,"index.html",locals())

 

这里主要是针对不同的数据返回不同的html代码,主要是css样式的不同的

首先从数据库中拿到所有的预定的信息,然后对不同的数据渲染不同的css样式

不同的数据有,“未被选中的会议室”,“当前用户选中的会议室”,“非当前用户选中的会议室”

 

 

b、前端的代码的

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/datetimepicker/bootstrap-datetimepicker.min.css">
    <style>
        .checked{
            background-color: yellow;
        }
        .active_now{
            background-color: red;
        }
        td{
            text-align: center;
        }
        th{
            text-align: center;
        }

        .td_active{
            background-color: #2e6da4;
        }
    </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 times in time_choice %}
                <th>{{ times.1 }}</th>
            {% endfor %}

        </tr>
    </thead>
    <tbody>
        {{ htmls |safe }}

    </tbody>
</table>
<input type="button" class="btn btn-success pull-right keep" value="提交">
<a href="/app1/logout"><input type="button" class="btn btn-info pull-left keep" value="注销"></a>
<script src="/static/jq/jquery-3.3.1.js"></script>
<script src="/static/jq/bootstrap.min.js"></script>
<script src="/static/datetimepicker/bootstrap-datetimepicker.min.js"></script>
<script src="/static/datetimepicker/bootstrap-datetimepicker.zh-CN.js"></script>


<script>
        var POST_DATA = {
            'ADD':{},
            "DEL":{}
        }
        function bindtd() {
        $(".item").bind("click",function () {
            var room_id = $(this).attr("room_id");
            var time_id = $(this).attr("time_id");
            if ($(this).hasClass("checked")){
                $(this).removeClass("checked");
                $(this).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");
                var del_index = POST_DATA.ADD[room_id].indexOf(time_id);
                POST_DATA.ADD[room_id].splice(del_index,1)
            }
            else if ($(this).hasClass("active_now")){
{#                pass#}
            }
            else {
                $(this).addClass("td_active");
                if (POST_DATA.ADD[room_id]){
                    POST_DATA.ADD[room_id].push(time_id);
{#                    alert(time_id)#}
                }
                else {
                   POST_DATA.ADD[room_id] = [time_id,]
                }

            }


        })
        }
        bindtd();

    {#        提交ajax数据#}

    $(".keep").bind("click",function () {
        $.ajax(
            {
                url:"/app1/book/",
                type:"POST",
                data:JSON.stringify(POST_DATA),
                contentType:"application/json",
{#              编码格式1:  application/json 这个是编码格式,告诉后端,我这次发的是json格式的数据,数据在请求体里的格式为'{"a":1,"b":2}',在视图函数中进行反序列化处理#}
{#              编码格式2:这个是默认的格式, 一般我们传递一个字典的格式过去,其实是用urldecode格式的数据发送给后端,在请求体里传递的数据类型为a=1&b=2&c=3#}

                success:function (data) {
                    document.location.reload()
                }


            }
        )
    })



</script>
</body>
</html>

 

这里需要注意的是这里

 

        function bindtd() {
        $(".item").bind("click",function () {
            var room_id = $(this).attr("room_id");
            var time_id = $(this).attr("time_id");
            if ($(this).hasClass("checked")){
                $(this).removeClass("checked");
                $(this).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");
                var del_index = POST_DATA.ADD[room_id].indexOf(time_id);
                POST_DATA.ADD[room_id].splice(del_index,1)
            }
            else if ($(this).hasClass("active_now")){
{#                pass#}
            }
            else {
                $(this).addClass("td_active");
                if (POST_DATA.ADD[room_id]){
                    POST_DATA.ADD[room_id].push(time_id);
{#                    alert(time_id)#}
                }
                else {
                   POST_DATA.ADD[room_id] = [time_id,]
                }

            }


        })
        }
        bindtd();

  

分别对空的表格,刚才点击过的预定的表格【但是还未更新到数据库】,当前用户预定的表格,其他用户预定的表格做分别的处理,添加不同的样式,同时更新POST_DAT

 

这里还有一个知识点

就是增加js的数组中的数据

POST_DATA.DEL[room_id].push(time_id)  

js删除数组中的元素的方式,首先要获取要删除元素的索引,然后在删除

                var del_index = POST_DATA.ADD[room_id].indexOf(time_id);
                POST_DATA.ADD[room_id].splice(del_index,1)

  

 

 

 

 

 

c、最后在看下更新数据库的试图函数

import json
def book(request):
    method = request.method.lower()
    if method == "post":
        add_dict = json.loads(request.body.decode('utf-8'))["ADD"]
        del_dict = json.loads(request.body.decode('utf-8'))["DEL"]
        print(add_dict,del_dict)
        user_obj = request.user
        if add_dict:
            for k in add_dict.keys():
                for v in add_dict[k]:
                    models.book.objects.create(
                        user_obj = user_obj,
                        room_obj = models.room.objects.get(rid=int(k)),
                        time_id = v,
                    )
        if del_dict:
            for k in del_dict.keys():
                for v in del_dict[k]:
                    models.book.objects.filter(
                        user_obj = user_obj,
                        room_obj = models.room.objects.get(rid=int(k)),
                        time_id = v
                    ).delete()

        return HttpResponse("ok")

 

首先从ADD的字典中拿出数据,然后调用create方法更新数据

然后从DEL的字典中拿出数据,然后调用del方法更新数据

最后返回结果,前端重新加载当前页面即可

posted on 2018-12-05 09:30  bainianminguo  阅读(317)  评论(0编辑  收藏  举报