* <pre>━━━━━━神兽出没━━━━━━

*   ┏┓   ┏┓

*  ┏┛┻━━━┛┻┓

*  ┃   王   ┃

*  ┃         ┃

*  ┃ ┳┛ ┗┳ ┃

*  ┃       ┃

*  ┃   ┻   ┃

*  ┃       ┃

*  ┗━┓   ┏━┛

*    ┃   ┃    神兽保佑,代码无bug

*    ┃   ┃

*    ┃   ┗━━━┓

*    ┃       ┣┓

*    ┃       ┏┛

*    ┗┓┓┏━┳┓┏┛

*     ┃┫┫ ┃┫┫

*     ┗┻┛ ┗┻┛

*</pre>

本练习作者源于虫师

1、环境配置

  1. 安装django

pip install django

  1. 配置环境变量

将下面路径添加到系统环境变量的path中

C:\Users\12978\AppData\Local\Programs\Python\Python36-32\Scripts

在cmd.exe中运行:django-admin help

出现以下图表示配置成功!

3、创建django项目

1.创建项目

方法一:点击:file-->new project,输入项目名称,创建项目。

方法二:win+r弹窗中输入命令cmd命令,输入:django-admin,罗列出 Django 所提供给我们的命令,其中使用“startproject”命令来创建项目,把项目创建在了D盘。

切换文件创建位置命令:cd /d d:

输入创建项目名称:django-admin startproject guest      #项目名为guest

项目结构如下:

与项目同名的目录中是配置文件,templates目录是html文件存放也就是MTV中的T。manage.py是django项目管理文件。

guest/__init__.py:一个空的文件,用它标识一个目录为 Python 的标准包。

guest/settings.py:Django 项目的配置文件,包括 Django 模块应用配置,数据库配置,模板配置等。

guest/urls.py:Django 项目的 URL 声明。

guest/wsgi.py:为 WSGI 兼容的 Web 服务器服务项目的切入点。

manage.py:一个命令行工具,可以让你在使用 Django 项目时以不同的方式进行交互。

查看 manage 所提供的命令:python manage.py

2.创建APP

 每个django项目中可以包含多个APP,相当于一个大型项目中的分系统、子模块、功能部件等等,相互之间比较独立,但也有联系。所有的APP共享项目资源。

在pycharm下方的terminal终端中输入命令:python manage.py startapp cmdb

目录如下:

这样就创建了一个叫做cmdb的APP,django自动生成“cmdb”文件夹。

migrations/:用于记录 models 中数据的变更。

admin.py:映射 models 中的数据到 Django 自带的 admin 后台。

apps.py:在新的 Django 版本中新增,用于应用程序的配置。

models.py:创建应用程序数据表模型(对应数据库的相关操作)。

tests.py:创建 Django 测试。

views.py:控制向前端显示哪些数据。

4.编写路由

路由都在urls文件里,它将浏览器输入的url映射到相应的业务处理逻辑。

编写路由需要用的正则表达式,

r 字符串前面加“ r ”是为了防止字符串中出现类似“\t”字符时被转义。

^ 匹配字符串开头;在多行模式中匹配每一行的开头。 ^abc abc

$ 匹配字符串末尾;在多行模式中匹配每一行末尾

通过^index/$ 匹配到/index/目录。并且将处理指向 sign 应用的视图文件 views.py 的 index 函数

在guest文件夹得urls.py编写

Django2.0中path无法匹配正则表达式,用下面的方法

re_path(r'^index/$',views.index),

1.项目地址配置:

方法一:启动项目命令:>python manage.py runserver

方法二:直接使用pycharm运行,打开链接地址;

URL 地栏输入:http://127.0.0.1:8000/或者http://localhost:8080/

修改Url.py文件,添加index路径

from django.contrib import admin

from django.urls import path,re_path

from cmdb import views       #导入模块

