zoukankan      html  css  js  c++  java
  • django1

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

     *   ┏┓   ┏┓

     *  ┏┛┻━━━┛┻┓

     *  ┃   王   ┃

     *  ┃         ┃

     *  ┃ ┳┛ ┗┳ ┃

     *  ┃       ┃

     *  ┃   ┻   ┃

     *  ┃       ┃

     *  ┗━┓   ┏━┛

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

     *    ┃   ┃

     *    ┃   ┗━━━┓

     *    ┃       ┣┓

     *    ┃       ┏┛

     *    ┗┓┓┏━┳┓┏┛

     *     ┃┫┫ ┃┫┫

     *     ┗┻┛ ┗┻┛

     *</pre>

    本练习作者源于虫师

    1、环境配置

    1. 安装django

    pip install django   

    1. 配置环境变量

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

    C:Users12978AppDataLocalProgramsPythonPython36-32Scripts

    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 ”是为了防止字符串中出现类似“ ”字符时被转义。

    ^ 匹配字符串开头;在多行模式中匹配每一行的开头。 ^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("102")

    运行后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=='123':
    
                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=='123':
    
                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

    sessioncookie的作用都是为了存储用户相关的信息。不同的是,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=='123':
    
            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_deleteCASCADEPROTECTSET_NULLSET_DEFAULTSET()五个可选择的值
    CASCADE:此值设置,是级联删除。
    PROTECT:此值设置,是会报完整性错误。
    SET_NULL:此值设置,会把外键设置为null,前提是允许为null
    SET_DEFAULT:此值设置,会把设置为外键的默认值。
    SET():此值设置,会调用外面的值,可以是一个函数。
    一般情况下使用CASCADE就可以了。

    修改后再次执行命令:

     

    2)命令2python 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()    #获得 tableEventGues 表)中的所有对象。

     

    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': '3306',
    
            '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=" 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 = '1')
    
            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:Users12978AppDataLocalProgramsPythonPython36-32libsite-packagespymysqlcursors.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:Users12978AppDataLocalProgramsPythonPython36-32libsite-packagespymysqlcursors.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)” 。

     

  • 相关阅读:
    2019-9-2-一个好的程序员
    2019-9-2-一个好的程序员
    2018-2-13-wpf-GifBitmapDecoder-解析-gif-格式
    2018-2-13-wpf-GifBitmapDecoder-解析-gif-格式
    2019-5-31-SharpDx-进入全屏模式
    2019-5-31-SharpDx-进入全屏模式
    2019-8-31-dotnet-删除只读文件
    2019-8-31-dotnet-删除只读文件
    PHP mysqli_real_connect() 函数
    PHP mysqli_query() 函数
  • 原文地址:https://www.cnblogs.com/huaerye/p/9774351.html
Copyright © 2011-2022 走看看