django养生

作者: riverstation | 来源:发表于2018-07-06 08:47 被阅读221次
    模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个准则就是高内聚低耦合。

    Django 安装

    Windows下安装 Django

    如果你还未安装Python环境需要先下载Python安装包。

    1、Python 下载地址:https://www.python.org/downloads/

    2、Django 下载地址:https://www.djangoproject.com/download/

    注意:目前Django 1.6.x以上版本已经完全兼容Python 3.x。

    Django 安装

    下载 Django 压缩包,解压并和Python安装目录放在同一个根目录,进入 Django 目录,执行python setup.py install,然后开始安装,Django将要被安装到Python的Lib下site-packages。

    [图片上传失败...(image-697485-1530838002396)]

    然后是配置环境变量,将这几个目录添加到系统环境变量中: C:\Python33\Lib\site-packages\django;C:\Python33\Scripts。 添加完成后就可以使用Django的django-admin.py命令新建工程了

    [图片上传失败...(image-a01c57-1530838002396)]

    Linux 上安装 Django

    yum 安装方法

    以下安装位于 Centos Linux 环境下安装,如果是你的 Linux 系统是 ubuntu 请使用 apt-get 命令。

    默认情况下 Linux 环境已经支持了Python。你可以在终端输入Python命令来查看是否已经安装。

    Python 2.7.3 (default, Aug  1 2012, 05:14:39) 
    [GCC 4.6.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> 
    

    安装 setuptools

    命令:

    yum install python-setuptools
    

    完成之后,就可以使用 easy_install 命令安装 django

    easy_install django
    

    之后我们在python解释器输入以下代码:

    [root@solar django]# python
    Python 2.7.3 (default, May 15 2014, 14:49:08)
    [GCC 4.8.0] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import django
    >>> django.VERSION
    (1, 6, 5, 'final', 0)
    >>>
    

    我们可以看到输出了Django的版本号,说明安装成功。

    Windows下安装django

    pip 命令安装方法

    pip install Django
    

    如果 pip < 1.4,安装方法如下:

    pip install https://www.djangoproject.com/download/1.11a1/tarball/
    

    Django与Python版本对应的关系

    [图片上传失败...(image-c8fe70-1530838002396)]

    安装Django 1.11.4

    pip install Django==1.11.4
    

    检查是否安装成功

    输入以下命令进行检查:

    >>> import django
    >>> django.get_version()  #获取当前的版本号
    

    [图片上传失败...(image-9beef2-1530838002396)]

    如果输出了Django的版本号说明安装正确。


    创建Django项目

    创建第一个项目

    使用 django-admin 来创建 HelloWorld 项目:

    在合适位置创建一个目录

    打开黑屏终端进入到上一步创建的目录下

    django-admin startproject HelloWorld(项目名)
    

    创建完成后我们可以查看下项目的目录结构:

    $ cd HelloWorld/
    $ tree
    |-- HelloWorld
    |   |-- __init__.py
    |   |-- settings.py
    |   |-- urls.
    |   `-- wsgi.py
    `-- manage.py
    

    目录说明:

    • HelloWorld: 项目的容器。
    • manage.py: 一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。
    • HelloWorld/init.py: 一个空文件,告诉 Python 该目录是一个 Python 包。
    • HelloWorld/settings.py: 该 Django 项目的设置/配置。
    • HelloWorld/urls.py: 该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"。
    • HelloWorld/wsgi.py: 一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目。

    接下来我们进入 HelloWorld 目录输入以下命令,启动服务器:

    python manage.py runserver 0.0.0.0:8000
    

    启动django后,不能访问,报400错误。

    原因:没有开启允许访问

    处理:编辑HelloWorld目录下setting.py ,把其中的

    ALLOWED_HOSTS=[]改成ALLOWED_HOSTS=['*'] ##* 表示任意地址。

    Django 模型

    Django 对各种数据库提供了很好的支持,包括:PostgreSQL、MySQL、SQLite、Oracle。

    Django 为这些数据库提供了统一的调用API。 我们可以根据自己业务需求选择不同的数据库。

    MySQL 是 Web 应用中最常用的数据库。

    数据库配置

    修改项目的__init__ 的文件 添加

    import pymysql
    pymysql.install_as_MySQLdb()
    

    我们在项目的 settings.py 文件中找到 DATABASES 配置项,将其信息修改为:

    HelloWorld/HelloWorld/settings.py: 文件代码:82行
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',  # 或者使用 mysql.connector.django
            'NAME': '数据库名称',
            'USER': '用户名',
            'PASSWORD': '密码',
            'HOST':'主机名',
            'PORT':'端口号',
        }
    }
    

    这里添加了中文注释,所以你需要在 HelloWorld/settings.py 文件头部添加 # -*- coding: UTF-8 --*。

    上面包含数据库名称和用户的信息,它们与 MySQL 中对应数据库和用户的设置相同。Django 根据这一设置,与 MySQL 中相应的数据库和用户连接起来。


    定义模型

    创建 APP

    Django规定,如果要使用模型,必须要创建一个app。我们使用以下命令创建一个 TestModel 的 app:

    django-admin startapp TestModel
    

    目录结构如下:

    HelloWorld
    |-- TestModel
    |   |-- __init__.py 
    |   |-- admin.py  配置后台
    |   |-- models.py 模型
    |   |-- tests.py  测试
    |   `-- views.py  视图
    

    设计表

    班级表结构 grades
    
    班级名称   gname                 
    成立时间   gdate                 
    女生总数  ggirlnum               
    男生总数  gboynum                
    是否删除  isDelelte              
                                   
                                   
    学生表结构  students
    
    学生姓名  sname 
    学生性别  ssex
    学生年龄  sage
    学生简介  scontend
    是否删除 isDelete                          
    

    我们修改 TestModel/models.py 文件,代码如下:

    HelloWorld/TestModel/models.py: 文件代码:
    # models.py
    from django.db import models
    
    class Grades(models.Model):
        gname = models.CharField(max_length=20)
        gdate = models.DateTimeField()
        ggirlnum = models.IntegerField()
        gboynum = models.IntegerField()
        isdelete = models.BooleanField(default=False)
    
    class Students(models.Model):
        sname = models.CharField(max_length=20)
        ssex = models.BooleanField(default=True)
        sage = models.IntegerField()
        scontented = models.CharField(max_length=20)
        isdelete = models.BooleanField(default=False)
        sgrade = models.ForeignKey("Grades")
    

    以上的类名代表了数据库表名,且继承了models.Model,类里面的字段代表数据表中的字段(name),数据类型则由CharField(相当于varchar)DateField(相当于datetime), max_length 参数限定长度。

    在settings.py文件中,将TestModel应用加入到INSTALLED_APPS选项中

    接下来在settings.py中找到INSTALLED_APPS这一项,如下:

    INSTALLED_APPS = (
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'TestModel',               # 添加此项 你的项目名称
    )
    
    在命令行中运行:
    $ python manage.py makemigrations TestModel  # 让 Django 知道我们在我们的模型有一些变更 #在migrations目录下生成一个迁移文件,此时数据库中还没有生成数据表
    $ python manage.py migrate   #m 创建表结构
    #$ python manage.py migrate TestModel   # 创建表结构
    
    看到几行 "Creating table…" 的字样,你的数据表就创建好了。
    Creating tables ...
    ……
    Creating table TestModel_test  #我们自定义的表
    ……
    

    表名组成结构为:应用名_类名(如:TestModel_test)。

    注意:尽管我们没有在models给表设置主键,但是Django会自动添加一个id作为主键。

    测试数据库

    (一) 进入到python shell

    执行 python manage.py shell

    (二) 引入包

    from  myApp.models  import  Grades,Students #导入models的类
    from  django.utils  import  timezone #导入时区(如果存在写入时间的字段)
    #from  datetime import  * #导入时间模块
    

    (三) 查询所有数据

    类名.objects.all()

    如 :Grades.objects.all()

    (四) 添加数据

    对象 = 类名()

    如: g = Grades()

    g.字段名 = 值

    保存

    g.save()

    注意:如果给gdate添加时间应该设置为 timezone.now() 否则会报错

    解决办法:

    g.gdate = timezone.now()

    [图片上传失败...(image-493dab-1530838002396)]

    (五) 查看某个对象

    类名.objects.get(pk=2) #pk 相当于自增id

    如果返回的是对象 那么在models里面的类 添加

    def __str__(self):
       return self.sname
    

    (六) 修改数据

    模型对象.属性 = 新值

    如 : g = Grades.objects.get(pk=2)

    g.字段名= 值

    g.save()

    (七) 删除数据

    模型对象.delete()

    如 : g = Grades.objects.get(pk=2)

    g.delete()

    注意:物理删除,数据库中的表里的数据被删除了

    (八) 给关联的表添加数据

    >>> stu = Students()
    >>> stu.sname = "薛艳梅"
    >>> stu.sgender = False
    >>> stu.sage = 20
    >>> stu.scontend = "我叫薛艳梅"
    >>> stu.sgrade = grade1 #为表 grade1对象  grade1 = Grades.objects.get(pk=1)或者 直接等于grade的自增id
    >>> stu.save()
    

    (九) 关联对象

    获得关联对象的集合

    需求:获取python04班级的所有学生

    如:
    g = Grades.objects.get(pk=1)
    g.students_set.all() #获取所有g表关联Students表里面所有的数据  类名首字母小写
    格式:对象.类名_set.all()
    

    Admin站点管理

    一 配置Admin应用

    在settinngs.py文件中的INSTALLED_APPS中添加'django.contrib.admin' 默认是已经添加好的

    二 创建管理员用户

    执行 python manage.py createsuperuser

    依次输入用户名、邮箱、密码

    三 配置中国的时区

    修改settings.py文件

    LANGUAGE_CODE = 'zh-Hans'

    TIME_ZONE = 'Asia/Shanghai'

    四 管理数据表

    (1) 修改admin.py文件 配置后台显示页面

    from .models import Grades,Students
    # 注册
    admin.site.register(Grades)
    admin.site.register(Students)
    

    (2) 配置后台成绩的页面显示

    from .models import Grades,Students
    # 注册
    class GradesAdmin(admin.ModelAdmin):
        #列表页属性
        #显示字段
        list_display = ['pk', 'gname', 'gdate', 'ggirlnum', 'gboynum', 'isdelete']
        #过滤字段
        list_filter = ['gname']
        #搜索字段
        search_fields = ['gname']
        #分页
        list_per_page = 5
        # 添加、修改数据的时候  属性的先后顺序
        # fields = ['ggirlnum','gboynum','gname','gdate','isdelete']
        #添加、修改数据的时候 给属性分组
        fieldsets = [
            ("num",{"fields":['ggirlnum','gboynum']}),
            ("base",{"fields":['gname','gdate','isdelete']}),
        ]
    admin.site.register(Grades, GradesAdmin)
    
    注意:fields与fieldsets不能同时使用

    (3) 关联对象

    需求:在创建一个班级时可以直接添加几个学生
    #TabularInline 横着显示添加学生布局 
    #StackedInline  #竖着显示添加学生的布局
    class StudentsInfo(admin.TabularInline):    
        model = Students
        extra = 2 #2带表添加的学生的个数
    class GradesAdmin(admin.ModelAdmin):
        inlines = [StudentsInfo]
    

    (4) 布尔值显示问题(显示成男女)

    class StudentsAdmin(admin.ModelAdmin):
        def gender(self):
            if self.ssex:
                return "男"
            else:
                return "女"
        #设置页面列的名称
        gender.short_description = "性别"
    
        list_display = ['pk','sname','sage',gender,'scontented','sgrade','isdelete']
        list_per_page = 10
        # 执行动作的位置 搜索框的上下位置
        actions_on_top = False
        actions_on_bottom = True
    admin.site.register(Students,StudentsAdmin)
    

    (5) 使用装饰器完成注册

    @admin.register(tudents)
    class StudentAdmin(admin.ModelAdmin):
        pass
    @admin.register(Students)
    class StudentsAdmin(admin.ModelAdmin):
        pass
    #admin.site.register(Students,StudentsAdmin)
    # admin.site.register(Grades, GradesAdmin)
    

    五 配置控制器

    概述:在django中,视图对web请求进行回应

    视图就是一个python函数,在views.py文件中定义

    (1) 定义控制器

    在myApp下的views.py

    HelloWorld
    |-- myApp
    |   |-- __init__.py
    |   |-- admin.py
    |   |-- apps.py
    |   |-- models.py
    |   |-- views.py
    |   |-- ....py
    |-- projct
    |   |-- __init__.py
    |   |-- settings.py
    |   |-- urls.py
    |   |-- urls.pyc
    |   |-- view.py
    |   |-- view.pyc
    |   |-- wsgi.py
    |   `-- wsgi.pyc
    |-- manage.py
    `-- templates
        `-- hello.html
    

    (2) 配置 urls.py 路由

    修改project目录下的urls.py文件

    from django.conf.urls import url,include
    from django.contrib import admin #导入后台登录模块
    from myApp import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls), #访问后台的路由
        #url(r'^', include('myApp.urls')), #访问在myApp中路由的文件(自定义的)
        url(r'^hello$', views.hello),
        url(r'^setdb$', views.setdb),
        url(r'^getDate$', views.getDate),
    ]
    
    在myApp下单独创建一个urls.py文件
    from django.conf.urls import url
    from myApp import views
    urlpatterns = [
        url(r'^$',views.index,name='index'),
    ]
    

    (3) HttpResponse 不通过模板 而是直接通过控制器进行返回 (一般作为调试使用)

    from django.http import HttpResponse
    from django.http import HttpResponse
    def index(request):
        return HttpResponse("我是首页")  #不通过模板 而是直接通过控制器进行返回
    

    (4) 将数据返回给视图进行渲染

    数据是字典形式

    from django.shortcuts import render #导入发送到模板的方法
    from datetime import datetime #导入时间模块
    from django.http import HttpResponse 
    from myApp.models import Grades #导入班级的类
    def hello(request):
        context = {}
        context['hello'] = 'Hello World!'
        context['bool'] = True
        context['myFor'] = 'abcdefg'
        return render(request, 'hello.html', context)
    
    # 数据库操作
    def setdb(request):
        g = Grades()
        g.gname = "python1701"
        g.gdate = datetime.now()
        g.ggirlnum = 10
        g.gboylnum = 40
        g.save()
        return HttpResponse("<p>数据添加成功!</p>") #直接进行返回
    
    def getDate(request):
        dataList = {}
        dataList['con'] = Grades.objects.all()
        return render(request,'show.html',dataList)
    

    六 配置 templates 模板

    概述:模板是HTML页面,可以根据视图中传递过来的数据进行填充

    (1)配置模板路径

    修改settings.py文件下的TEMPLATES 59行

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            # 'DIRS': [],
            'DIRS': [BASE_DIR+"/templates",]或[os.path.join(BASE_DIR,'templates')],      #配制模板路径
    

    (2) 模板语法

    <h1>{{ hello }}</h1> 双{} 代表存储的是变量

    Django 模板标签

    if/else 标签

    基本语法格式如下:

    {% if condition %}
         ... display
    {% endif %}
    

    或者:

    {% if condition1 %}
       ... display 1
    {% elif condition2 %}
       ... display 2
    {% else %}
       ... display 3
    {% endif %}
    

    根据条件判断是否输出。if/else 支持嵌套。

    {% if %} 标签接受 and , or 或者 not 关键字来对多个变量做判断 ,或者对变量取反( not ),例如:

    {% if athlete_list and coach_list %}
         athletes 和 coaches 变量都是可用的。
    {% endif %}
    
    

    for 标签

    {% for %} 允许我们在一个序列上迭代。

    与Python的 for 语句的情形类似,循环语法是 for X in Y ,Y是要迭代的序列而X是在每一个特定的循环中使用的变量名称。

    每一次循环中,模板系统会渲染在 {% for %} 和 {% endfor %} 之间的所有内容。

    例如,给定一个运动员列表 athlete_list 变量,我们可以使用下面的代码来显示这个列表:

    <ul>
    {% for athlete in athlete_list %}
        <li>{{ athlete.name }}</li>
    {% endfor %}
    </ul>
    

    给标签增加一个 reversed 使得该列表被反向迭代:

    {% for athlete in athlete_list reversed %}
    ...
    {% endfor %}
    

    可以嵌套使用 {% for %} 标签:

    {% for athlete in athlete_list %}
        <h1>{{ athlete.name }}</h1>
        <ul>
        {% for sport in athlete.sports_played %}
            <li>{{ sport }}</li>
        {% endfor %}
        </ul>
    {% endfor %}
    

    ifequal/ifnotequal 标签

    {% ifequal %} 标签比较两个值,当他们相等时,显示在 {% ifequal %} 和 {% endifequal %} 之中所有的值。

    下面的例子比较两个模板变量 user 和 currentuser :

    {% ifequal user currentuser %}
        <h1>Welcome!</h1>
    {% endifequal %}
    

    和 {% if %} 类似, {% ifequal %} 支持可选的 {% else%} 标签:

    {% ifequal section 'sitenews' %}
        <h1>Site News</h1>
    {% else %}
        <h1>No News Here</h1>
    {% endifequal %}
    

    注释标签

    Django 注释使用 {# #}。

    {# 这是一个注释 #}
    

    过滤器

    模板过滤器可以在变量被显示前修改它,过滤器使用管道字符,如下所示:

    {{ name|lower }}
    

    {{ name }} 变量被过滤器 lower 处理后,文档大写转换文本为小写。

    过滤管道可以被* 套接* ,既是说,一个过滤器管道的输出又可以作为下一个管道的输入:

    {{ my_list|first|upper }}
    

    以上实例将第一个元素并将其转化为大写。

    有些过滤器有参数。 过滤器的参数跟随冒号之后并且总是以双引号包含。 例如:

    {{ bio|truncatewords:"30" }}
    

    这个将显示变量 bio 的前30个词。

    其他过滤器:

    • addslashes : 添加反斜杠到任何反斜杠、单引号或者双引号前面。

    • date : 按指定的格式字符串参数格式化 date 或者 datetime 对象,实例:

      {{ pub_date|date:"F j, Y" }}
      
    • length : 返回变量的长度。

    include 标签

    {% include %} 标签允许在模板中包含其它的模板的内容。

    下面这个例子都包含了 nav.html 模板:

    {% include "nav.html" %}
    

    模板继承

    模板可以用继承的方式来实现复用。

    接下来我们先创建之前项目的 templates 目录中添加 base.html 文件,代码如下:

    HelloWorld/templates/base.html 文件代码:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>菜鸟教程(runoob.com)</title>
    </head>
    <body>
        <h1>Hello World!</h1>
        <p>菜鸟教程 Django 测试。</p>
        {% block mainbody %}
           <p>original</p>
        {% endblock %}
    </body>
    </html>
    

    以上代码中,名为 mainbody 的 block 标签是可以被继承者们替换掉的部分。

    所有的 {% block %} 标签告诉模板引擎,子模板可以重载这些部分。

    hello.html 中继承 base.html,并替换特定 block,hello.html 修改后的代码如下:

    {% extends "base.html" %}
    {% block mainbody %}<p>继承了 base.html 文件</p>
    {% endblock %}
    

    模型 model

    Django对各种数据库提供了很好的支持,Django为这些数据库提供了统一的调用API,可以根据不同的业务需求选择不同的数据

    一 配置数据库

    修改工程目录下的_init_.py文件

    import pymysql
    pymysql.install_as_MySQLdb()
    

    修改settings.py文件

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': "kaishen",
            'USER':'root',
            'PASSWORD':'sunck',
            'HOST':'localhost',
            'PORT':'3306',
        }
    }
    

    Zh

    二 开发流程

    1. 配置数据库

    2. 定义模型类

      一个模型类都在数据库中对应一张数据表

    3. 生成迁移文件

    4. 执行迁移生成数据表

      python manage.py makemigrations TestModel
      python manage.py migrate   # 创建表结构
      
    5. 使用模型类进行增删改查(crud)操作

    三 ORM

    概述

    对象-关系-映射

    任务

    1. 根据对象的类型生成表结构
    2. 将对象、列表的操作转换为sql语句
    3. 将sql语句查询到的结果转换为对象、列表

    优点

    极大的减轻了开发人员的工作量,不需要面对因数据库的变更而修改代码

    图解

    [图片上传失败...(image-31c2b-1530838045053)]

    四 定义模型

    (1) 模型、属性、表、字段间的关系

    一个模型类在数据库中对应一张表,在模型类中定义的属性,对应该模型对照表中的一个字段

    (2) 定义属性

    详情请见定义属性.md

    (3) 创建模型类

    (4) 元选项

    在模型类中定义Meta类,用于设置元信息

    1. db_table

      定义数据表名,推荐使用小写字母,数据表名默认为项目名小写_类名小写

    2. ordering

      对象的默认排序字段,获取对象的列表时使用

      • ordering['id'] 升序
      • ordering['-id'] 降序

      注意:排序会增加数据库的开销

    实例

    class Students(models.Model):
        sname    = models.CharField(max_length=20)
        sgender  = models.BooleanField(default=True)
        sage     = models.IntegerField(db_column="age")
        scontend = models.CharField(max_length=20)
        isDelete = models.BooleanField(default=False)
        # 关联外键
        sgrade = models.ForeignKey("Grades")
        def __str__(self):
            return self.snamea
        lastTime = models.DateTimeField(auto_now=True)
        createTime = models.DateTimeField(auto_now_add=True)
        class Meta:
            db_table="students" #手动起表名
            ordering=['id']  #按照id升序
    

    五 模型成员

    类属性

    (1) objects

    是Manager类型的一个对象,作用是与数据库进行交互

    当定义模型类是没有指定管理器,则Django为模型创建一个名为objects的管理器

    (2) 自定义管理器

    class Students(models.Model):
        # 自定义模型管理器
        # 当自定义模型管理器,objects就不存在了
        stuObj = models.Manager()
    

    当为模型指定模型管理器,Django就不在为模型类生成objects模型管理器

    (3) 自定义管理器Manager类

    模型管理器是Django的模型进行与数据库进行交互的接口,一个模型可以有多个模型管理器

    作用

    向管理器类中添加额外的方法

    修改管理器返回的原始查询集

    重写get_queryset()方法

    代码示例

    class StudentsManager(models.Manager):
        def get_queryset(self):
            return super(StudentsManager,self).get_queryset().filter(isDelete=False)#将isDelete为 False的数据进行返回
    
    class Students(models.Model):
        # 自定义模型管理器
        # 当自定义模型管理器,objects就不存在了
        stuObj = models.Manager()
        stuObj2 = StudentsManager()
    

    创建对象

    (1) 目的

    向数据库中添加数据

    当创建对象时,django不会对数据库进行读写操作,当调用save()方式时才与数据库交互,将对象保存到数据库表中

    注意:__init__方法已经在父类models.Model中使用,在自定义的模型中无法使用

    (2) 方法

    1. 在模型类中增加一个类方法

    实例

    class Students(models.Model):
        #定义一个类方法创建对象
        @classmethod
        def addStudents(cls, name, age, gender, contend, grade, isD=False):
            stu = cls(sname = name, sage = age, sgender = gender, scontend = contend, sgrade = grade, isDelete=isD)
            return stu
    
    在视图中使用
    def addStudents(request):
        g = Grades.objects.get(pk=1)
        # return HttpResponse(g)
        stu = Students.addStudents('李四',10,'0','我是类方法添加的',g)
        stu.save()
        return HttpResponse('添加完成')
    
    2. 在定义管理器中添加一个方法

    实例

    class StudentsManager(models.Manager):
        def get_queryset(self):
            return super(StudentsManager,self).get_queryset().filter(isDelete=False)
        def addStudents(self, name, age, ssex, contend, grade, lastT, createT, isD=False):
            stu = self.model()
            # print(type(grade))
            stu.sname = name
            stu.sage = age
            stu.ssex = ssex
            stu.scontend = contend
            stu.sgrade = grade
            return stu
    class Students(models.Model):
        stuObj2 = StudentsManage() #添加了自己过滤方法的类
    
    在视图中使用
    def addStudents2(request):
        g = Grades.objects.get(pk=1)
        stu = Students.stuObj2.addStudents('w1W',30,'0','我是类方法添加的',g)
        stu.save()
        return HttpResponse('***')
    

    六 模型查询

    概述

    1. 查询集表示从数据库获取的对象集合
    2. 查询集可以有多个过滤器
    3. 过滤器就是一个函数,基于所给的参数限制查询集结果
    4. 从sql角度来说,查询集合select语句等价,过滤器就像where条件

    (1) 查询集

    在管理器上调用过滤器方法返回查询集

    查询集经过过滤器筛选后返回新的查询集,所以可以写成链式调用

     Entry.objects.filter ( 
    ...     headline__startswith='What' 
    ... ).exclude( 
    ...     pub_date__gte=datetime.now() 
    ... ).filter ( 
    ...     pub_date__gte=datetime(2005, 1, 1) 
    ... ) 
    最后返回的QuerySet是headline like 'What%' and put_date<now() and pub_date>2005-01-01 
    

    惰性执行:创建查询集不会带来任何数据的访问,直到调用数据时,才会访问数据库

    QuerySet是延迟加载 
    只在使用的时候才会去访问数据库,如下: 
    >>> q = Entry.objects.filter (headline__startswith="What") 
    >>> q = q.filter (pub_date__lte=datetime.now()) 
    >>> q = q.exclude(body_text__icontains="food") 
    >>> print q 
    在print q时才会访问数据库。
    

    直接访问数据的情况

    1. 迭代
    2. 序列化
    3. 与if合用

    (2) 返回查询集的方法称为过滤器

    1. all() 返回查询集中的所有数据

    Students.stuObj2.all()  #获取Students类里面所有数据
    Students.stuObj2.all()[0:5] #获取Students类里面前5条数据数据
    Students.stuObj2.all()[(int(page)-1)*5:int(page)*5] 分页
    
    url(r'^stu/(\d+)/$', views.stupage),
    def stupage(request,page):
        dataList = {}
        dataList['stu'] = Students.stuObj2.all()[(int(page)-1)*5:int(page)*5]
    

    2. filter() 返回符合条件的数据

    得到一个集合对象
    返回一个与参数匹配的QuerySet,相当于等于(=).

    一个条件的情况

    • filter(键=值)
    多个条件 并且的关系
    • filter(键=值, 键=值)

      Students.stuObj.filter(sname__contains='孙',ssex=True)
      
    • filter(键=值).filter(键=值)

    实例

    表.objects.filter(id=2) ---[obj1,]  ,得到一个集合对象,集合里只有一个,跟上first()或者【0】取到一个具体对象
    

    3. exclude() 过滤掉符合条件的数据

    返回一个与参数不匹配的QuerySet,相当于不等于(!=)

    Students.stuObj.exclude(sname__contains='孙')  #过滤掉sname字段值包含孙的数据
    

    4. order_by(字段名) 排序

    实例

    按照id升序

    Students.stuObj2.order_by('pk')
    

    按照id降序

    Students.stuObj2.order_by('-pk')
    

    扩展

    如果需要以多个字段为标准进行排序(第二个字段会在第一个字段的值相同的情况下被使用到),使用多个参数就可以了,如下:

    Publisher.objects.order_by("state_province", "address")
     [<Publisher: Apress>, <Publisher: O'Reilly>]
    

    我们还可以指定逆向排序,在前面加一个减号 - 前缀:

    Publisher.objects.order_by("-name")
    [<Publisher: O'Reilly>, <Publisher: Apress>]
    

    尽管很灵活,但是每次都要用 order_by() 显得有点啰嗦。 大多数时间你通常只会对某些 字段进行排序。 在这种情况下,Django让你可以指定模型的缺省排序方式:

    class Publisher(models.Model):
      name = models.CharField(max_length=30)
      address = models.CharField(max_length=50)
      city = models.CharField(max_length=60)
      state_province = models.CharField(max_length=30)
      country = models.CharField(max_length=50)
      website = models.URLField()
     
      def __unicode__(self):
        return self.name
     
      class Meta:
        ordering = ['name']  #在查询数据的时候 就按照name升序
    

    现在,让我们来接触一个新的概念。 class Meta,内嵌于 Publisher 这个类的定义中(如果 class Publisher 是顶格的,那么 class Meta 在它之下要缩进4个空格--按 Python 的传统 )。你可以在任意一个 模型 类中使用 Meta 类,来设置一些与特定模型相关的选项。 在 附录B 中有 Meta 中所有可选项的完整参考,现在,我们关注 ordering 这个选项就够了。 如果你设置了这个选项,那么除非你检索时特意额外地使用了 order_by(),否则,当你使用 Django 的数据库 API 去检索时,Publisher对象的相关返回值默认地都会按 name 字段排序。

    5. reverse() 对查询结果反向排序

    注意: 需要先排序order_by(*field),才能反转

    Students.stuObj.all().order_by('pk').reverse()
    

    6. distinct() 从返回结果中剔除重复纪录

    不支持

    Students.stuObj.all().order_by('pk').distinct('sage')
    #DISTINCT ON fields is not supported by this database backend 数据库不支持
    

    7. values() 一条数据就是一个对象(字典),返回一个列表

    实例

    Students.stuObj.values() #得到QuerySet集合是所有的记录,,里面是字典,key是字段,value是值,
    

    参数:为要返回的字段名和值 (默认返回全部)

    类名.objects.values('title','price')#可以加多个字段
    

    连贯操作

    Book.objects.filter(id__gt=4).values('title')#查询id大于4,的title,得到一个对象集合,显示书名
        #<QuerySet [{'title': '富爸爸'}]>
    

    8. value_list ( )  得到一个元组格式的数据,只有字段的值,

    # ----valuelist 方法查询  ,得到一个元组格式数据,只有字段的值,
        b4 = Book.objects.filter(id__gt=3).values_list('title')
        print(b4)   
        #<QuerySet [('追风筝的人',), ('富爸爸',)]>
    

    (3) 返回单个数据

    1. get() 返回一个满足条件的对象

      注意:

      • 如果没有找到符合条件的对象,会引发"模型类.DoesNotExist"异常
      • 如果找到多个对象,会引发"模型类.MultipleObjectsReturned"异常
      Students.stuObj.get(pk=1) #查询id为1的数据
      
      >>> Entry.objects.order_by('headline')[0] 
      #这是取按headline字段排序后的第一个对象。 
      >>> Entry.objects.order_by('headline')[0:1].get () 
      #这和上面的等同的。 
      
      表.objects.get(id=2)---obj,得到一个单独的对象,确定能找到,可以用,如果找到多个或者没有的,都报错。
    2. count() 返回当前查询集中的对象个数
      Students.stuObj.filter(ssex=True).count() #性别为1的人数
      
    3. first() 返回查询集中的第一个对象
      Students.stuObj.filter(ssex=True).first()  #返回 性别为1 的第一条数据
      
      QuerySet.first(),与get()方法一样,都得到一个对象
      
    4. last() 返回查询集中的最后一个对象
      Students.stuObj.filter(ssex=True).last()  #返回 性别为1 的最后一条数据
      
      QuerySet.last(),与get()方法一样,都得到一个对象
      
    5. exists() 如果QuerySet包含数据,就返回True,否则返回False ---只判断是否有记录
      Students.stuObj.exists()
      Students.stuObj.filter(isDelete=False).exists()
      

    (4) 限制查询集

    查询集返回列表,可以使用下标的方法进行限制,等同于sql中的limit语句

    studentsList = Students.stuObj2.all()[0:5]
    
    >>> Entry.objects.order_by('headline')[0] 
    #这是取按headline字段排序后的第一个对象。 
    >>> Entry.objects.order_by('headline')[0:1].get () 
    #这和上面的等同的。
    

    注意:下标不能是负数

    (5) 查询集的缓存

    每个查询集都包含一个缓存,来最小化的对数据库访问

    在新建的查询集中,缓存首次为空,第一次对查询集求值,会发生数据缓存,django会将查询出来的数据做一个缓存,并返回查询结构,以后的查询直接使用查询集的缓存

    以下语句要查询两次数据库

    print([c.code for c in Catalog.objects.all()])
    
    print([c.name for c in Catalog.objects.all()])
    

    以下语句可以用上django的缓存机制,只用访问一次数据

    cl = Catalog.objects.all();
    print([c.code for c in cl])
    print([c.name for c in cl])
    

    最好是把所有数据,先遍历一边,在进行访问:

    cl = Catalog.objects.all();
    
    [c.code for c in cl]
    
    cl[1];  # 从缓存读数据
    
    cl[1];  # 从缓存读数据
    

    以下四种方法将对象集放进缓存

    [c for c in queryset]
    
    bool(queryset)
    
    c in queryset
    
    list(queryset)
    

    # 在对象查询集中使用数据索引要格外小心,因为每次索引都会访问1次数据库,即使是访问同一个元素。注意如下语句:

    cl = Catalog.objects.all();

    cl[1]; # 访问1次数据库

    cl[1]; # 在访问1次数据库

    (6) 字段查询

    概述

    实现了sql中的where语句,作为方法filter()、exclude()、get()的参数

    语法

    属性名称__比较运算符=值

    外键

    属性名_id

    Students.stuObj2.filter(sgrade_id=1)

    (7) 字段值修改

    update 和save方法区别

    Book.objects.filter(id=5).update(price=1000) #直接更新update 是QuerySet集合对象的方法,推荐

    save方法

    book = Book.objects.get(id=5)

    book.price=400

    book.save()


    比较运算符

    1. 完全匹配运算符
      __exact 判断,大小写敏感
      __iexact 精确等于 忽略大小写 ilike 'aaa'

      精确等于 like 'aaa'

      filter(sname_exact=False)

      Students.stuObj.filter(sname = 'aw1w') #不区分大小写
      Students.stuObj.filter(sname__exact = 'aw1w') #不区分大小写
      #等同于SELECT ... WHERE headline = 'aw1w'; 
      Students.stuObj.filter(sname__iexact = 'aw1w') #不区分大小写
      
      Blog.objects.get (id__exact=14)  # Explicit form 
      >>> Blog.objects.get (id=14)         # __exact is implied 
      这两种方式是等同的,都是查找id=14的对象。 
      

      注意,如果在exact运算符右侧指定None,那么在翻译成SQL语句时就会按照SQL中的NULL进行比较。

      Students.stuObj.filter(sname__exact=None)
      等价于SQL语法:
      select * from students where sname is null
      

    2. __contains 是否包含,大小敏感
      包含 like '%aaa%'

      __icontains 包含 忽略大小写 ilike '%aaa%',但是对于sqlite来说,contains的作用效果等同于icontains

      studentsList = Students.stuObj2.filter(sname__contains="孙") #查询sname属性中包含孙的所有数据
      Students.stuObj.filter(sname__icontains='w') #不区分大小写
      等同于SELECT ... WHERE sname LIKE '%w%'; 
      
    3. __startswith、__endswith 以value开头或结尾,大小写敏感

      __istartswith 以...开头 忽略大小写

      __iendswith 以...结尾,忽略大小写

      studentsList = Students.stuObj2.filter(sname__startswith="孙") #sname字段以孙子开头的所有数据
      studentsList = Students.stuObj2.filter(sname__endswith="孙") #sname字段以孙子结尾的所有数据
      
      #不区分大小写
      Students.stuObj.filter(sname__istartswith='a')
      Students.stuObj.filter(sname__iendswith='a')
      
      startswith 等同于sql语句中的 name like 'Lennon%', 
      endswith等同于sql语句中的 name like '%Lennon'. 
      
    以上四个在前面加上i,就表示不区分大小写iexact、icontains、istartswith、iendswith
    1. __isnull 是否为空
      __isnull=True/False
      filter(sname__isnull=False)
      
    2. __in 是否包含在范围内
      studentsList = Students.stuObj2.filter(pk__in=[2,4,6,8,10])
      #取反  not-in
      studentsList = Students.stuObj2.exclude(pk__in=[2,4,6,8,10])
      
    3. __range() 范围bettwen and
      __range(start_date, end_date)
      models.Tb1.objects.filter(id__range=[1, 2])  
      
    4. __gt、__gte、__lt、__lte 属性名__gt/gte/lt/lte
      Students.stuObj2.filter(sage__gt=30)  #年龄大于30的数据
      
    5. __year、__month、__day、__week_day、__hour、__minute、__second
      Students.stuObj2.filter(lastTime__year=2017)  #查询lastname字段的年份为2017的所有数据
      
      Entry.objects.filter (pub_date__year=2006) 
      不使用Entry.objects.all().filter (pub_date__year=2006),虽然也能运行,all()最好再获取所有的对象时使用。 
      slect * from entry where pub_date_year='2006' 
      简单日期操作
      from datetime import datetime;
      from datetime import date; 
      print(Catalog.objects.filter(create_date__year=2013));    # 时间的年份为2013年
      print(Catalog.objects.filter(create_date__gte=date.today()));    # 时间大于今天
      print(Catalog.objects.filter(create_date__gte=datetime(2013, 5, 23))); # 时间大于2013年5月23日
      print(Catalog.objects.filter(create_date__lte='2013-05-23'))  # 时间小于2013年5月23日
      

    聚合函数

    使用aggregate()函数返回聚合函数的值

    1. Avg 平均数
    2. Count 统计
    3. Max 最大
    4. Min 最小
    5. Sum 求和

    实例

    from django.db.models import Max
    from django.db.models import aggregates
    maxAge = Students.stuObj2.aggregate(Max('sage'))
    

    F对象

    可以使用模型的A属性与B属性进行比较,

    实例

    from django.db.models import F,Q
    def grades(request):
        g = Grades.objects.filter(ggirlnum__gt=F('gboynum'))
        print(g)
        return HttpResponse("打印属性值ggirlnum大于gboynfum的字段值")
    
    支持F对象的算术运算
    Grades.objects.filter(ggirlnum__gt=F('gboynum')+20)
    

    Q对象

    概述: 过滤器的方法中的关键字参数,条件为And模式

    需求: 进行or查询

    Students.stuObj2.filter(Q(pk__lte=3)) #匹配id小于等于 3的数据
    Students.stuObj.filter(Q(pk=1)| Q(pk=2)) #查询id为1 或者 为2 的所有数据
    
    用Q对象实现复杂的查询
    Q(question__startswith='Who') | Q(question__startswith='What') 
    等同于WHERE question LIKE 'Who%' OR question LIKE 'What%' 
    
    import datetime
    Poll.objects.get ( 
        Q(question__startswith='Who'), 
        Q(pub_date=datetime.date(2018,2,26)) | Q(pub_date=datetime.date(2018,2,26)) 
    ) 
    等同于SELECT * from polls WHERE question LIKE 'Who%' AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06') 
    
    取反
    Students.stuObj.filter(~Q(pk__in=[1])) #匹配id为1以外的所有数据
    

    注意

    1. id/pk/exect

      >>> Blog.objects.get (id__exact=14) # Explicit form 
      >>> Blog.objects.get (id=14) # __exact is implied 
      >>> Blog.objects.get (pk=14) # pk implies id__exact 
      等同于select * from where id=14 
      

      注意:pk代表当前的主键 而不是id

    2. 转义 %

      >>> Entry.objects.filter (headline__contains='%') 
      等同于SELECT ... WHERE headline LIKE '%\%%'; 
      
    3. Caching and QuerySets

      >>> print [e.headline for e in Entry.objects.all()] 
      >>> print [e.pub_date for e in Entry.objects.all()] 
      应改写为: 
      >> queryset = Poll.objects.all() 
      >>> print [p.headline for p in queryset] # Evaluate the query set. 
      >>> print [p.pub_date for p in queryset] # Re-use the cache from the evaluation.、 
      这样利用缓存,减少访问数据库的次数。 
      
    4. 删除

      Entry.objects.filter (pub_date__year=2005).delete() 
      

      删除所有

      Entry.objects.all().delete()
      
    5. 一次更新多个值

      # Update all the headlines with pub_date in 2007. 
      Entry.objects.filter (pub_date__year=2007).update(headline='Everything is the same') 
      
      >>> b = Blog.objects.get (pk=1) 
      # Change every Entry so that it belongs to this Blog. 
      >>> Entry.objects.all().update(blog=b) 
      
      #更改id在2,4,6的sname和ssex的值
      Students.stuObj.filter(pk__in=[2,4,6]).update(sname='张三',ssex=1)
      #更改所有的数据的字段sname和ssex的值
      Students.stuObj.all().update(sname='张三',ssex=1)
      #删除id在2,4,6的sname和ssex的值
      Students.stuObj.filter(pk__in=[2,4,6,8,10]).delete()
      
      如果用save()方法,必须一个一个进行保存,需要对其就行遍历,如下: 
      for item in my_queryset: 
          item.save() 
      
      注意:save更适合单条数据的更新 update更适合批量次的更新

    模型之间的关系

    1. 1 :1
    2. 1 :N
    3. M:N

    一、1:1

    1. 使用models.OneToOneField实现
    2. 这个字段在哪一个模型中都是可以使用的
      • 使用了OneToOne的模型,默认它会随着绑定的数据而进行变化,绑定的数据被删除,它也会被删除
    3. 添加顺序
      • OneToOne绑定的表是主表
      • 使用OneToOne的是从表
    4. on_delete
      • models.CASCADE 默认值
        默认CASECADE,默认从表数据跟随主表删除(比较暴力,容易出问题,开发中基本不用)
      • models.PROTECT 保护模式
        PROTECT,保护默认,开发中常用(主表数据有从表数据的时候,主表是不能实现删除的)
      • models.SET_NULL 置空模式
        # 在删除的时候模式有5个,默认是伴随删除,setXXX设置为某一值
        id_person = models.OneToOneField("Person", on_delete=models.SET_NULL, null=True)#注意 要设置为null为True,因为字段默认不为nully
      • SETXXX 当删除,设置对应的字段值为YYY
    5. PROTECT保护的是主表数据
    6. SETXXX 设置的是从表

    二、1:N

    1. 使用ForeignKey实现
    2. 在使用的时候也有on_delete
    3. on_delete和一对一完全一样

    三、M:N

    1. 使用ManyToMany实现
    2. 最好使用在从表中,非用户表
    3. 模型在生成数据表的时候,会生成专门的一张表来维护多对多的关系,关系表
    4. 关系表中存储的是两张表的id
    5. 关系表存储多对多的关系
    6. 主从关系
      • 使用ManyToMany的可以认为是从表
      • 从表可以管理自己的主表对应数据
      • 主表也可以而管理从表中自己对应的数据
      • 数据都是一个集合
        • add
        • remove
        • clear

    创建多对多关系实例:

    • 方式一

      from django.db import models

      class Class5(models.Model):
      name = models.CharField(max_length=32)

      class Class3(models.Model):
      name = models.CharField(max_length=32)

      class Computer(models.Model):
      c5 = models.ForeignKey("Class5")
      c3 = models.ForeignKey("Class3")1234567891011

    • 方式二

      from django.db import models

      class Class5(models.Model):
      name = models.CharField(max_length=32)

      class Class3(models.Model):
      name = models.CharField(max_length=32)
      c5 = models.ManyToManyField("Class5")12345678

    多对多关系增加数据

    以方式二为例

    from django.db import models
    
    # 先获取Class3表数据
    obj = models.Class3.objects.filter(name="xxxx").first()
    # 添加关系,与Class5中id为1的关联
    obj.c5.add(1)
    
    # obj.c5.add(1,2,3)     # 添加多个关系
    # obj.c5.add(*[1,2,3])  # 添加多个关系123456789
    

    多对多关系查询数据

    from django.db import models
    
    # 先获取Class3表数据
    obj = models.Class3.objects.filter(name="xxxx").first()
    # 获取所有与当前数据关联的Class5数据
    obj.c5.all()123456
    

    多对多关系更新

    from django.db import models
    
    # 先获取Class3表数据
    obj = models.Class3.objects.filter(name="xxxx").first()
    
    # 更新数据
    obj.c5.set([1,2,3])1234567
    

    多对多关系删除

    from django.db import models
    
    # 先获取Class3表数据
    obj = models.Class3.objects.filter(name="xxxx").first()
    
    # 删除单条数据
    obj.c5.remove(1)
    
    # 删除多条数据
    obj.c5.remove(1,2,3)    # 或者:obj.c5.remove(*[1,2,3])
    
    # 删除所有与当前数据关联的数据
    obj.c5.clear()
    

    模型继承

    1. 抽象
      • 公共特性,人和狗
      • name,legs
      • 不同的职能
      • 人享受,人做饭,狗看门,
    2. 抽象的模型,不会生成表
      • 继承自抽象模型的模型,它会在自己的表中包含抽象模型中的字段
      • 抽象的模型不能实例化(只能子类实例化)
    3. 非抽象模型,会生成自己的表
      • 非抽象模型也可以继承
      • 所有子表的公共数据会在父表中存储
      • 子表特有的属性会在自己额外的表中存储,子表和父表通过外键级联在一起

    模型中的属性

    1. 显性(自己直接创建的)
    2. 隐形的(系统为我们创建的)
    3. Manager(默认系统自动创建,对应的字段叫objects)
      • 自定义管理器
      • 继承自models.Manager
      • 定义自己的方法
        • 添加统一的删除过滤
        • 添加创建对象的方法

    ORM字段属性的使用

    定义属性

    概述
        ·django根据属性的类型确定以下信息
            ·当前选择的数据库支持字段的类型
            ·渲染管理表单时使用的默认html控件
            ·在管理站点最低限度的验证
    
        ·django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则django不会再生成默认的主键列
    
        ·属性命名限制
            ·遵循标识符规则
            ·由于django的查询方式,不允许使用连续的下划线
    

        ·定义属性时,需要字段类型,字段类型被定义在django.db.models.fields目录下,为了方便使用,被导入到django.db.models中
        ·使用方式
            ·导入from django.db import models
            ·通过models.Field创建字段类型的对象,赋值给属性
    
    逻辑删除
        ·对于重要数据都做逻辑删除,不做物理删除,实现方法是定义isDelete属性,类型为BooleanField,默认值为False
    

    字段类型

        ·AutoField
            ·一个根据实际ID自动增长的IntegerField,通常不指定如果不指定,一个主键字段将自动添加到模型中
    
        ·CharField(max_length=字符长度)
            ·字符串,默认的表单样式是 TextInput
    
        ·TextField
            ·大文本字段,一般超过4000使用,默认的表单控件是Textarea
    
        ·IntegerField
            ·整数
    
        ·DecimalField(max_digits=None, decimal_places=None)
            ·使用python的Decimal实例表示的十进制浮点数
            ·参数说明
                ·DecimalField.max_digits
                    ·位数总数
                ·DecimalField.decimal_places
                    ·小数点后的数字位数
    
        ·FloatField
            ·用Python的float实例来表示的浮点数
    
        ·BooleanField
            ·true/false 字段,此字段的默认表单控制是CheckboxInput
    
        ·NullBooleanField
            ·支持null、true、false三种值
    
        ·DateField([auto_now=False, auto_now_add=False])
            ·使用Python的datetime.date实例表示的日期
            ·参数说明
                ·DateField.auto_now
                    ·每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false
                ·DateField.auto_now_add
                    ·当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false
            ·说明
                ·该字段默认对应的表单控件是一个TextInput. 在管理员站点添加了一个JavaScript写的日历控件,和一个“Today"的快捷按钮,包含了一个额外的invalid_date错误消息键
            ·注意
                ·auto_now_add, auto_now, and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果
    
        ·TimeField
            ·使用Python的datetime.time实例表示的时间,参数同DateField
    
        ·DateTimeField
            ·使用Python的datetime.datetime实例表示的日期和时间,参数同DateField
    
        ·FileField
            ·一个上传文件的字段
    
        ·ImageField
            ·继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image
    

    字段选项

    字段选项
        ·概述
            ·通过字段选项,可以实现对字段的约束
            ·在字段对象时通过关键字参数指定
    
        ·null
            ·如果为True,Django 将空值以NULL 存储到数据库中,默认值是 False
    
        ·blanke
            ·如果为True,则该字段允许为空白,默认值是 False
    
        ·注意
            ·null是数据库范畴的概念,blank是表单验证证范畴的
    
        ·db_column
            ·字段的名称,如果未指定,则使用属性的名称
    
        ·db_index
            ·若值为 True, 则在表中会为此字段创建索引
    
        ·default
            ·默认值
    
        ·primary_key
            ·若为 True, 则该字段会成为模型的主键字段
    
        ·unique
            ·如果为 True, 这个字段在表中必须有唯一值
    

    关系

    关系
        ·分类
            ·ForeignKey:一对多,将字段定义在多的端中
            ·ManyToManyField:多对多,将字段定义在两端中
            ·OneToOneField:一对一,将字段定义在任意一端中
    
        ·用一访问多
            ·格式
                ·对象.模型类小写_set
            ·示例
                grade.students_set
    
        ·用一访问一
            ·格式
                ·对象.模型类小写
            ·示例
                ·grade.students
    
        ·访问id
            ·格式
                ·对象.属性_id
            ·示例
                ·student.sgrade_id
    

    视图 view

    一 视图的概念

    (1) 视图的作用

    视图接受web请求,并响应web请求

    (2) 视图的本质

    视图就是一个python中的函数

    (3) 响应

    1. 网页
      • 重定向
      • 错误视图
        • 404
        • 500
        • 400
    2. JSON数据

    二 url配置

    路由:

    处理URL与函数之间关系的程序称为路由

    (1) 配置流程

    制定根级url配置文件

    settings.py文件中的ROOT_URLCONF(默认实现了)

    ROOT_URLCONF = 'project.urls'
    ROOT_URLCONF = '当前Django项目名.urls'
    

    (2) urlpatterns

    一个url实例的列表

    url参数
    1. Z正则表达式
    2. 视图名称
    3. 名称 当前反向解析的name的名称
    url匹配正则的注意事项:
    1. 如果想要从url中获取一个值,需要对正则加小括号
    2. 匹配正则前方不需要加反斜杠
    3. 正则前需要加r表示字符串不转义

    实例

    urlpatterns = [
        url(r'^stu/(\d+)/$', views.stupage,name='stupage'),
    ]
    

    (3) 引入其他url配置

    在应用中创建urls.py文件,定义本应用的url配置,在工程urls.py文件中使用include()方法

    from django.conf.urls import url, include
    from django.contrib import admin
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^', include('myApp.urls', namespace="myApp"))
    ]
    
    myApp文件夹下的URL配置s
    from django.conf.urls import url
    from . import views/fsrom myApp import views  那种引入views都可以
    urlpatterns = [
        url(r'^$', views.index, name="index"),
    ]
    

    (4) URL的反向解析

    概述: 如果在视图、模板中使用了硬编码链接,在url配置发生改变时,动态生成链接的地址

    解决: 在使用链接时,通过url配置的名称,动态生成url地址

    作用于: 使用url模板

    使用方法:

    • 定义url时,需要为include定义namespace属性,为url定义name属性
    • 使用时,在模板中使用url标签,在视图中使用reverse函数,根据正则表达式动态生成地址,减轻后期维护成本。
    模板中超链接步骤:

    1)在项目urls.py中为include定义namespace属性。

    url(r’^’,include(‘booktest.urls’,namespace=’booktest’)),

    2)在应用的urls.py中为url定义name属性,并修改为fan2。

    url(r’^fan2/$’, views.fan2,name=’fan2’),

    3)在模板中使用url标签做超链接,此处为templates/booktest/fan1.html文件。

    <html>
    <head>
        <title>反向解析</title>
    </head>
    <body>
    普通链接:<a href="/fan2/">普通fan2</a>
    <hr>
    反向解析:<a href="{%url 'booktest:fan2'%}">反向解析fan2</a>
    </body>
    </html>
    

    4)回到浏览器中,后退,刷新,查看源文件,两个链接地址一样

    [图片上传失败...(image-80ea03-1530838081153)]

    5)在应用的urls.py中,将fan2修改为fan_show。

    url(r’^fan_show/$’, views.fan2,name=’fan2’),

    6)回到浏览器中,刷新,查看源文件,两个链接地址不一样。

    [图片上传失败...(image-ea84ae-1530838081153)]

    三 视图函数

    (1) 定义视图

    本质:一个函数

    视图参数:

    • 一个HttpRequest的实例
    • 通过正则表达式获取的参数

    位置: 一般在views.py文件下定义

    (2) 错误视图

    404视图

    找不到网页(url匹配不成功)时返回

    在templates目录下定义404.html

    request_path 导致错误的网址

    实例

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>404页面</title>
    </head>
    <body>
        <h1>页面丢失</h1>
        <h2>{{request_path}}</h2>
    </body>
    </html>
    

    配置settings.py

    DEBUG 如果为True永远不会调用404.html页面

    settings 第26行
    DEBUG = False
    
    500视图

    在视图代码中出现错误(服务器代码)

    400视图

    错误出现在客户的操作

    四 HttpRequest对象

    (1) 概述

    服务器接收http请求后,会根据报文创建HttpRequest对象

    视图的第一个参数就是HttpRequest对象

    django创建的,之后调用试图时传递给视图

    也就是在浏览器请求的时候给视图的数据

    (2) 属性

    1. path 请求的完整路径(不包括域名和端口)
    2. method 表示请求的方式,常用的有GET、POST
    3. encoding 表示浏览器提交的数据的编码方式 一般为utf-8
    4. GET 类似字典的对象,包含了get请求的所有参数
    5. POST 类似字典的对象,包含了post请求的所有参数
    6. FILES 类似字典的对象,包含了所有上传的文件
    7. COOKIES 字典,包含所有的cookie
    8. session 类似字典的对象,表示当前会话

    实例

    print(request.path)
    print(request.method)
    print(request.encoding) #在视图中获取不到
    print(request.GET)
    print(request.POST)
    print(request.FILES)
    print(request.COOKIES)
    print(request.session)
    

    (3) 方法

    is_ajax() 如果是通过XMLHttpRequest发起的,返回True

    QueryDict对象

    (4) QueryDict对象

    request对象中的GET、POST都属于QueryDict对象

    方法

    get()

    • 作用:根据键获取值d
    • 只能获取一个值
    • www.sunck.wang/abc?a=1&b=2&c=3

    getlist()

    • 将键的值以列表的形式返回
    • 可以获取多个值dx
    • www.sunck.wang/abc?a=1&a=2&c=3

    (5) GET属性

    获取浏览器传递过来给服务器的数据

    实例

    url为 http://127.0.0.1:8000/sunck/get1?a=1&b=2&c=3
    def get1(request):
        a = request.GET.get('a')
        b = request.GET['b']
        c = request.GET.get('c')
        return HttpResponse(a + "  " + b + "  " + c)
    
    http://127.0.0.1:8000/sunck/get2?a=1&a=2&c=3
    def get2(request):
        a = request.GET.getlist('a')
        a1 = a[0]
        a2 = a[1]
        c = request.GET.get('c')
        return HttpResponse(a1 + "  " + a2 + "  " + c)
    

    (6) POST属性

    使用表单提交实现post请求

    关闭csrf

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        # 'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    

    实例

    def showregist(request):
        return render(request, 'myApp/regist.html')
    def regist(request):
        name = request.POST.get("name")
        gender = request.POST.get("gender")
        age = request.POST.get("age")
        hobby = request.POST.getlist("hobby")
        print(name)
        print(gender)
        print(age)
        print(hobby)
        return HttpResponse("post")
    

    五 HttpResponse对象

    概述:给浏览器返回数据

    HttpRequest对象是由django创建的,HttpResponse对象由程序员创建

    (1) 返回用法

    不调用模板,直接返回数据

    HttpResponse("直接返回给浏览器 不会调用模板")

    from django.http import HttpResponse
    def index(request):
        return HttpResponse("直接返回给浏览器 不会调用模板")
    

    调用模板

    使用render方法

    原型:render(request, templateName[, context])

    作用: 结合数据和模板,返回完整的HTML页面

    参数:

    • request 请求体对象
    • templateName 模板路径
    • context 传递给需要渲染在模板上的数据

    实例:

    def index(request):
        return render(request,'myApp/index.html',{'传递给模板的键名':"传递过去的数据"})
    

    (2) 属性

    1. content 表示返回的内容

    2. charset 编码格式

    3. status_code 响应状态码 【ˈstætəs'】

    4. _content_type_for_repr 指定输出的MIME类型

      MIME类型-在把输出结果传送到浏览器上的时候,浏览器必须启动是党的应用程序来处理这个输出文档。这可以通过多种类型MIME(多功能网际邮件扩充协议)来完成。在HTTP中,MIME类型被定义在Content-Type header中
      

    实例

    def showHttResponse(request):
      res = HttpResponse()
      res.content = b'good' #设置内容
      print(res.content)
      print(res.charset)
      print(res.status_code)
      print(res._content_type_for_repr)
    

    (3) 方法

    1. HttpResponse() 使用页面内容实例化HttpResponse对象

    2. write(content) 以文件的形式写入 向浏览器输出内容

    3. flush() 以文件的形式输出缓冲区

    4. set_cookie(key, value='', max_age=None,expires=None) 设置cookie

    5. delete_cookie(key) 删除cookie

    6. Request.COOKIES.get(key) 获取cookie 的值

      注意: 如果删除一个不存在的key,就当什么都没发生

    Cookie:会话控制 cookie和session 为了维护客户端的状态 因为HTTP协议是无状态的协议

    Cookie常用参数

    • key:键
    • value:值
    • max_age:多久后过期,时间为秒
    • expires:过期时间,为具体时间
    • path:生效路径
    • domain:生效的域名
    • secure:HTTPS传输时应设置为true
    • httponly:值应用于http传输,JavaScript无法获取
    def myCookie(request):
        res = HttpResponse()
        print(request.COOKIES)s
        print(request.COOKIES.get('a','b')) #获取cookie键为a的值 如果cookie不存在则返回b
        # res.set_cookie('mycookie','value',expires=2) #设置2秒的过期时间
        res.delete_cookie(key)#删除cookie
        return res
    

    Cookie加解密

    # salt:加密盐,内容可随便定义
    HttpResponse().set_signed_cookie("key","value",salt="jkkll")
    
    
    # 解密,加密盐的内容应与加密时的内容保持一致
    request.get_signed_cookie("key",salt="jkkll")
    

    注意:如果没有设置Cookie超时时间,表示关闭浏览器之后自动删除Cookie,Cookie尽量避免存储敏感信息。

    六 子类HttpResponseRedirect

    功能: 重定向,服务器端跳转

    简写: redirect(to) to推荐使用反向解析

    实例

    # 重定向
    from django.http import HttpResponseRedirect
    from django.shortcuts import redirect
    def redirect1(request):
        # return HttpResponseRedirect('/sunck/redirect2')
        return redirect('/sunck/redirect2')
    def redirect2(request):
        return HttpResponse("我是重定向后的视图")
    

    重定向参数问题

    from django.core.urlresolvers import reverse

    1)在booktest/urls.py中,修改fan2如下:

    url(r’^fan(\d+)_(\d+)/$’, views.fan2,name=’fan2’),

    from django.shortcuts import redirect
    from django.core.urlresolvers import reverse
    
    def redirect1(request):
        return redirect(reverse('myApp:fun2',args = (1,2)))
        return HttpResponseRedirect(reverse('app:car',args=[1]))
    def fun2(request,arg1,arg2):
        print(arg1,arg2)
        return HttpResponse("我是重定向后的视图")
    

    注意:路径必须使用反向解析 参数必须为元组或者列表的序列类型

    关键字参数

    1)在booktest/urls.py中,修改fan2如下:

     url(r'^fan(?P<id>\d+)_(?P<age>\d+)/$', views.fan2,name='fan2'),
    
    给匹配的值起下标名的例子
    import re
    x = re.compile("(?P<id>\d+)_(?P<age>\d+)")
    a = x.search('1_2')
    print(a.group('id'))
    print(a.group('age'))
    

    2)修改templates/booktest/fan1.html文件如下:

    <html>
    <head>
        <title>反向解析</title>
    </head>
    <body>
    普通链接:<a href="/fan100_18/">fan2</a>
    <hr>
    <!--关键字参数-->
    反向解析:<a href="{%url 'booktest:fan2' id=100 age=18%}">fan2</a>
    <!--普通参数-->
    反向解析:<a href="{%url 'booktest:fan2' 100 18%}">fan2</a>
    </body>
    </html>
    

    3)回到浏览器中,刷新,查看源文件如下图:

    [图片上传失败...(image-758b3c-1530838081153)]

    • 使用重定向传递关键字参数格式如下:

    return redirect(reverse(‘booktest:fan2’, kwargs={‘id’:110,’age’:26}))

    七 子类JsonResponse

    返回json数据,一般用于异步请求

    json = JsonResponse(data)

    注意:Content-type类型为application/jsonc

    from django.http import HttpResponseRedirect,JsonResponse
    def json(request):
      j = JsonResponse({'name':'zs','age':18})
      print(type(j))
      return HttpResponse(j)
    

    八 session

    概述: http是无状态的协议,每次请求都是一次新的请求

    客户端与服务器端的一次通信就是一次会话

    实现状态保持,在客户端或者服务端存储有关会话的数据

    存储方式:

    1. cookie 所有的数据存储在客户端,不要存敏感的数据
    2. session 所有的数存储在服务端,在客户端用cookie存储session_id

    状态保持的目的:在一段时间内跟踪请求者的状态,可以实现跨页面访问当前的请求者的数据

    注意: 不同的请求者之间不会共享这个数据,与请求者一一对应的

    (1) 启用session

    settings文件中

    INSTALLED_APPS  'django.contrib.sessions',  34行
    MIDDLEWARE  'django.contrib.sessions.middleware.SessionMiddleware', 44行
    

    (2) 使用session

    启用session后,每个HttpRequest对象都有一个session属性,就是一个类似字典的对象

    1.设置session

    request.session['键'] = '值'

    2. 根据键获取session值

    get(key, default=None)

    request.session.get["k1"],如果不存在则会报错,为了防止出错可以request.session.get('k1',none)

    3. 清空所有的会话(但是不会删除Django的session表中的session数据和cookie)

    clear()

    request.session.clear()

    4. 删除当前的会话并删除会话的cookie

    flush()

    request.session.flush()

    del request.session['k1'] 删除

    5.导入 logout 清除session

    from django.contrib.auth import logout

    logout(request)

    注意:cookie依然存在 只是清除了cookie的值和session表中的数据

    (3) 设置过期时间

    1. 如果不设置,14天后过期

    2. 整数:

      request.session.set_expiry(10)

      但是不会删除Django的session表中的session数据

    3. 时间对象

    4. 0 关闭浏览器时失效

    5. None 依赖全局session失效策略

    实例 登录退出

    def index(request):
        myDict = 
        myDict['mame'] = '首页'
        print(request.session.get('username','游客'))
        myDict['username'] = request.session.get('username','游客')
        return render(request,'myApp/index.html',myDict)
    #登录
    def login(request):
        print('走到这里了')
        return render(request,'myApp/login.html')
    #登录处理
    def doLogin(request):
        print(request.POST.get('uname'))
        print(request.POST.get('password'))
        request.session['username'] = request.POST.get('uname')
        request.session.set_expiry(10) #设置过期时间
        return redirect('/abc/')
    #退出登录
    from django.contrib.auth import logout as l
    def logout(request):
        # request.session.flush()
        # request.session.clear()
        l(request)
        return HttpResponse('<meta http-equiv="refresh" content="3;/abc/">退出成功')
    
    #模板
    <form action="{% url 'myApp:dologin' %}" method="post">
        <p>用户名: <input type="text" name="uname"></p>
        <p>密码: <input type="password" name="password"></p>
        <p><input type="submit" value="submit"></p>
    </form>
    
    #URL
    url(r'^login/$',views.login,name='login'),
    url(r'^dologin/$',views.doLogin,name='dologin'),
    url(r'^logout/$',views.logout,name='logout'),
    

    配置 settings.py

    (4) 存储session的位置

    1. 数据库 默认存储在数据库中

      Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
      SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)    
      
    2. 缓存 (只存储在本地内存中,如果丢失不能找回,比数据库快)

      SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
      SESSION_CACHE_ALIAS = 'default'        # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
      
    3. 数据库和缓存 (优先从本地缓存中读取,读取不到再去数据库中获取)

      SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
      SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
      
    4. 设置session的公共部分

          SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
          SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)
          SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
          SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
          SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
          SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
          SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
          SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)
      

    (5) 使用redis缓存session

    安装 django-redis-sessions

    pip install django-redis-sessions

    settings.py进行配置

    SESSION_ENGINE = 'redis_sessions.session'
    SESSION_REDIS_HOST = 'localhost'
    SESSION_REDIS_PORT = 6379
    SESSION_REDIS_DB = 0
    SESSION_REDIS_PASSWORD = '123456'
    SESSION_REDIS_PREFIX = 'session'
    

    总报redis连接 密码输入错误

    (6) session常用的操作

    # 获取、设置、删除Session中数据
            request.session['k1']
            request.session.get('k1',None)
            request.session['k1'] = 123
            request.session.setdefault('k1',123) # 存在则不设置
            del request.session['k1']
     
            # 所有 键、值、键值对
            request.session.keys()
            request.session.values()
            request.session.items()
            request.session.iterkeys()
            request.session.itervalues()
            request.session.iteritems()
     
     
            # 用户session的随机字符串
            request.session.session_key
     
            # 将所有Session失效日期小于当前日期的数据删除
            request.session.clear_expired()
     
            # 检查 用户session的随机字符串 在数据库中是否
            request.session.exists("session_key")
     
            # 删除当前用户的所有Session数据
            request.session.delete("session_key")
     
            request.session.set_expiry(value)
                * 如果value是个整数,session会在些秒数后失效。
                * 如果value是个datatime或timedelta,session就会在这个时间后失效。
                * 如果value是0,用户关闭浏览器session就会失效。
                * 如果value是None,session会依赖全局session失效策略。
    

    模板 templates

    一 概述

    模板由两部分组成

    1. HTML代码
    2. 逻辑控制代码

    作用

    快速生成HTML页面

    优点

    1. 模板的设计实现了业务逻辑与现实内容的分离
    2. 视图可以使用任何模板l

    模板处理

    1. 加载
    2. 渲染

    二 定义模板

    (1) 变量

    1. 视图传递给模板的数据

    2. 要遵守标识符规则

    3. 语法

      {{ var }}

    4. 注意

      如果使用的变量不存在,则插入的是空字符串

    5. 在模板中使用语法

      • 字典查询
      • 属性或者方法
      • 数字索引
    6. 在模板中调用对象的方法

      注意:不能传递参数

    (2) 标签

    语法: {% tag %}

    作用:

    1. 在输出中创建文本
    2. 控制逻辑和循环

    1、if/else 标签

    ==, !=, >=, <=, >, < 这些比较都可以在模板中使用

    and, or, not, in, not in 也可以在模板中使用

    基本语法格式如下:

    {% if condition %}
         ... display
    {% endif %}
    

    或者:

    {% if condition1 %}
       ... display 1
    {% elif condition2 %}
       ... display 2
    {% else %}
       ... display 3
    {% endif %}
    
    {% if a == 10 %}
        <h1>10</h1>
    {% elif a == 20 %}
        <h2>20</h2>
    {% endif %}
    

    根据条件判断是否输出。if/else 支持嵌套。

    {% if %} 标签接受 and , or 或者 not 关键字来对多个变量做判断 ,或者对变量取反( not ),例如:

    {% if athlete_list and coach_list %}
         athletes 和 coaches 变量都是可用的。
    {% endif %}d
    

    2、for 标签

    {% for %} 允许我们在一个序列上迭代。

    与Python的 for 语句的情形类似,循环语法是 for X in Y ,Y是要迭代的序列而X是在每一个特定的循环中使用的变量名称。

    每一次循环中,模板系统会渲染在 {% for %} 和 {% endfor %} 之间的所有内容。

    例如,给定一个运动员列表 athlete_list 变量,我们可以使用下面的代码来显示这个列表:

    <ul>
    {% for athlete in athlete_list %}
        <li>{{ athlete.name }}</li>
    {% endfor %}
    </ul>
    
    给标签增加一个 reversed 使得该列表被反向迭代:
    {% for athlete in athlete_list reversed %}
    ...
    {% endfor %}
    
    可以嵌套使用 {% for %} 标签:
    {% for athlete in athlete_list %}
        <h1>{{ athlete.name }}</h1>
        <ul>
        {% for sport in athlete.sports_played %}
            <li>{{ sport }}</li>
        {% endfor %}
        </ul>
    {% endfor %}
    
    {% empty %}
    {% for  变量  in  列表 %}
    语句1
    {% empty %}
    语句2
    {% endfor %}
    

    注意: 列表为空或者列表不存在时执行语句2

    {{ forloop.counter }} 表示当前是第几次循环

    遍历字典

    views.py

    def home(request):
        info_dict = {'site': u'自强学堂', 'content': u'各种IT技术教程'}
        return render(request, 'home.html', {'info_dict': info_dict})
    

    home.html

    站点:{{ info_dict.site }} 内容:{{ info_dict.content }}
    

    注意:在模板中取字典的键是用点info_dict.site,而不是Python中的 info_dict['site']

    还可以这样遍历字典:

    {% for key, value in info_dict.items %}
        {{ key }}: {{ value }}
    {% endfor %}
    

    其实就是遍历这样一个 List: [('content', u'自强学堂'), ('site', u'各种IT技术教程')]

    实例,在模板进行 条件判断和 for 循环的详细操作:

    views.py

    def home(request):
        List = map(str, range(100))# 一个长度为100的 List
        return render(request, 'home.html', {'List': List})
    

    假如我们想用逗号将这些元素连接起来:

    home.html

    {% for item in List %}
        {{ item }}, 
    {% endfor %}
    

    效果如下:

    [图片上传失败...(image-21fe0b-1530838118122)]

    我们会发现最后一个元素后面也有一个逗号,这样肯定不爽,如果判断是不是遍历到了最后一个元素了呢?

    用变量 forloop.last 这个变量,如果是最后一项其为真,否则为假,更改如下:

    {% for item in List %}
        {{ item }}{% if not forloop.last%},{% endif %} 
    {% endfor %}
    

    在for循环中还有很多有用的东西,如下:

    变量 描述
    forloop.counter 索引从 1 开始算
    forloop.counter0 索引从 0 开始算
    forloop.revcounter 索引从最大长度到 1
    forloop.revcounter0 索引从最大长度到 0
    forloop.first 当遍历的元素为第一项时为真
    forloop.last 当遍历的元素为最后一项时为真
    forloop.parentloop 用在嵌套的 for 循环中,获取上一层 for 循环的 forloop

    3、ifequal/ifnotequal 标签

    {% ifequal %} 标签比较两个值,当他们相等时,显示在 {% ifequal %} 和 {% endifequal %} 之中所有的值。

    下面的例子比较两个模板变量 user 和 currentuser :

    {% ifequal user currentuser %}
        <h1>Welcome!</h1>
    {% endifequal %}
    

    和 {% if %} 类似, {% ifequal %} 支持可选的 {% else%} 标签:

    {% ifequal section 'sitenews' %}
        <h1>Site News</h1>
    {% else %}
        <h1>No News Here</h1>
    {% endifequal %}
    

    4、注释标签b

    comment

    作用:注释多行

    {% comment %}
        <h1>sunck is a cool man</h1>
        <h1>sunck is a handsome man</h1>
        {{stu.sname}}
    {% endcomment %}
    
    Django 注释使用 {# #}。
    {# 这是一个注释 #}
    

    注意:注释的代码都不会再浏览器的HTML页面中显示出来

    5、include 标签

    {% include %} 标签允许在模板中包含其它的模板的内容。

    下面这个例子都包含了 nav.html 模板:

    {% include "nav.html" %}
    

    注意:如果是myApp下的模板需要写成

    {% include "myApp/head.html" %}
    

    6、url 反向解析

    作用:反向解析

    格式: {% url 'namespace:name' [ 参数1 参数2 ] %}

    <a href="{% url 'myApp:logout' %}">退出</a>
    

    反向解析中URL的参数

    位置参数

    1)在booktest/urls.py中,修改fan2如下:

    url(r’^fan(\d+)_(\d+)/$’, views.fan2,name=’fan2’),

    2)修改templates/booktest/fan1.html文件如下:

    <html>
    <head>
        <title>反向解析</title>
    </head>
    <body>
    普通链接:<a href="/fan2_3/">fan2</a>
    <hr>
    反向解析:<a href="{%url 'booktest:fan2' 2 3%}">fan2</a>
    </body>
    </html>12345678910
    

    关键字参数

    1)在booktest/urls.py中,修改fan2如下:

     url(r'^fan(?P<id>\d+)_(?P<age>\d+)/$', views.fan2,name='fan2'),
    

    2)修改templates/booktest/fan1.html文件如下:

    <html>
    <head>
        <title>反向解析</title>
    </head>
    <body>
    普通链接:<a href="/fan100_18/">fan2</a>
    <hr>
    反向解析:<a href="{%url 'booktest:fan2' id=100 age=18%}">fan2</a>
    </body>
    </html>12345678910
    
    • 使用重定向传递关键字参数格式如下:

    return redirect(reverse(‘booktest:fan2’, kwargs={‘id’:110,’age’:26}))

    7、跨站请求伪造 csrf

    某些恶意网站包含链接、表单、按钮、js,利用登陆用户在浏览器中认证,从而攻击服务

    作用:用于跨站请求伪造保护

    防止CSRF

    在settings.py文件中的MIDDLEWARE增加(默认就有)

    'django.middleware.csrf.CsrfViewMiddleware',
    

    格式:{% csrf_token %}

    实例
    <form action="{% url 'myApp:dologin' %}" method="post">
        {% csrf_token %}  
    </form>
    

    8、模板继承

    block、extends

    作用:用于模板的继承 可以减少页面的内容的重复定义,实现页面的重用

    block标签

    在父模板中预留区域,子模板去填充

    语法:

    {% block  标签名 %}
    
    {%endblock 标签名%}
    

    extends标签

    语法:

    {% extends  '父模板路径' %}
    

    接下来我们先创建之前项目的 templates 目录中添加 base.html 文件,代码如下:

    HelloWorld/templates/base.html 文件代码:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>{% block title %}菜鸟教程(runoob.com){% endblock %}</title>
    </head>
    <body>
       {% include 'nav.html' %}
     
       {% block content %}
        <div>这里是默认内容,所有继承自这个模板的,如果不覆盖就显示这里的默认内容。</div>
       {% endblock %}
       {% include 'bottom.html' %}
    </body>
    </html>
    

    以上代码中,名为 mainbody 的 block 标签是可以被继承者们替换掉的部分。

    所有的 {% block %} 标签告诉模板引擎,子模板可以重载这些部分。

    hello.html 中继承 base.html,并替换特定 block,hello.html 修改后的代码如下:

    {% extends "base.html" %}
     
    {% block title %}欢迎光临首页{% endblock %}
     
    {% block content %}
    {% include 'ad.html' %}
    这里是首页,欢迎光临
    {% endblock %}
    

    9、HTML转义

    return render(request,'myApp/index.html',{"code":"<h1>xlg is a very good man</h1>"})
    {{code}}
    

    将接收到的code当成普通字符串渲染

    将接收到的字符串当成HTML代码渲染

    1. safe

      {{code|safe}}
      
    2. autoescape

      {% autoescape off %}
         {{code}}
      {% endautoescape %}
      

    (3) 过滤器

    语法:{{ var|过滤器 }}

    作用:在变量被显示前修改它

    模板过滤器可以在变量被显示前修改它,过滤器使用管道字符,如下所示:

    {{ name|lower }}
    

    {{ name }} 变量被过滤器 lower 处理后,文档大写转换文本为小写。

    过滤管道可以被* 套接* ,既是说,一个过滤器管道的输出又可以作为下一个管道的输入:

    {{ my_list|first|upper }} #第一个显示并转化为大写
    {{ my_list|last|upper }}  #最后一个显示并转化为大写
    

    以上实例将第一个元素并将其转化为大写。

    有些过滤器有参数。 过滤器的参数跟随冒号之后并且总是以双引号包含。 例如:

    {{ bio|truncatewords:"30" }}
    {{ letter|truncatewords:'20'|upper }} #取出钱20个值并转化为大写
    

    这个将显示变量 bio 的前30个词。

    注意: 需要将变量bio的单词或者汉子 空格来划分 否则不起作用 如:bio = ab cd ef 而不是 abcdef

    其他过滤器:
    • addslashes : 添加反斜杠到任何反斜杠、单引号或者双引号前面。

      letter:'abc\def'
      {{ letter|addslashes }}
      
    • date : 按指定的格式字符串参数格式化 date 或者 datetime 对象,实例:

      {{ pub_date|date:"F j, Y" }}
      
    • length : 返回变量的长度。

    • join

      格式:值|join:‘#’

      <h1>{{list|join:'#'}}</h1>
      
    如果一个变量没有被提供,或者值为false、空,可以使用默认值

    default

    格式:{{ var|default:'good'}}

    <h1>{{test|default:'没有'}}</h1>
    

    django 模板中 加减乘除 求余

    加法

    {{value|add:10}}
    note:value=5,则结果返回15

    减法

    {{value|add:-10}}
    note:value=5,则结果返回-5,加一个负数就是减法了

    乘法

    {% widthratio 5 1 100%}
    note:等同于:(5 / 1) * 100 ,结果返回500,withratio需要三个参数,它会使用参数1/参数2*参数3的方式进行运算,进行乘法运算,使「参数2」=1

    除法

    {% widthratio 5 100 1%}
    note:等同于:(5 / 100) * 1,则结果返回0.05,和乘法一样,使「参数3」= 1就是除法了。

    求余 求2的余数

    {% if forloop.counter0|divisibleby:2 %}
    

    三 验证码

    作用:在用户注册、登陆页面的时候使用,为了防止暴力请求,减轻服务器的压力 防止csrf一种方式

    验证码代码

    安装pillow模块

    pip install pillow

    def verifycode(request):
        #引入绘图模块
        from PIL import Image, ImageDraw, ImageFont
        #引入随机函数模块
        import random
        #定义变量,用于画面的背景色、宽、高
        bgcolor = (random.randrange(20, 100), random.randrange(
            20, 100), random.randrange(20, 100))
        width = 100
        height = 50
        #创建画面对象
        im = Image.new('RGB', (width, height), bgcolor)
        #创建画笔对象
        draw = ImageDraw.Draw(im)
        #调用画笔的point()函数绘制噪点
        for i in range(0, 100):
            xy = (random.randrange(0, width), random.randrange(0, height))
            fill = (random.randrange(0, 255), 255, random.randrange(0, 255))
            draw.point(xy, fill=fill)
        #定义验证码的备选值
        str = '1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'
        #随机选取4个值作为验证码
        rand_str = ''
        for i in range(0, 4):
            rand_str += str[random.randrange(0, len(str))]
        #构造字体对象
        font = ImageFont.truetype(r'C:\Windows\Fonts\AdobeArabic-Bold.otf', 40)
        #构造字体颜色
        fontcolor1 = (255, random.randrange(0, 255), random.randrange(0, 255))
        fontcolor2 = (255, random.randrange(0, 255), random.randrange(0, 255))
        fontcolor3 = (255, random.randrange(0, 255), random.randrange(0, 255))
        fontcolor4 = (255, random.randrange(0, 255), random.randrange(0, 255))
        #绘制4个字
        draw.text((5, 2), rand_str[0], font=font, fill=fontcolor1)
        draw.text((25, 2), rand_str[1], font=font, fill=fontcolor2)
        draw.text((50, 2), rand_str[2], font=font, fill=fontcolor3)
        draw.text((75, 2), rand_str[3], font=font, fill=fontcolor4)
        #释放画笔
        del draw
        #存入session,用于做进一步验证
        request.session['verify'] = rand_str
        #内存文件操作
        import io
        buf = io.BytesIO()
        #将图片保存在内存中,文件类型为png
        im.save(buf, 'png')
        #将内存中的图片数据返回给客户端,MIME类型为图片png
        return HttpResponse(buf.getvalue(), 'image/png')
    
    模板中的代码
    <form method="post" action="/verifycodecheck/">
        {%csrf_token%}
        <input type="text" name="verifycode"/>
        <img src="/verifycode/" alt="" onclick="this.src='/verifycode/?id='+Math.random()"></p>
        <input type="submit" value="登陆"/>
        <span>{{flag}}</span>
    </form>
    
    在视图中去验证验证码
    from django.shortcuts import render,redirect
    def verifycodefile(request):
        f = request.session.get("flag", True)
        str = ""
        if f == False:
            str = "请重新输入"
        request.session.clear()
        return render(request,'myApp/verifycodefile.html',{"flag":str})
    def verifycodecheck(request):
        code1 = request.POST.get("verifycode").upper()
        code2 = request.session["verify"].upper()
        if code1 == code2:
            return render(request,'myApp/success.html')
        else:
            request.session["flag"] = False
            return redirect('/verifycodefile/')
    
    URL配置
    url(r'^verifycode/$', views.verifycode),
    url(r'^verifycodefile/$', views.verifycodefile),
    url(r'^verifycodecheck/$', views.verifycodecheck),
    

    Django高级

    一、静态文件

    管理静态文件(例如图像,JavaScript,CSS,字体,图片)

    网站通常需要提供其他文件,如图片,JavaScript或CSS。在Django中,我们将这些文件称为“静态文件”。Django提供 django.contrib.staticfiles来帮助你管理它们。

    本页介绍如何提供这些静态文件。

    配置静态文件
    1. 确保django.contrib.staticfiles包含在你的 INSTALLED_APPS

    2. 在您的设置文件中,定义STATIC_URL,例如:

      STATIC_URL = '/static/'
      
    3. 在您的模板中,或者使用硬编码url的方式 /static/my_app/example.jpg,最好使用static 模板标签通过使用配置的STATICFILES_STORAGE存储来构建给定相对路径的URL (当您想要切换到内容交付网络(CDN)时,用于提供静态文件)。

      {% load static %}
      <img src="{% static "my_app/example.jpg" %}" alt="My image"/>
      
    4. 将您的静态文件存储static在应用程序中调用的文件夹中。例如

      my_app/static/my_app/example.jpg

    您的项目可能还会有不与特定应用绑定的静态资产。除了static/在应用程序中使用目录之外,您还可以[STATICFILES_DIRS]在设置文件中定义一个目录列表(),其中Django也将查找静态文件。例如:

    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, "static"),
        '/var/www/static/',
    ]
    
    配置settings.py
    STATIC_URL = '/static/'#比如图片
    #普通文件会查找下面的路径  比如导入js,css
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR,'static')
    ]
    
    实例
    {% load static from staticfiles %}
    {% load staticfiles %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
        <link rel="stylesheet" type="text/css" href="{% static 'myApp/css/style.css' %}"/>
        <script type="text/javascript" src="/static/myApp/js/jquery-3.1.1.min.js"></script>
        <script type="text/javascript" src="/static/myApp/js/sunck.js"></script>
    </head>
    <body> 
        <h1>xlg is a good man</h1>
        <img src="/static/myApp/img/2.png"/>
        <img src="{% static 'myApp/img/2.png' %}"/>
    </body>
    </html>
    

    二、中间件

    概述: 一个轻量级、底层的插件,可以介入Django的请求和响应

    本质:一个Python类

    方法

    1. __init__不需要传参数,服务器响应第一个请求的时候自动调用,用于确定是否启用该中间件

    2. process_request(self,request) 在执行视图之前被调用(分配url匹配视图之前),每个请求上都会调用,返回None或者HttpResponse对象

    3. process_view(self,request,view_func,view_args,view_kwargs) 调用视图之前执行,每个请求都会调用,返回None或者HttpResponse对象see

    4. process_template_response(self,request,response) 在视图刚好执行完后调用,每个请求都会调用,返回None或者HttpResponse对象

      使用render

    5. process_response(self,request,response) 所有响应返回浏览器之前调用,每个请求都会调用,返回HttpResponse对象

    6. process_exception(self,request,exception) 当视图抛出异常时调用,返回HttpResponse对象

    自定义中间件

    1. UM和myApp同级->创建工程目录middleware-->目录下创建myApp目录

    2. |-myApp
      |-middleware
      |--myApp
      |----myMiddle.py
      |-project
      

    3. 在middleware下的myApp里 创建一个python文件 myMiddle.py

    from django.utils.deprecation import MiddlewareMixin
    class MyMiddle(MiddlewareMixin):
        def process_request(self, request):
            print("get参数为:", request.GET.get("a"))
    
    1. 使用自定义中间件

      配置settings.py文件

      MIDDLEWARE中添加

      'middleware.myApp.myMiddle.MyMiddle'

    三、上传图片

    概述:文件上传时,文件数据存储在request.FILES属性中

    注意:

    1. form表单要上传文件需要加enctype="multipart/form-data"
    2. 上传文件必须是post请求

    存储路径

    1. 在static目录下创建upfile目录用于存储接收上传的文件

    2. 配置settings.py文件

      MDEIA_ROOT=os.path.join(BASE_DIR,r'static/upfile')

    代码示例

    模板

    <body>
        <form method="post" action="/savefile/" enctype="multipart/form-data">
            {%csrf_token%}
            <input type="file" name="file"/>
            <input type="submit" value="上传"/>
    </form>
    

    视图

    def upfile(request):
        return render(request, 'myApp/upfile.html')
    import os
    from django.conf import settings
    def savefile(request):
        if request.method == "POST":
            f = request.FILES["file"]
            # 文件在服务器端的路径
            #os.path.splitext(path)获取文件扩展名
            filePath = os.path.join(settings.MDEIA_ROOT, f.name)
            with open(filePath, 'wb') as fp:
                for info in f.chunks():# 分块写入文件  
                    fp.write(info)
            return HttpResponse("上传成功")
        else:
            return HttpResponse("上传失败")
    

    在进行进一步的代码解释之前,需要先讲几个关于上传文件的方法和属性:

    myFile.read():从文件中读取整个上传的数据,这个方法只适合小文件;

    myFile.chunks():按块返回文件,通过在for循环中进行迭代,可以将大文件按块写入到服务器中;

    myFile.multiple_chunks():这个方法根据myFile的大小,返回True或者False,当myFile文件大于2.5M(默认为2.5M,可以调整)时,该方法返回True,否则返回False,因此可以根据该方法来选择选用read方法读取还是采用chunks方法:

         if myFile.multiple_chunks() == False:
             # 使用myFile.read()
          else:
             # 使用myFile.chunks()
    

    myFile.name:这是一个属性,不是方法,该属性得到上传的文件名,包括后缀,如123.exe;

    myFile.size:这也是一个属性,该属性得到上传文件的大小。

    四、分页

    (1) Paginator对象

    1. 创建对象

      格式:Paginator(列表, 整数)

      返回值:返回的分页对象

    2. 属性

      count 对象总数

      num_pages 页面总数

      page_range [1,2,3,4,5] 页码从1开始

    3. 方法

      page(num) 获得一个Page对象,如果提供的页码不存在会抛出"InvalidPage"异常

    4. 异常

      • InvalidPage 当向page()传递的是一个无效的页码时抛出
      • PageNotAnInteger 当向page()传递的不是一个整数时抛出
      • EmptyPage 当向page()传递一个有效值,但是该页面时没有数据时抛出

    (2) Page对象c

    1. 创建对象

      Paginator对象的page()方法返回得到Page对象

      不需要手动创建

    2. 属性

      • object_list 当前页上所有的数据(对象)列表
      • number 当前页的页码值
      • paginator 当前page对象关联的paginator对象
    3. 方法

      • has_next() 判断是否有下一页,如果有返回True
      • has_previous() 判断是否有上一页,如果有返回True
      • has_other_pages() 判断是否有上一页或下一页,如果有返回True
      • next_page_number() 返回下一页的页码,如果下一页不存在抛出InvalidPage异常
      • previous_page_number() 返回上一页的页码,如果上一页不存在抛出InvalidPage异常
      • len() 返回当前页的数据(对象)个数

    代码示例

    路由配置
    url(r'^stupage/(\d+)/$',views.stuPage,name='page'),
    
    视图
    allStu = Students.stuObj.all()
        pag = Paginator(allStu,6)
        # if int(nowPage)>=int(pag.num_pages):
        #     nowPage = pag.num_pages
        try:
            page = pag.page(nowPage)
        except:
            page = pag.page(pag.num_pages)
        # print(page)
        return render(request,'myApp/studentPage.html',{'students':page})
    
    模板
    <body>
        <ul>
            {% for stu in students %}
            <li>
                {{stu.sname}}-{{stu.sgrade}}
            </li>
            {% endfor %}
        </ul>
        <ul>
            {% for index in students.paginator.page_range %}
                {% if index == students.number %}
                    <li>
                    {{index}}
                </li>
                {% else %}
                    <li>
                    <a href="{% url 'myApp:page' index %}">{{index}}</a>
                </li>
                {% endif %}
            {% endfor %}
        </ul>
    </body>
    

    五、Ajax

    需要动态生成,请求JSON数据
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script type="text/javascript" src="/static/myApp/js/jquery-3.1.1.min.js"></script>
    </head>
    <body>
        <h1>学生信息列表</h1>
        <button id="btn">显示学生信息</button>
        <script type="text/javascript" src="/static/myApp/js/sunck.js"></script>
    </body>
    </html>
    
    Jquery代码
    <script src="{% static 'js/jquery-1.8.3.min.js' %}"></script>
        <script>
            $(function () {
                $('button').click(function () {
                {% comment %}                
                    $.ajax({
                        type:'get',
                        url:'{% url "myApp:stuinfo" %}',
                        dataType:'json',
                        success:function(status,data){
                            console.log(status)
                        }
                    })
               {% endcomment %}
                    $.get('{% url "myApp:stuinfo" %}',function(data,status){
                        str = ''
                        if(status == 'success'){
                            for(var i in data.data){
    {#                            console.log(data.data[i][0])#}
                                str += '<li>'+data.data[i][0]+' '+data.data[i][1]+'</li>';
                            }
                            $('ul').append(str)
                        }
                    })
                })
            })
        </script>
    </head>
    <body>
    <ul>
    </ul>
    <button>点击</button>
    </body>
    
    视图
    def ajaxstudents(request):
        return render(request, 'myApp/ajaxstudents.html')
    from django.http import JsonResponse
    def studentsinfo(request):
        s = request.is_ajax() #判断是否是ajax请求
        if not s:
            return HttpResponse('不是ajax请求')
        stus = Students.objects.all()
        list = []
        for stu in stus:
            list.append([stu.sname, stu.sage])
        return JsonResponse({"data":list})
    #使用json.dumps写法 传到前台的json需要解析
    import json
    return HttpResponse(json.dumps({'data':l}))
    
    #ajax获取的数据改成
    data = JSON.parse(data).data#如果使用jsondump需要去解析
    for(var i in a){
        console.log(a[i][0])
    }
    

    六、富文本

    pip install django-tinymce

    在站点中使用

    (1) 配置settings.py文件

    INSTALLED_APPS添加 'tinymce',

    Settings.py添加

    TINYMCE_DEFAULT_CONFIG = {
        'theme':'advanced',
        'width':600,
        'height':400, 
    }
    

    (2) 创建一个模型类

    from tinymce.models import HTMLField
    class Text(models.Model):
        str = HTMLField()
    

    进行文件迁移

    python manage.py makemigrations

    python manage.py migrateas

    (3) 配置站点

    admin.py文件

    from .models import Text
    admin.site.register(Text)
    
    python manage.py createsuperuser #创建站点用户

    在自定义视图中使用

    {% load static from staticfiles %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>富文本</title>
        <script type="text/javascript" src="/static/tiny_mce/tiny_mce.js"></script>
        <script type="text/javascript">
            tinyMCE.init({
                'mode':'textareas',
                'theme':'advanced',
                'width':800,
                'height':600,
            })
        </script>
    </head>
    <body>
        <form action="/saveedit/" method="post">
            <textarea name="str">sunck is a good man</textarea>
            <input type="submit" value="提交"/>
        </form>
    </body>
    </html>
    

    七、celerys

    http://docs.jinkan.org/docs/celery/

    问题:

    用户发起request,并且要等待response返回。但是在视图中有一些耗时的操作,导致用户可能会等待很长时间才能接受response,这样用户体验很差

    网站每隔一段时间要同步一次数据,但是http请求是需要触发的

    (1) celery

    1. 任务task

      本质是一个python函数,将耗时操作封装成一个函数

    2. 队列queue

      将要执行的任务放队列里

    3. 工人worker

      负责执行队列中的任务

    4. 代理broker

      负责调度,在部署环境中使用redis

    (2) 解决

    celery来解决

    1. 将耗时的操作放到celery中执行
    2. 使用celery定时执行

    (3) 安装

    • pip install celery
    • pip install celery-with-redis
    • pip install django-celery

    (4) 配置settings.py

    INSTALLED_APPS 添加

    djcelery

    在settings下方添加如下代码
    import djcelery
    djcelery.setup_loader()#初始化
    BROKER_URL='redis://:密码@127.0.0.1:6379/0'#0带表16个库中使用第0个库
    CELERY_IMPORTS=('myApp.task') #myApp是项目名
    

    (5) 在应用目录下创建task.py文件 也就是myApp下

    from celery import task
    import time  
    
    @task
    def tt():
        print("xlg is a good man")
        time.sleep(5)
        print("xlg is a nice man")
    

    (6) 迁移,生成celery需要的数据库表

    python manage.py migrate

    (7) 在工程目录下的project目录下创建celery.py的文件

    from __future__ import absolute_import
    
    import os
    from celery import Celery
    from django.conf import settings
    
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'whthas_home.settings')
    
    app = Celery('portal')
    
    app.config_from_object('django.conf:settings')
    app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
    
    
    @app.task(bind=True)
    def debug_task(self):
        print('Request: {0!r}'.format(self.request))
    

    (8) 在工程目录下的project目录下的init.py文件中添加

    from .celery import app as celery_app

    (9) 视图

    from .task import tt
    def celery(request):
        tt.delay()#添加到celery中执行,不会阻塞
        return render(request, 'myApp/celery.html')
    

    (10) 启动redis

    C:\redis64-2.8.2101>redis-server.exe redis.windows.conf

    C:\redis64-2.8.2101>Redis-cli.exe

    c127.0.0.1:6379>auth '123456'

    (11) 启动服务

    python manange.py runserver 0.0.0:8000

    (12) 启动worker

    python manage.py celery worker --loglevel=info

    相关文章

      网友评论

        本文标题:django养生

        本文链接:https://www.haomeiwen.com/subject/xhupuftx.html