urlpatterns = [

#re_path('admin/', admin.site.urls),

re_path(r'^index/$',views.index),     添加路径配置

5. views视图编写业务处理逻辑

业务处理逻辑都在views.py文件里。

from django.http import HttpResponse

def index(request):

    return HttpResponse("")

运行后http://localhost:8080/index返回内容为102

6.返回HTML文件

1.创建 templates/index.html 文件

<html>

<head>

<title>Django Page</title>

 </head>

<body>

<h1>Hello Django!</h1>

</body>

 </html>

2.修改views.py文件

导入的 render 函数。该函数的第一个参数是请求对象的,第二个参 数返回一个 index.html 页面。

from django.shortcuts import render
from django.http import HttpResponse def index(request): return render(request,"index.html") # return HttpResponse("102")'''

4、views视图get/post请求案例

GET- 从指定的资源请求数据。

POST- 向指定的资源提交要被处理的数据

1.登录使用get请求,修改index.html

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Django page</title>

</head>

<body>

<h1>发布管理</h1>

<form method="POST" >

    <input name="username" type="text" placeholder="username"><br>

    <input name="password" type="password" placeholder="password"><br>

    <button id="btn" type="submit">登录</button>

 </form>

</body>

</html>

请求地址:运行后http://localhost:8080/index

输入用户名和密码,查看用户提交的数据添加到url地址中:

http://localhost:8080/index/?username=admin&password=admin123

2.使用post请求

将 form 表单的中的属性改为 method="post",会报错,报错信息如下:

“CSRFverificationfailed.Requestaborted.”

( Cross-SiteRequestForgery, CSRF)Django 针对 CSRF 的保护措施是在生成的每个表单中放置一个自动生成的令牌,通过这个令牌判断 POST 请求是否来自同一个网站。

解决办法1:需要在 from 表单中添加{% csrf_token %}。

解决办法2:在setting.py文件中注释掉csrf.

3.处理登录请求

1.修改index.html文件

#通过 form 表单的 action 属性来指定提交的路径,,添加{{error}},它对应 render 返回字典中的 key,并且在登录失败 的页面中显示 value,

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Django page</title>
</head>
<body>
<h1>发布管理</h1>
<form method="POST" action="/login_action/">
<input name="username" type="text" placeholder="username"><br>
<input name="password" type="password" placeholder="password"><br>
{{ error }}<br>
<button id="btn" type="submit">登录</button>
</form>
</body>
</html>

2.修改urls.py文件

from django.urls import path,re_path
from cmdb import views urlpatterns = [
#re_path('admin/', admin.site.urls),
re_path(r'^index/$',views.index),
re_path(r'^login_action/$',views.login_action),

3.修改views.py

from django.shortcuts import render
from django.http import HttpResponse def index(request): return render(request,"index.html") #登录 def login_action(request): if request.method =='POST': username = request.POST.get('username','') password = request.POST.get('password','') if username == 'admin' and password=='': return HttpResponse(‘login success!’) else: return render(request,'index.html', {'error': 'username or passworderror!'})

运行运行程序:

4.添加登录成功页面

1.创建/templates/event_manage.html 页面

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Event Manage Page</title>

</head>

<body>

<h1>Login Success!</h1>

</body>

</html>

2.修改views.py

from django.shortcuts import render

from django.http import HttpResponse,HttpResponsePermanentRedirect

def index(request):

    return render(request,"index.html")

#登录

def login_action(request):

    if request.method =='POST':

        username = request.POST.get('username','')

        password = request.POST.get('password','')

        user = auth.authenticate(username=username, password=password)

        if username == 'admin' and password=='':

            return HttpResponsePermanentRedirect('/event_manage/')

        else:

            return render(request,'index.html', {'error': 'username or passworderror!'})

    else:

            return render(request,'index.html', {'error': 'username or passworderror!'})

#发布会管理

def event_manage(request):

     return render(request,"event_manage.html",{"user":username})

又用到的一个新的类 HttpResponseRedirect,它可以对路径进行重定向,从而将登录成功之后的请求 指向/event_manage/目录。

创建 event_manage 函数,用于返回发布会管理 event_manage.html 面页

3.修改urls.py文件

from django.contrib import admin
from django.urls import path,re_path
from cmdb import views urlpatterns = [
#re_path('admin/', admin.site.urls),
re_path(r'^index/$',views.index),
re_path(r'^login_action/$',views.login_action),
re_path(r'^event_manage/$',views.event_manage), #添加路由

重新运行!

5. Cookie 和 Session

session和cookie的作用都是为了存储用户相关的信息。不同的是,cookie是存储在本地浏览器,而session存储在服务器。存储在服务器的数据会更加的安全,不容易被窃取。但存储在服务器也有一定的弊端,就是会占用服务器的资源,但现在服务器已经发展至今,一些session信息还是绰绰有余的。

1.修改views.py文件

from django.shortcuts import render
from django.http import HttpResponse,HttpResponsePermanentRedirect def index(request): return render(request,"index.html") # return HttpResponse("102")''' #登录 def login_action(request): if request.method =='POST': username = request.POST.get('username','') password = request.POST.get('password','') if username == 'admin' and password=='': response= HttpResponsePermanentRedirect('/event_manage/') #response.set_cookie('user',username,3600) #添加浏览器cookie request.session['user']=username #把cookie替换为 session 信息记录到浏览器 else: return render(request,'index.html', {'error': 'username or passworderror!'}) #发布会管理 def event_manage(request): #username = request.COOKIES.get('user','') ##读取浏览器cookie username=request.session.get('user','') # 读取浏览器 session return render(request,"event_manage.html",{"user":username})

set_cookie()方法传了三个参数,第一个参数“user”是用于表示写入浏览器的 Cookie 名,第二个 参数 username 是由用户在登录页上输入的用户名,第三个参数 3600 用于表示该 cookie 信息在浏览器中的停 留时间,默认以秒为单位。

而在 event_manage 视图函数中,通过 request.COOKIES 来读取 Cookie 名为“user”的值。并且通过 render 将和 event_manage.html 页面一起返回给客户端浏览器。

2.修改/event_manage.html

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Event Manage Page</title>

</head>

<body>

<h1>Login Success!</h1>

<div style="float:right;"><a>嘿!{{ user }} 欢迎</a><hr/> </div>

</body>

</html>

Cookie的运行页面:

3.读取session时的问题

将cookie替换后再次登录会报错:“nosuchtable:django_session”

这个错误跟 Session 的机制有关,要服务器端记录用户的数据,那么一定要有地方来存放用户 Sessionid 对应的信息才对。所以,我们需要创建 django_session 表。

命令:python3 manage.py migrate

如下:

在 guest 项目的根目录下会生成一个 db.sqlite3 文件.

6、django模型

1.设计系统表

Django 提供完善的模型(model)层主要用来创建和存取数据,不需要我们直接对数据库操作。每个模型是一个 Python 类,继承 django.db.models.model 类。该模型的每个属性表示一个数据库表字段。每个字段都指定为一个类属性,每个属性都映射到一个数据库列。自动生成的数据库访问的 API。

1.打开.../sign/models.py 文件,完成表的创建。

from django.db import models

from django.utils import timezone

# Create your models here.

#发布会

class Event(models.Model):

    name=models.CharField(max_length=100)   #发布会标题

    limit=models.IntegerField(blank=True, null=True)     #参加人数

    status=models.BooleanField(blank=True, null=True)    #状态

    address=models.CharField(max_length=200)   #地址

    start_time=models.DateTimeField(default=timezone.now)   #发布会时间

    create_time=models.DateTimeField(default=timezone.now)   #创建时间(自动获取时间)

    def __str__ (self):

        return self.name

#嘉宾表

class Guest(models.Model):

    #event=models.ForeignKey(Event)  关联外键会报错,外键值的后面加上 on_delete=models.CASCADE

    event=models.ForeignKey('Event',on_delete=models.CASCADE)             #关联发布会

    realname=models.CharField(max_length=64)    #姓名

    phone=models.CharField(max_length=16)     #手机号

    email=models.EmailField(blank=True, null=True)               #邮箱

    sign=models.BooleanField(blank=True, null=True)                 #签到状态

    create_time=models.DateTimeField(default=timezone.now)   #创建时间(自动获取时间)

    class Meta:

        unique_together=("event","phone")

    def __str__(self):

        return self.realname

对于产品发布会来说,显然它是一个事件。那么时间、地点、人物等要素必不可少。数据库表的设计需

要围绕着这些要素进行。

关于发布会表(Event 类)和嘉宾表(Guest 类)的每一个字段,在代码中已经做了注解。有些字段的设 计需要做一下简单的说明。

首先,发布会表和嘉宾表中默认都会生成自增 id,而我们在创建模型时不需要声明该字段。

其次,发布会表中增加了 status 字段用于表示发布会的状态是否开启,用于控制该发布会是否可用。

再次,嘉宾表中通过 event_id 关联发布会表,一条嘉宾信息一定所属于某一场发布会。

最后,对于一场发布会来说,一般会选择手机号作为一位嘉宾的验证信息,所以,对于一场发布会来说, 手机号必须是唯一。除了嘉宾 id 外,这里通过发布会 id+手机号来做为联合主键。

__str__()方法告诉 Python 如何将对象以 str 的方式显示出来。所以,为每个模型类添加了__str__()方法。

Django 数据类型:

2.数据迁移

1)命令:python manage.py makemigrations cmdb

使用命令生成数据表时的问题:

event=models.ForeignKey(Event)  关联外键会报错,外键值的后面加上 on_delete=models.CASCADE

报错信息:

原因:在django2.0后,定义外键和一对一关系的时候需要加on_delete选项,此参数为了避免两个表里的数据不一致问题,不然会报错:
TypeError: __init__() missing 1 required positional argument: 'on_delete'
举例说明:
user=models.OneToOneField(User)
owner=models.ForeignKey(UserProfile)
需要改成:
user=models.OneToOneField(User,on_delete=models.CASCADE) --在老版本这个参数(models.CASCADE)是默认值
owner=models.ForeignKey(UserProfile,on_delete=models.CASCADE) --在老版本这个参数(models.CASCADE)是默认值
参数说明:
on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五个可选择的值
CASCADE:此值设置,是级联删除。
PROTECT:此值设置,是会报完整性错误。
SET_NULL:此值设置,会把外键设置为null,前提是允许为null。
SET_DEFAULT:此值设置,会把设置为外键的默认值。
SET():此值设置,会调用外面的值,可以是一个函数。
一般情况下使用CASCADE就可以了。

修改后再次执行命令:

2)命令2:python manage.py migrate

2.Admin后台管理

们创建的发布会和嘉宾表 同样可以通过 Admin 后台去管理。

1.修改cmdb/admin.py文件

from django.contrib import admin

from cmdb.models import Event, Guest

# Register your models here.

admin.site.register(Event)

admin.site.register(Guest)

运行,查看admin后台:

2.修改admin.py文件,显示更多字段

from django.contrib import admin

from cmdb.models import Event, Guest

# Register your models here.

class EventAdmin(admin.ModelAdmin):         #新建EventAdmin 类,继承 django.contrib.admin.ModelAdmin 类,保存着一个类的自定义配置,以供Admin 管理工具使用

    #list_display:字段名称的数组,用于定义要在列表中显 示哪些字段,字段名称必须是模型中的 Event()类定义的

    list_display = ['name','status','start_time','id']

    search_fields = ['name']     #搜索栏  search_fields 用于创建表字段的搜索器,可以设置搜索关键字匹配多个表字段

    list_filter = ['status']     #过滤器  用于创建字段过

class GuestAdmin(admin.ModelAdmin):

    list_display = ['realname','phone','email','sign','create_time','event']

    search_fields = ['realname','phone']     #搜索栏

    list_filter = ['sign']     #过滤器

admin.site.register(Event,EventAdmin)   #:用 EventAdmin 选项注册 Event 模块。

admin.site.register(Guest,GuestAdmin)

运行程序:

3.数据访问

命令: python manage.py shell

通过shell命令,在该模式下操做数据表操作。

命令:from sign.models import Event, Guest  #导入cmdb应用下的 models.py 中的 Event 表和 Guest 表。

命令:Event.objects.all()    #获得 table(Event、Gues 表)中的所有对象。

3.Sqlitestudio

SQLiteStudio 是一个跨平台的 SQLite 数据库的管理工具.

下载地址:http://sqlitestudio.pl/

4.安装mysql

mysql安装包:https://dev.mysql.com/downloads/file/?id=479141

环境:Django2.1+mysql版本5.7 ,因为5.5得不支持

5.安装 PyMySQL

命令:>python -m pip install PyMySQL

6.Django配置mysql

1.修改guest/settings.py文件

DATABASES = {

    'default': {

        #'ENGINE': 'django.db.backends.sqlite3',

        #'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),

        'ENGINE': 'django.db.backends.mysql',

        'HOST': '127.0.0.1',

        'PORT': '',

        'NAME': 'guest',

        'USER': 'root',

        'PASSWORD': 'root',

        'OPTIONS': {

            'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",

    }

  }

}

注意:切换了数据库后,之前 Sqlite3 数据库里的数据并不能复制到 MySQL 中,所以需要重新进行数据 库同步,使数据模型重新在 MySQL 数据库中生成表。在编辑器中创建guest数据库。

3.修改guest/__init__.py

Django通过 PyMySQL驱动来连接MySQL数据库

import pymysql

pymysql.install_as_MySQLdb()

4.执行数据库同步

命令:python manage.py migrat

运行成功页面:

更换了数据库,所以,Admin 后台超级管理员账号(admin/admin123456)也需要重新创建:

用户名为:admin   密码:admin123456

命令:python manage.py createsuperuser

7、Django模板

1.Django-bootstrap3

项目是将 BootStrap3(3 表示版本号)集成到 Django 中,作为 Django 的一个应用提供。 这样做的好处是在 Django 中用 bootstrap 会更加方便。

命令安装: pip install django-bootstrap3

1.修改guest/setting.py文件,添加bootstrap3

INSTALLED_APPS = [

    'django.contrib.admin',

    'django.contrib.auth',

    'django.contrib.contenttypes',

    'django.contrib.sessions',

    'django.contrib.messages',

    'django.contrib.staticfiles',

    'cmdb',

    'bootstrap3',

]

2.发布会管理

1.发布会列表,修改 event_manage()视图。

from sign.models import Event,Guest

#发布会管理

@login_required

def event_manage(request):

    event_list=Event.objects.all()        #用于查询所有发布会对象

    #username = request.COOKIES.get('user','')  ##读取浏览器cookie

    username=request.session.get('user','')   # 读取浏览器 session

    return render(request,"event_manage.html",{"user":username,

                                               "events":event_list})   #通过 render()函数附加在 event_manage.html 页面 返回给客户端浏览器。

#发布会名称搜索

@login_required

def search_name(request):

    username = request.session.get('user', '')

    search_name = request.GET.get("name", "")

    event_list = Event.objects.filter(name__contains=search_name)

    return render(request, "event_manage.html", {"user": username,

                                                 "events": event_list})

2.修改/templates/event_manage.html 页面

<!DOCTYPE html>

<html lang="en">

<head>

    {% load bootstrap3 %}

    {% bootstrap_css %}

    {% bootstrap_javascript %}

    <meta charset="UTF-8">

    <title>Guest Manage</title>

</head>

<body role="document">

 <!-- 导航栏 -->

    <nav class="navbar navbar-inverse navbar-fixed-top">

      <div class="container">

        <div class="navbar-header">

          <a class="navbar-brand" href="/event_manage/">Guest Manage System</a>

        </div>

        <div id="navbar" class="collapse navbar-collapse">

          <ul class="nav navbar-nav">

            <li class="active"><a href="#">发布会</a></li>

            <li><a href="/guest_manage/">嘉宾</a></li>

          </ul>

          <ul class="nav navbar-nav navbar-right">

           <li><a href="#">{{user}}</a></li>

           <li><a href="/logout/">退出</a></li>

         </ul>

        </div><!--/.nav-collapse -->

      </div>

    </nav>

      <!--发布会表单-->

      <div class="page-header" style="padding-top: 60px;">

        <div id="navbar" class="navbar-collapse collapse">

          <form class="navbar-form" method="get" action="/search_name/">

            <div class="form-group">

              <input name="name" type="text" placeholder="名称" class="form-control">

            </div>

            <button type="submit" class="btn btn-success">搜索</button>

          </form>

        </div><!--/.navbar-collapse -->

      </div>

      <!--发布会列表-->

      <div class="row" style="padding-top: 80px;">

        <div class="col-md-6">

          <table class="table table-striped">

            <thead>

              <tr>

                <th>id</th>

                <th>名称</th>

                <th>状态</th>

                <th>地址</th>

                <th>时间</th>

                <th style="width: 45px;">签到</th>

                <th>签到正式</th>

              </tr>

            </thead>

            <tbody>

              {% for event in events %}

                <tr>

                  <td>{{ event.id }}</td>

                  <td>{{ event.name }}</td>

                  <td>{{ event.status }}</td>

                  <td>{{ event.address }}</td>

                  <td>{{ event.start_time }}</td>

                  <td><a href="/sign_index/{{ event.id }}/"  target="{{ event.id }}_blank">sign</a></td>

                  <td><a href="/sign_index2/{{ event.id }}/"  target="{{ event.id }}_blank">sign_web</a></td>

                </tr>

             {% endfor %}

            </tbody>

          </table>

        </div>

      </div>

</body>

</html>

3.添加搜索路径的路由/guest/urls.py

re_path(r'^search_name/$',views.search_name),

运行:

3.嘉宾管理

1.创建/templates/guest_manage.html

<!DOCTYPE html>

<html lang="en">

<head>

    {% load bootstrap3 %}

    {% bootstrap_css %}

    {% bootstrap_javascript %}

    <meta charset="UTF-8">

    <title>Title</title>

</head>

<body role="document">

<!-- 导航栏 -->

        <nav class="navbar navbar-inverse navbar-fixed-top">

            <div class="container">

                <div class="navbar-header">

                    <a class="navbar-brand" href="/guest_manage/">Guest Manage System</a>

                </div>

                <div id="navbar" class="collapse navbar-collapse">

                    <ul class="nav navbar-nav">

                        <li><a href="/event_manage/">发布会</a></li>

                        <li class="active"><a href="#about">嘉宾</a></li>

                    </ul>

                    <ul class="nav navbar-nav navbar-right">

                        <li><a href="#">{{user}}</a></li>

                        <li><a href="/logout/">退出</a></li>

                    </ul>

                </div><!--/.nav-collapse -->

            </div>

        </nav>

        <

        <!--发布会表单-->

        <div class="page-header" style="padding-top: 60px;">

            <!-- 搜索功能-->

            <div id="navbar" class="navbar-collapse collapse">

                <form class="navbar-form" method="get" action="/search_phone/">

                    <div class="form-group">

                        <input name="phone" type="text" placeholder="手机号" class="form-control">

                    </div>

                    <button type="submit" class="btn btn-success">搜索</button>

                </form>

            </div><!--/.navbar-collapse -->

        </div>

        <!--嘉宾列表 -->

        <div class="row" style="padding-top: 80px;">

            <div class="col-md-6">

                <table class="table table-striped">

                    <thead>

                    <tr>

                        <th>id</th>

                        <th>名称</th>

                        <th>手机</th>

                        <th>Email</th>

                        <th>签到</th>

                        <th>发布会id</th>

                    </tr>

                    </thead>

                    <tbody>

                    {% for guest in guests %}

                        <tr>

                            <td>{{ guest.id }}</td>

                            <td>{{ guest.realname }}</td>

                            <td>{{ guest.phone }}</td>

                            <td>{{ guest.email }}</td>

                            <td>{{ guest.sign }}</td>

                            <td>{{ guest.event }}</td>

                        </tr>

                    {% endfor %}

                    </tbody>

                </table>

            </div>

        </div>

      <!-- 列表分页器 -->

        <div class="pagination">

          <span class="step-links">

            {% if guests.has_previous %}

              <a href="?phone={{ phone }}&page={{ guests.previous_page_number }}">previous</a>

            {% endif %}

              <span class="current">

                Page {{ guests.number }} of {{ guests.paginator.num_pages }}.

              </span>

            {% if guests.has_next %}

              {% if phone %}

                <a href="?phone={{ phone }}&page={{ guests.next_page_number }}">next</a>

              {% else %}

               <a href="?page={{ guests.next_page_number }}">next</a>

              {% endif %}

            {% endif %}

          </span>

        </div>

    </body>

</html>

2./guest/urls.py 文件中添加嘉宾路径的路由

re_path(r'^guest_manage/$',views.guest_manage),

re_path(r'^search_phone/$',views.search_phone),

3.views.py 文件,创建 guest_manage()视图函数

from cmdb.models import Event,Guest

# 嘉宾管理

@login_required

def guest_manage(request):

    username = request.session.get('user', '')

    guest_list = Guest.objects.all()

    return render(request, "guest_manage.html", {"user": username,

                                                 "guests": guest_list})

#嘉宾手机号搜索

@login_required

def search_phone(request):

    username = request.session.get('user', '')

    search_phone = request.GET.get("phone", "")

    guest_list = Guest.objects.filter(phone__contains=search_phone)

    return render(request, "guest_manage.html", {"user": username,

                                                 "guests": guest_list})

运行:

4.分页,修改views.py

from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger

# 嘉宾管理

@login_required

def guest_manage(request):

    username = request.session.get('user', '')

    guest_list = Guest.objects.all()

    paginator = Paginator(guest_list, 2)

    page = request.GET.get('page')

    try:

        contacts = paginator.page(page)

    except PageNotAnInteger:

        contacts = paginator.page(1)

    except EmptyPage:

        contacts = paginator.page(paginator.num_pages)

    return render(request, "guest_manage.html", {"user": username,

                                                 "guests": contacts})

运行:

4.签到

1.templates/event_manage.html 页面增加签到链接

<td> <a href="/sign_index/{{ event.id }}/" target="{{ event.id }}_blank"> sign</a> </td>

注释:当点击 sign 链接时,路径会默认跳转到“/sign_index/{{event.id }}/”路径。其中{{event.id}} 为发布会 的 id。target="{{event.id}}_blank" 属性表示链接在新窗口打开。

2./guest/urls.py 文件中添加路径路由。

re_path(r'^sign_index/(?P<event_id>[0-9]+)/$', views.sign_index),

注释:(?P<event_id>[0-9]+) 配置二级目录,发布会 id,要求必须为数字。而且匹配的数字,将会作为 sign_index() 视图函数的参数。

3./sign/views.py 文件,创建 sign_index()视图函数

from django.shortcuts import render,get_object_or_404

#签到页面

@login_required

def sign_index(request,event_id):

    event=get_object_or_404(Event,id=event_id)

return render(request,'sign_index.html',{'event':event})

4.创建.../templates/sign_index.html 签到页面

<!DOCTYPE html>

<html lang="en">

<head>

    {% load bootstrap3 %}

    {% bootstrap_css %}

    {% bootstrap_javascript %}

    <meta charset="UTF-8">

    <title>签到</title>

</head>

<body>

    <!-- 导航栏 -->

    <nav class="navbar navbar-inverse navbar-fixed-top">

      <div class="container">

        <div class="navbar-header">

          <a class="navbar-brand" href="#">{{ event.name }}</a>

        </div>

        <div id="navbar" class="collapse navbar-collapse">

          <ul class="nav navbar-nav">

            <li><a href="/event_manage/">发布会</a></li>

            <li><a href="/guest_manage/">嘉宾</a></li>

          </ul>

        </div><!--/.nav-collapse -->

      </div>

    </nav>

      <!--签到表单-->

      <div class="page-header" style="padding-top: 80px;">

          <div id="navbar" class="navbar-collapse collapse">

          <form  class="navbar-form" action="/sign_index_action/{{ event.id }}/" method="post">

          <div class="input-group">

            <input type="text" class="form-control" placeholder="输入手机号" name="phone">

              </div>

            <button type="submit" class="btn btn-success">签到</button><br>

              <font color="#663399">

                 <br>{{ hint }}

                  <br>{{ guest.realname }}

                  <br>{{ guest.phone }}

              </font>

          </form>

        </div><!-- /.col-lg-6 -->

      </div><!-- /.row -->

    </div>

</body>

</html>

运行:

5.签到动作

1.guest/urls.py 文件,添加签到路径的路由

re_path(r'^sign_index_action/(?P<event_id>[0-9]+)/$', views.sign_index_action),

2.sign/views.py 文件,创建 sign_index_action()视图函数

# 签到动作

@login_required

def sign_index_action(request,event_id):

    event = get_object_or_404(Event, id=event_id)

    phone = request.POST.get('phone','')

    result = Guest.objects.filter(phone = phone)

    if not result:

        return render(request, 'sign_index.html', {'event': event,

                                                   'hint': 'phone error.'})

    result = Guest.objects.filter(phone=phone,event_id=event_id)

    if not result:

        return render(request, 'sign_index.html', {'event': event,

                                                       'hint':'eventidorphoneerror.'})

    result = Guest.objects.get(phone=phone,event_id=event_id)

    if result.sign:

        return render(request, 'sign_index.html', {'event': event,

                                                           'hint': "user has sign in."})

    else:

        Guest.objects.filter(phone=phone,event_id=event_id).update(sign = '')

        return render(request, 'sign_index.html', {'event': event,

                                                           'hint':'sign in success!',

                                                           'guest': result})

注释:查询 Guest 表判断用户输入的手机号是否存在,如果不存在将提示用户“手机号为空或不存在”。

然后,通过手机和发布会 id 两个条件来查询 Guest 表,如果结果为空将提示用户“该用户未参加此次发布会”。最后,再通过手机号查询 Guest 表,判断该手机号的签到状态是否为 1,如果为 1,表示已经签过到了, 返回用户“已签到”,否则,将提示用户“签到成功!”,并返回签到用户的信息。

3.修改.../templates/sign_index.html 页面,增加 sign_index_action()视图函数返回的提示信息的位置。

运行:

5.退出登录

1./urls.py 文件,添加退出目录的路由

re_path(r'^logout/$', views.logout),

2./views.py 文件,创建 logout()视图函数

# 退出登录

@login_required

def logout(request):

auth.logout(request) #退出登录

response = HttpResponsePermanentRedirect('/index/')

return response

8、Django测试

1.unittest framework

单元测试:unittest

HTTP 接口自动化测试:unittest+Requests

WebUI 自动化测试:unittest+Selenium

移动自动化测试:unittest+Appium

1.Django 的单元测试使用 Python 标准库模块:unittest。该模块定义使用基于类的方法测试。在我们创建 Django 应用时,默认已经帮我们生成了 tests.py 文件,打开.../sign/tests.py 文件,编写测试如下代码:

from django.test import TestCase

from cmdb.models import Event,Guest

from datetime import datetime

from django.contrib.auth.models import User

'''

# Create your tests here.

class ModelTest(TestCase):          #创建ModelTest类,继承django.test的TestCase类

    #模型测试

    #在 setUp()初始化方法中,创建一条发布会和嘉宾数据

    def setUp(self):

        Event.objects.create(id=1, name="oneplus 3 event", status=True, limit=2000,

                             address='shenzhen', start_time='2016-08-31 02:18:22')

        Guest.objects.create(id=1,event_id=1, realname='huahua',

                             phone='13711001101',email='alen@mail.com', sign=False)

    def test_event_models(self):

        #测试发布会表

        result = Event.objects.get(name="oneplus 3 event")

        self.assertEqual(result.address, "shanghai")

        self.assertTrue(result.status)

    def test_guest_models(self):

        #测试嘉宾表

        result = Guest.objects.get(phone='17322222222')

        self.assertEqual(result.realname, "huahua")

        self.assertFalse(result.sign)

'''

class IndexPageTest(TestCase):

    #测试index登录首页

    def test_index_page_renders_index_template(self):

        #断言是否用给定的index.html模版响应

        response = self.client.get('/index/')      #client.get()方法从TestCase父类继承而来,用于请求一个路径,

        self.assertEqual(response.status_code, 200)   #assertEqual()服务器对客户端的应答是否 为 200,

        self.assertTemplateUsed(response, 'index.html')  #assertTemplateUsed()断言是否用给定的是 index.html模版响应

'''

class LoginActionTest(TestCase):

    #测试登录动作

    def setUp(self):

        User.objects.create_user('admin', 'admin@mail.com', 'admin123456')

    def test_add_author_email(self):

        #测试添加用户 #

        user = User.objects.get(username="admin")

        self.assertEqual(user.username, "admin")

        self.assertEqual(user.email, "admin@mail.com")

    def test_login_action_username_password_null(self):

        # 用户名密码为空

        response = self.client.post('/login_action/', {'username': '', 'password': ''})

        self.assertEqual(response.status_code, 200)

        self.assertIn(b"username or password null!", response.content)

    def test_login_action_username_password_error(self):

        # 用户名密码错误

        response = self.client.post('/login_action/', {'username': 'abc', 'password': '123'})

        self.assertEqual(response.status_code, 200)

        self.assertIn(b"username or password error!", response.content)

    def test_login_action_success(self):

        #登录成功

        response = self.client.post('/login_action/', data={'username': 'admin', 'password': 'admin123456'})

        self.assertEqual(response.status_code, 302)

class EventMangeTest(TestCase):

    # 发布会管理

    def setUp(self):

        User.objects.create_user('admin', 'admin@mail.com', 'admin123456')

        Event.objects.create(name="xiaomi5", limit=2000, address='beijing', status=1, start_time='2017-8-10 12:30:00')

        login_user = {'username': 'admin', 'password': 'admin123456'}

        self.client.post('/login_action/', data=login_user)  # 预先登录

    def test_add_event_data(self):

        #测试添加发布会

        event = Event.objects.get(name="xiaomi5")

        self.assertEqual(event.address, "beijing")

    def test_event_mange_success(self):

       # 测试发布会:xiaomi5

        response = self.client.post('/event_manage/')

        self.assertEqual(response.status_code, 200)

        self.assertIn(b"xiaomi5", response.content)

        self.assertIn(b"beijing", response.content)

    def test_event_mange_search_success(self):

        # 测试发布会搜索

        response = self.client.post('/search_name/', {"name": "xiaomi5"})

        self.assertEqual(response.status_code, 200)

        self.assertIn(b"xiaomi5", response.content)

        self.assertIn(b"beijing", response.content)

class GuestManageTest(TestCase):

    # 嘉宾管理

    def setUp(self):

        User.objects.create_user('admin', 'admin@mail.com', 'admin123456')

        Event.objects.create(id=1,name="xiaomi5", limit=2000, address='beijing', status=1, start_time='2017-8-10 12:30:00')

        Guest.objects.create(realname="alen", phone=18611001100,email='alen@mail.com', sign=0, event_id=1)

        login_user = {'username': 'admin', 'password': 'admin123456'}

        self.client.post('/login_action/', data=login_user)  # 预先登录

    def test_add_guest_data(self):

        # 测试添加嘉宾

        guest = Guest.objects.get(realname="alen")

        self.assertEqual(guest.phone, "18611001100")

        self.assertEqual(guest.email, "alen@mail.com")

        self.assertFalse(guest.sign)

    def test_event_mange_success(self):

        # 测试嘉宾信息: alen

        response = self.client.post('/guest_manage/')

        self.assertEqual(response.status_code, 200)

        self.assertIn(b"alen", response.content)

        self.assertIn(b"18611001100", response.content)

    def test_guest_mange_search_success(self):

        #测试嘉宾搜索

        response = self.client.post('/search_phone/',{"phone":"18611001100"})

        self.assertEqual(response.status_code, 200)

        self.assertIn(b"alen", response.content)

        self.assertIn(b"18611001100", response.content)

class SignIndexActionTest(TestCase):

    # 发布会签到

    def setUp(self):

        User.objects.create_user('admin', 'admin@mail.com', 'admin123456')

        Event.objects.create(id=1, name="xiaomi5", limit=2000, address='beijing', status=1, start_time='2017-8-10 12:30:00')

        Event.objects.create(id=2, name="oneplus4", limit=2000, address='shenzhen', status=1, start_time='2017-6-10 12:30:00')

        Guest.objects.create(realname="alen", phone=18611001100, email='alen@mail.com', sign=0, event_id=1)

        Guest.objects.create(realname="una", phone=18611001101, email='una@mail.com', sign=1, event_id=2)

        login_user = {'username': 'admin', 'password': 'admin123456'}

        self.client.post('/login_action/', data=login_user)

    def test_sign_index_action_phone_null(self):

        #手机号为空

        response = self.client.post('/sign_index_action/1/', {"phone": ""})

        self.assertEqual(response.status_code, 200)

        self.assertIn(b"phone error.", response.content)

    def test_sign_index_action_phone_or_event_id_error(self):

        # 手机号或发布会id错误

        response = self.client.post('/sign_index_action/2/', {"phone": "18611001100"})

        self.assertEqual(response.status_code, 200)

        self.assertIn(b"event id or phone error.", response.content)

    def test_sign_index_action_user_sign_has(self):

        # 用户已签到

        response = self.client.post('/sign_index_action/2/', {"phone": "18611001101"})

        self.assertEqual(response.status_code, 200)

        self.assertIn(b"user has sign in.", response.content)

    def test_sign_index_action_sign_success(self):

        # 签到成功

        response = self.client.post('/sign_index_action/1/', {"phone": "18611001100"})

        self.assertEqual(response.status_code, 200)

        self.assertIn(b"sign in success!", response.content)

'''

'''

切换到项目的根目录下,通过 manage.py 所提供的“test”命令运行测试

测试运行命令方式:

1、运行所有用例:

python manage.py test

2、运行cmdb应用下的所有用例:

python manage.py test cmdb

3、运行cmdb应用下的tests.py文件用例:

python manage.py test cmdb.tests

4、运行 cmdb 应用 tests.py 测试文件下的 ModelTest 测试类

python manage.py test sign.tests.ModelTest

5、执行 ModelTest 测试类下面的 test_event_models 测试方法(用例):

python manage.py test sign.tests.ModelTest.test_event_models

6、使用 -p (或 --pattern)参数模糊匹配测试文件

>python manage.py test -p test*.py

......

'''

运行D:\guest>python manage.py test

2.其中发现两个错误和解决办法

1.C:\Users\12978\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pymysql\cursors.py:170: Warning: (3135, "'NO_ZERO_DATE', 'NO_ZERO_IN_DATE' and 'ERROR_FOR_DIVISION

_BY_ZERO' sql modes should be used with strict mode. They will be merged with strict mode in a future release.")

result = self._query(query)

C:\Users\12978\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pymysql\cursors.py:170: Warning: (3090, "Changing sql mode 'NO_AUTO_CREATE_USER' is deprecated. It

will be removed in a future release.")

result = self._query(query)

解决办法:

2.报错信息解决方案:

Django还有一些warning打印出来:/Users/jay/workspace/te/env/lib/python2.7/site-packages/django/db/models/fields/__init__.py:903: RuntimeWarning: DateTimeField TestSuite.update_time received a naive datetime (2014-06-15 14:38:37.873873) while time zone support is active. RuntimeWarning)

这个warning的原因是,Django配置为使用timezone的datetime格式,而datetime.now是不包含timezone信息的。

如果不需要在程序中特别处理时区(timezone-aware),在Django项目的settings.py文件中,可以直接设置为“USE_TZ = False”就省心了。然后,在models.py中简单的设置为“ create_time = models.DateTimeField(auto_now_add=True)”和“update_time = models.DateTimeField(auto_now=True)”。

如还要保持USE_TZ=True,则可设置为“default=datetime.now().replace(tzinfo=utc)” 。

django1的更多相关文章

  1. python版本随意切换之python2.7+django1.8.7+uwsgi+nginx源码包部署。

    资源准备: wget https://www.python.org/ftp/python/2.7.13/Python-2.7.13.tgz wget https://www.djangoproject ...

  2. django开发个人简易Blog—nginx+uwsgin+django1.6+mysql 部署到CentOS6.5

    前面说完了此项目的创建及数据模型设计的过程.如果未看过,可以到这里查看,并且项目源码已经放大到github上,可以去这里下载. 代码也已经部署到sina sea上,地址为http://fengzhen ...

  3. [Django]Django1.8修改MySQL已存在表的问题?

    前言:django1.8版本出现这种问题,关于标题不好命令,直接看正文问题描述! 问题描述: 在已经生成了models.py中表的情况下,更改了modes.py中的表,但是syncdb不起作用报错.于 ...

  4. WIN7下django1.8下载安装

    前言:公司电脑上django是在pycharm上下载自动安装的,家里电脑没安pycharm,所以自己手动安装. django下载地址:https://www.djangoproject.com/dow ...

  5. django1.9 + uwsgi +nginx1.9 部署(centos6.6)

    django1.9 + uwsgi +nginx1.9 部署 官方介绍 https://uwsgi.readthedocs.io/en/latest/tutorials/Django_and_ngin ...

  6. Django1.9开发博客(14)- 集成Xadmin

    xadmin是一个django的管理后台实现,使用了更加灵活的架构设计及Bootstrap UI框架, 目的是替换现有的admin,国人开发,有许多新的特性: 兼容 Django Admin 使用 B ...

  7. Django1.9开发博客(10)- 全文搜索

    Django本身不提供全文检索的功能,但django-haystack为其提供了全文检索的框架. django-haystack能为Django提供whoosh,solr,Xapian和Elastic ...

  8. 利用pip8.1.2 安装django1.9.7

    把python2升级到python3之后,利用pip安装django1.9.7时报错: DistributionNotFound: The 'pip==7.1.0' distribution was ...

  9. django1.7取消syncdb后不能创建model相应表的问题

    一.在运行一个django程序时,无法创建自定义model相应的表. 我检查seetings.py文件,发现自定义的app,blog已经写到INSTALLED_APPS中, INSTALLED_APP ...

  10. Django1.10环境安装

    在Ubuntu14上 一 安装脚本 wget https://github.com/django/django/archive/master.tar.gz apt-get install python ...

随机推荐

  1. 实验二《Java面向对象程序设计》的一点说明

    实验二<Java面向对象程序设计>的一点说明 本周的实验要求是: 完成实验二<Java面向对象程序设计>中的内容 其中Eclipse相关的内容参考Intellj IDEA 简易 ...

  2. abap test msg

  3. (转)Golang--使用iota(常量计数器)

    iota是golang语言的常量计数器,只能在常量的表达式中使用. iota在const关键字出现时将被重置为0(const内部的第一行之前),const中每新增一行常量声明将使iota计数一次(io ...

  4. Micro和Macro性能学习【转载】

    转自:https://datascience.stackexchange.com/questions/15989/micro-average-vs-macro-average-performance- ...

  5. Windows 下运行Makefile文件

    下载并安装Microsoft Visual Studio2017 配置环境变量: 计算机右击-属性-高级系统设置-环境变量-选择Path编辑-添加nmake的路径: D:\Microsoft Visu ...

  6. Kafka笔记1(初步认识)

    Kafka 被称为“分布式提交日志”或“分布式流平台” 文件系统或数据库提交日志用来提供所有事务的持久记录,通过重放这些日志重建系统状态,同时Kafka数据是按照一定顺序持久化保存的,可以按需读取 K ...

  7. CentOS 7 nginx+tomcat9 session处理方案之session保持

    Session保持(会话保持)是我们见到最多的名词之一,通过会话保持,负载均衡进行请求分发的时候保证每个客户端固定的访问到后端的同一台应用服务器.会话保持方案在所有的负载均衡都有对应的实现.而且这是在 ...

  8. fcrackzip (zip密码破解工具)

    现在做一个例子,首先生成一个带有密码的zip的包 zip -P hujhh test.zip test1.txt test2,txt 可以看到密码是5位的纯字母 现在就用我们的这个软件开始破解 fcr ...

  9. mongodb 安装遇到问题:the domain,user name and/or password are incorrect.remember to use"." for the domain if the account is on the local machine

    安装mongoDB遇到如下问题:the domain,user name  and/or password are incorrect.remember to use"." for ...

  10. mock基本使用

    **一.mock解决的问题** 开发时,后端还没完成数据输出,前端只好写静态模拟数据.数据太长了,将数据写在js文件里,完成后挨个改url.某些逻辑复杂的代码,加入或去除模拟数据时得小心翼翼.想要尽可 ...