MVC:一种设计模式.就是把代码解耦,分割成很多部件

  1. M:模型(model):是应用程序中用于处理应用程序数据逻辑的部分.
    通常模型对象负责在数据库中存取数据
  2. V:视图(View):是应用程序中处理数据显示的部分.
    通常视图是依据模型数据创建的.
  3. C:控制器(Controller):是应用程序中处理用户交互的部分.
    通常控制器负责从视图读取数据,控制用户输入,并向模型发生数据

1555162736965

示例:
用户(就是上面的电脑)发送一个HTTP请求给服务器,背后的逻辑是:

  1. 控制器接受用户的request
  2. 控制器让model去数据库里拿数据,然后将数据发给控制器.
  3. 然后控制器将拿到的数据发送给视图.
  4. 最后视图将拿到的数据显示给用户

Django将MVC模式修改成MTV模式:

  1. Model:模型:负责业务对象与数据库对象(ORM)
    和MVC的Model差不多,还是负责管理数据的.
  2. Template:模板:负责如何把页面展示给用户.
    相当于MVC的View,负责展示页面
  3. View:视图:负责业务逻辑,并在适当的时候调用Model和Template.
    相当于MVC的Controller

注意:Django还有一个url分发器,作用是将一个个的url页面请求分发给不同的view处理,view再调用相应的Model和VTemplate

20171215145650232

示例:
用户发送一个request请求

  1. url分发器根据url将不同的请求分给不同的view.
  2. view告诉模型将数据库的数据拿出来给View
  3. view再将从模型拿到的数据给模板,让模板展示给用户.

项目说明:

  1. manage.py:一个命令行工具,可以使我们使用多种方式对Django项目进行交互
  2. _init_.py:空文件,他告诉python这个目录应该被看作一个python包
  3. setting.py:项目的配置文件
  4. urls.py:项目的url声明(就是url分发器)
  5. wsgi.py:项目与wsgi兼容的web服务器入口.

基本操作:

  1. 设计表结构

  2. 配置数据库:
    因为Django默认数据为SQLite,我们可以将其修改为MySQL.在setting.py的DATABASES选项配置:

    1
    2
    3
    4
    5
    6
    7
    8
    DATABASES = {
    'default': {
    # 使用的数据库类型
    'ENGINE': 'django.db.backends.sqlite3',
    # 使用数据库的名
    'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
    }

    修改步骤如下:

    1. 在_init_.py写入:

      1
      2
      import pymysql
      pymysql.install_as_MySQLdb()
    2. 首先在MySQL里创建一个数据库:(数据库名自选)

      1
      create database djangoDB;
    3. 将setting.py的DATABASES选项配置改为:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      DATABASES = {
      'default': {
      'ENGINE': 'django.db.backends.mysql',
      'NAME': 'djangoDB',
      'USER':'root',
      'PASSWORD':'5KVp2y7,k96o',
      'HOST':'localhost',
      'POST':'3306'
      }
      }
  3. 创建应用:
    在一个项目中可以创建多种应用.每个应用运行一种业务处理.

    1
    2
    # 注意在manage.py中运行
    python manage.py startapp myapp

    admin.py:站点配置

    models.py:模型:
    view.py:视图

注意在创建应用之后需要激活应用:

在setting.py中,将myapp应用加入到installed_apps中

  1. 定义模型:
    模型其实就是一个类.这个类继承model.Model

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    from django.db import models

    # Create your models here.

    class Grades(models.Model):
    gname = models.CharField(max_length=20)
    gdate = models.DateTimeField()
    ggirlnum = models.IntegerField()
    gboynum = models.IntegerField()
    isDelete = models.BooleanField()
    def __str__(self):
    return f'{gname}-{gdate}'

    class Students(models.Model):
    sname =models.CharField(max_length=20)
    sgender = models.BooleanField(default=True)
    sage = models.IntegerField()
    scontend = models.CharField(max_length=20)
    # 定义外键
    sgreade = models.ForeignKey('Grades')
    isDelete = models.BooleanField(default=False)
    def __str__(self):
    return f'{sname}-{sdate}'
  2. 在数据库中生成数据表:

    1. 生成迁移文件

      1
      python manage.py makemigrations

      这时就会在migrations目录下生成迁移文件.
      (此时数据库中还没有生成数据表)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      # 在数据库中键入
      show tables;
      /*
      +--------------------+
      | Tables_in_djangodb |
      +--------------------+
      | django_migrations |
      +--------------------+
      */
    2. 执行迁移

      1
      python manage.py migrate
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      # 在数据库中键入
      show tables;
      /*
      +----------------------------+
      | Tables_in_djangodb |
      +----------------------------+
      | auth_group |
      | auth_group_permissions |
      | auth_permission |
      | auth_user |
      | auth_user_groups |
      | auth_user_user_permissions |
      | django_admin_log |
      | django_content_type |
      | django_migrations |
      | django_session |
      | myapp_grades |
      | myapp_students |
      +----------------------------+
      */

      desc myapp_grades;
      /*
      +----------+-------------+------+-----+---------+----------------+
      | Field | Type | Null | Key | Default | Extra |
      +----------+-------------+------+-----+---------+----------------+
      | id | int(11) | NO | PRI | NULL | auto_increment |
      | gname | varchar(20) | NO | | NULL | |
      | gdate | datetime(6) | NO | | NULL | |
      | ggirlnum | int(11) | NO | | NULL | |
      | gboynum | int(11) | NO | | NULL | |
      | isDelete | tinyint(1) | NO | | NULL | |
      +----------+-------------+------+-----+---------+----------------+
      */
  3. 数据操作:

    1. 进入到python shell

      1
      python manage.py shell
    2. 引入包:

      1
      2
      3
      from myapp.models import Grades,Students
      from django.utils import timezone
      from datetime import *
    3. 查询所有数据

      1
      2
      Grades.objects.all()
      # <QuerySet []>
    4. 添加数据:
      本质:创建一个模型类的对象实例.

      1
      2
      3
      4
      5
      6
      7
      8
      grade = Grades()
      grade.gdate =datetime(year=2017,month=7,day = 7)
      grade.gname = 'hyl'
      grade.ggirlnum = 3
      grade.gboynum = 70
      grade.isDelete = False

      grade.save()
    5. 查询某个对象

      1
      2
      Grades.objects.get(id=1)
      # <Grades: Grades object>
    6. 修改数据:

      1
      2
      3
      x = Grades.objects.get(id=1)
      x.gname = 'hyl'
      x.save()
    7. 删除数据:

      1
      Grades.objects.get(id=1).delete()
    8. 连接关联对象:
      使用模式创建外键的方式:把另一个表的实例对象作为这个表实例对象的属性

      1
      2
      3
      4
      s1 = Students()
      g1 = Grades()
      # 把另一个表的实例对象作为这个表实例对象的属性
      s1.sgreade = g1
    9. 获取关联对象:
      属性:关联的类名(小写)_set

      1
      2
      3
      4
      # 一对多,一实体具有一个自带的属性
      # 这个属性名为:多实体表名_set
      g1 = Grades()
      g1.students_set.all()
    10. 便捷的添加表数据的方式:
      关联的类名(小写)_set.create

      1
      2
      # 使用班级表的实例对象来创建学生数据
      g1.students_set.create(sname='hyl',sgender=True,scontend='my name is hyl',sage=45)
  4. 启动服务器:

    1
    python manage.py runserver ip:port

    ip可以不写,不写的话代码本机IP,端口号默认8000

    说明:这是一个纯python写的轻量级web服务器,仅仅在开发测试中使用

  5. Admin站点管理:

    1. 概述:

      1. 内容发布:负责添加,修改,删除内容.
        (这是真正意义就修改数据库中数据,只是提供一个可视化界面而已)
      2. 公告访问
    2. 配置Admin应用:
      admin其实本身就是一个应用.要使用这个应用就需要在setting.py中配置.(当然默认已经配置好了)

      1
      2
      3
      4
      5
      INSTALLED_APPS = [
      # 默认配置好了
      'django.contrib.admin',
      ...
      ]
    3. 创建管理员用户:

      1
      python manage.py createsuperuser

      然后进入127.0.0.1:8000/admin即可

    4. 汉化:

      1
      2
      LANGUAGE_CODE = 'zh-hans'
      TIME_ZONE = 'Asia/shanghai'
    5. 管理数据表:
      修改admin文件

      1
      2
      3
      4
      5
      6
      7
      # myapp/admin

      # 先导入
      from .models import Grades,Students
      # 后注册
      admin.site.register(Grades)
      admin.site.register(Students)

      1555206902506

    6. 自定义管理页面
      使用管理页面类

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      # Register your models here.
      from django.contrib import admin

      # 先导入表格类
      from .models import Grades,Students

      class GradesAdmin(admin.ModelAdmin):
      # 列表页属性
      list_display = ['id','gname','gdate','ggirlnum','gboynum','isDelete']
      list_filter = ['gname']
      search_fields = ['gname']
      list_per_page = 5

      # 添加,修改页面属性
      # fileds和fieldsets不能同时使用
      # fields = ['ggirlnum','gboynum','gname','gdate','isDelete']
      fieldsets = [
      ('num',{'fields':['ggirlnum','gboynum']}),
      ('base',{'fields':['gname','gdate','isDelete']}),
      ]

      # 后注册表格类(要导入GradesAdmin类作为参数)
      admin.site.register(Grades,GradesAdmin)
      admin.site.register(Students)
      1. 列表页属性

        • list_display:

          1
          list_display = ['id','gname','gdate','ggirlnum','gboynum','isDelete']

          显示需要的字段1555207674255

        • list_filter:
          过滤字段(就是添加一个过滤器)

          1
          list_filter = ['gname']

          1555207870256

        • search_fields:
          添加一个搜索字段

          1
          search_fields = ['gname']

          1555208017557

        • list_per_page:
          分页

          1
          2
          # 每5条一页
          list_per_page = 5
      2. 添加,修改页面属性
        1555208204058

        • fields:
          规定属性的顺序

          1
          fields = ['ggirlnum','gboynum','gname','gdate','isDelete']

          1555208654399

        • fieldsets:
          给属性分组
          注意fieldsets属性不能和fields属性同时使用

          1
          2
          3
          4
          5
          # 注意下面图片的字段顺序和这里的字段顺序是一致的
          fieldsets = [
          ('num',{'fields':['ggirlnum','gboynum']}),
          ('base',{'fields':['gname','gdate','isDelete']}),
          ]

          1555210066809
          解释:为什么fieldsets和fields不能同时使用?因为fieldsets本身就已经对字段排序了.

    7. 关联对象:
      需求:在创建一个班级时可以直接添加几个学生
      这时还是要创建一个类StudentsInfo:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      # 新建一个类
      # 注意继承TabularInline
      class StudentsInfo(admin.TabularInline):
      # 要调用的表
      model = Students
      # 要添加几个数据
      extra = 2

      class StudentsInfo(admin.ModelAdmin):
      # 将新建的类放在inlines里面
      inlines = [StudentsInfo]
      list_display = ...

      当新建一张Grade表的时候,下面就会提供一个Students让你填写:

      1555213155603
      其实StudentsInfo类不一定要继承admin.TabularInline,也可以继承admin.StackedInline,只是显示不同而已
      1555213433907

    8. 布尔值显示问题:
      我们对于性别sgender使用了布尔值,但是在终端显示的是0,1.现在想要让他显示’男’和’女’
      在类里定义方法,然后传入list_display

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      class StudentAdmin(admin.ModelAdmin):
      # 定义一个方法
      def gender(self):
      if self.sgender:
      return '男'
      else:
      return '女'
      # 将方法gender代替掉原来的'sgender'
      list_display = ['id','sname','sage',gender,'scontend','sgreade','isDelete']
      list_per_page = 2

      1555213896317

      修改字段名就是修改字段的short_description属性:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      class StudentAdmin(admin.ModelAdmin):
      def gender(self):
      if self.sgender:
      return '男'
      else:
      return '女'
      def sage(self):
      return self

      # 修改字段的字段名
      # 修改字段的short_description属性
      gender.short_description = '性别'
      sage.short_description = '年龄'
      # 替换字段
      list_display = ['id','sname',sage,gender,'scontend','sgreade','isDelete']
    9. 执行动作的位置问题
      1555214524065
      就是将这个框移动到下面去:
      修改actions_on_top/actions_on_bottom属性:

      1
      2
      3
      4
      5
      6
      class StudentAdmin(admin.ModelAdmin):
      # 两个都是True则上下都有
      actions_on_top = False
      actions_on_bottom = True

      ...

      1555214669455

  6. 使用装饰器完成注册admin.
    我们上面将数据表注册到admin使用的方式是:
    新建一个类StudentAdmin,然后通过修改这个类的属性来修改数据表的显示问题,最后将这个类使用

    1
    admin.site.register(Grades,GradesAdmin)

    来完成注册.

    现在我们通过装饰器来完成注册:
    其实方法很简单,就是将admin.site.register(Grades,GradesAdmin)换成装饰器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 使用装饰器,传入表格类作为参数
    @admin.register(Students)
    class StudentAdmin(admin.ModelAdmin):
    actions_on_top = False
    actions_on_bottom = True

    def gender(self):
    if self.sgender:
    return '男'
    else:
    return '女'
    def sage(self):
    return self

    # 修改字段的字段名
    gender.short_description = '性别'
    sage.short_description = '年龄'

    list_display = ['id','sname',sage,gender,'scontend','sgreade','isDelete']
    list_per_page = 2
  7. 视图的基本使用:

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

    • 视图其实就是一个函数,在view.py中定义
      url分发器来找到对应url,然后让这个url调用对应的视图.所以有多少个页面就有多少个视图.

      1
      2
      3
      4
      5
      6
      # Create your views here.
      from django.shortcuts import render
      from django.http import HttpResponse

      def index(request):
      return HttpResponse('hello world')
    • 配置url:

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

        1
        2
        3
        4
        5
        6
        7
        8
        # project/urls.py
        from django.conf.urls import url,include
        from django.contrib import admin

        urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^',include('myapp.urls'))
        ]
      2. 在myApp应用目录下创建一个urls.py文件

        1
        2
        3
        4
        5
        6
        7
        8
        # myapp/urls.py
        from django.conf.urls import url
        from . import views

        urlpatterns = [
        url(r'^$', views.index),
        ]

    • 流程说明:
      20171215145650232

      1. url控制器就是project目录下的urls.py.
      2. 当然我们键入http://127.0.0.1:8000/时,首先经过url控制器,匹配到`url(r'^',include('myapp.urls'))`
      3. 然后include视图函数定位到app.urls文件
      4. 进入app.urls后被url(r'^$', views.index)匹配
      5. 调用view.index函数
    • 为什么要用两级的urls控制器?
      project/urls.py是总的urls控制器,是不可或缺的.而myapp/urls.py是一个app应用的借口,只要调用了这个接口就可以使用这个app应用了,这有利于代码的重用.

      具体是如何重用的?
      两级urls控制器是url的二级目录
      eg:当我们输入http://127.0.0.1:8000/时调用总的urls控制器,匹配到`url(r'^',include('myapp.urls'))`,然后转到app.urls,匹配到`url(r’^$’, views.index)`,最后去调用view.index
      如果我们输入http://127.0.0.1:8000/2怎么办?这时我们就可以在app.urls增加一个url.用来分类这个链接.

      1
      2
      3
      4
      5
      6
      7
      8
      # project/urls.py
      from django.conf.urls import url,include
      from django.contrib import admin

      urlpatterns = [
      url(r'^admin/', admin.site.urls),
      url(r'^',include('myapp.urls'))
      ]
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      # myapp/urls.py
      from django.conf.urls import url
      from . import views

      urlpatterns = [
      url(r'^$', views.index),
      # 注意是(\d+),要用分组
      # 这个分组会传递给view.detail作为参数
      url(r'^(\d+)/$',views.detail)
      ]

      1
      2
      3
      4
      5
      6
      7
      8
      9
      # myapp.views.py
      from django.shortcuts import render
      from django.http import HttpResponse

      def index(request):
      return HttpResponse('hello world')

      def detail(request,num):
      return HttpResponse(f'detail {num}')
      1. 当我们输入http://127.0.0.1:8000/2时,首先到总的urls控制器中,
      2. 其中的url(r'^',include('myapp.urls'))匹配成功http://127.0.0.1:8000/,然后调用对应的视图函数include('myapp.urls'),
      3. include('myapp.urls')调用app.urls,其中的url(r'^(\d+)/$',views.detail)成功匹配到http://127.0.0.1:8000/2中的`/2`,调用视图函数views.detail
      4. views.detail获取到/2,将其赋给num变量,返回 detail 2
        1555289161053
    • 总结:
      也就是说,project/urls.py是用来匹配http://127.0.0.1:8000/的,而app.urls是用来匹配后面的/2的.

      ==两级urls控制器是url的二级目录,用来层层细化url,最终找到对应的视图函数==

  8. 模板的基本使用:

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

    • 创建模板:
      在manage.py目录下创建一个对应模板目录templates.目录templates下面就存放每个app对应的模板文件

    • 配置模板目录:
      修改setting.py文件的TEMPLATES选项.把templates的目录层级告诉DIRS变量

      1
      2
      3
      4
      5
      6
      TEMPLATES = [
      {
      'BACKEND':...
      'DIRS': [os.path.join(BASE_DIR,'templates')],
      ...
      }
    • 基本使用:
      目标:输入http://127.0.0.1:8000/grade返回数据库中grede表的内容.输入http://127.0.0.1:8000/student 返回数据库中student表的内容.

      1. 定义模板:
        找templates/myapp/目录下创建一个grade.html文件

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        <!-- templates/myapp/grades.html -->
        <!DOCTYPE html>
        <html lang='cn'>
        <head>
        <meta charset="UTF-8">
        <title>班级信息</title>
        </head>

        <body>

        </body>
        </html>

        同理创建student.html

      2. 模板语法:

        • {{输出值,可以是变量,一个可以是对象属性}}
        • {%执行代码段%}

        所以前面templates/myapp/grades.html修改为

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        <!-- templates/myapp/grades.html -->
        <!DOCTYPE html>
        <html lang='cn'>
        <head>
        <meta charset="UTF-8">
        <title>班级信息</title>
        </head>

        <body>
        <h1>班级信息列表</h1>
        <!-- 每个班级,因此需要循环 -->
        {%for grade in grades%}
        <li>
        <!-- 双括号下面可以是变量也可以是属性 -->
        <a href="#">{{grade.gname}}</a>
        </li>
        {%endfor%}

        </body>
        </html>

        解释:

        12行-17行其实是一个循环.表示遍历grades(这个grades会由views.py传入),每个grade创建一个<li>,<li>里面创建一个<a>,用grade.gname来填充数据.

      3. 修改myapp/urls.py

        1
        2
        3
        4
        5
        6
        7
        8
        9
        from django.conf.urls import url
        from . import views

        urlpatterns = [
        url(r'^$', views.index),
        url(r'^(\d+)/$',views.detail),
        # 匹配这个url
        url(r'^grades/$',views.grades)
        ]
      4. 创建视图函数:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        # myapp/views.py
        from .models import Grades

        def grades(request):
        # grades函数的使命:去数据库里取出数据,将数据传递给模板
        # (模板再渲染页面,将渲染好的页面返回给浏览器)

        # 首先取出数据
        gradeslist = Grades.objects.all()

        # render的使用接口:
        # 将某个数据数据传给myapp/grades.html这个模板,
        # 是什么数据?实际上是一个字典
        # 该字典以myapp/grades.html里使用的变量作为键,以数据表的数据作为值
        return render(request,'myapp/grades.html',{'grades':gradeslist})
      5. 结果如下:
        1555293072933

  9. 模板的进阶使用:
    现在我们已经创建一个班级信息列表了,现在我们需要制作下面功能,点击grade1,然后跳转到grade1的全部数据
    (简单来说就是:点击班级显示对应班级的学生)

    1. 首先我们将grade.html修改为:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      ...
      <body>
      <h1>班级信息列表</h1>
      <ul>
      {%for grade in grades%}
      <li>
      # a标签的href修改为grade.id
      <a href="{{grade.id">{{grade.gname}}</a>
      </li>
      {%endfor%}
      </ul>

      </body>

      这样,当我们点击的时候就会出现:

      1555331897150
      注意此时url已经变成了http://127.0.0.1:8000/grades/2,所以我们只需再制作一个url分发器,视图即可.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      # app/urls.py
      from django.conf.urls import url
      from . import views

      urlpatterns = [
      url(r'^$', views.index),
      url(r'^(\d+)/$',views.detail),

      url(r'^grades/$',views.grades),
      url(r'^students/$',views.students),
      # 添加新的url
      url(r'^grades/(\d+)$',views.detail_grades)
      ]
      1
      2
      3
      4
      5
      6
      7
      8
      # app/views.py

      # 注意这里的视图函数多了一个num参数(从url分发器里拿到的)
      def detail_grades(request,num):
      grade = Grades.objects.get(id=num)
      studentslist = grade.students_set.all()
      # 重要:注意这里还是调用了student.html这个模板(并没有新建模板)
      return render(request,'myapp/students.html',{'students':studentslist})

简要流程:

  1. 创建工程:
    django-admin startproject myproject
  2. 创建项目:
    python manage.py startapp myapp
  3. 激活项目:
    修改setting.py中的INSTALLED_APPS
  4. 配置数据库:
    1. 修改__init__.py文件
    2. 修改setting.py中的DATABASES
  5. 创建模型类:
    在项目目录下的models.py文件中
  6. 生成迁移文件:
    python manage.py makemigrations
  7. 执行迁移:
    python manage.py migrate
  8. 配置站点
  9. 创建template目录/项目模板目录
  10. 在setting.py中配合模板路径
  11. 在project下修改urls.py
  12. 在项目目录下创建urls.py

当我们获取一个Django项目时,如果才能在我们的电脑里运行?

  1. 在setting.py里修改数据库名,数据库密码
  2. 删除迁移文件
  3. 在数据库中创建对应的数据库
  4. 执行生成迁移文件
  5. 执行迁移

模型

  1. Django对各种数据库都有很好的支持,而且提供了统一的API接口

  2. ORM:

    1. O:对象,R:关系,M:映射
      ORM

    2. 任务:

      • 根据对象的类型生成表结构
      • 将对象,列表的操作转换为sql语句
      • 将sql语句查询到的结果转换为对象和列表
    3. 优点:极大的减轻了开发人员的工作量,不需要面对因数据库的变更和修改代码.

  3. 定义模型:
    模型,属性,表,字段的关系:

    • 模型类在数据库中对应一张表
    • 在模型类中定义的属性对应该模型对照表中得到一个字段.
  4. 定义属性:

    • django会为表添加自动增长的主键列,每个模型只能有一个主键列.
      但是如果使用选项设置某属性为主键列后,则就不能生成默认的主键列
    • 属性命名规则:
      不能用python的关键字.
      不能使用连续的下划线.
    • 所有的字段类型都被定义在django.db.models.fields目录下
    • ==强烈建议对于重要的数据做逻辑删除,而不是物理删除==
      实现方法是定义isDelete属性,类型为BooleanField,默认值为False
  5. 字段类型:

    • AutoField:
      实际上默认的主键列的字段类型就是AutoField.他是一个会根据实际ID自动增长的IntegerField,通常不用这个字段类型.

    • CharField(max_length=字符长度):
      字符串类型.默认的表单样式是TextInput(就是在站点管理的时候显示的是textinput格式)

    • TextField:
      大文本字段.一般超过4000字节的时候使用.默认的表单控件是Textarea

    • IntegerField:
      整数字段

    • DecimalField(max_digits=None,decimal_places=None):
      使用python的Decimal实例表示的十进制浮点数.
      DecimalFiled.max_digits:位数总数.
      DecimalField.decimal_places:小数点后的数字位数.

    • floatField:
      用python的float实例来表示的浮点数.

    • BooleanField:
      布尔字段,默认表单控件是CheckboxInput

    • NullBooleanField:
      支持Null,true,false三种值.

    • DateField([auto_now =False,auto_now_add =False]):
      使用python的datetime.date实例表示的日期.默认对应的表单控件时候一个TextInput
      DateField.auto_now:每次保存对象时,自动设置该字段为当前时间,一般用于最后一次修改的时间戳(就是说,当修改一行的时候,该行的DateField字段就会指定更改时间)
      DateField.auto_now_add:当对象第一次被创建时自动设置当前时间,用于创建的时间.戳,他总是使用当前日期

注意:auto_now_add和auto_now是互斥的.他们不会同时出现在同一个字段.(废话,一个是创建时间,一个是修改时间.)

  • TimeField([auto_now =False,auto_now_add =False]):
    使用python的datetime.time实例表示的时间,参数同DateField

  • DateTimeField([auto_now =False,auto_now_add =False]):
    使用python的datetime.
    datetime实例表示的日期和时间,参数同DateField

  • FileField:
    一个上传文件的字段.

  • ImageField:
    继承了FileField的所有属性和方法,但对上传的对象进行校验,确保这是一个有效的Image.

  1. 字段选项:

    • 概述:
      通过字段选项,可以实现对字段的约束.字段选项必须使用关键字参数.

    • null:
      将空值存储到数据库中,默认为False

    • blanke:
      如果为True,该字段允许空白.默认为False

注意null是数据库范畴的概念,blank是表单验证范畴的.

  • db_column:

    字段的名称.如果未指定,这使用属性的名称.

    eg:当我们定义一个字段时若写到:
    sage = models.IntegerField(db_column='age')
    则在数据库中回忆age来命名该字段,但是models.py中该字段的名称还是sage.

  • db_index:
    若为True,则会在表中以此字段创建索引.

  • default:
    默认值

  • primary_key:
    若为True,设置主键字段

  • unique:
    唯一约束.

  1. 关系:

    • 分类:
      1. Foreignkey:一对多,将字段定义在==多==的端中
      2. ManyToManyField:多余多,将字段定义在==两端==中(本来按照数据库的完整性约束应该再手动建一张表的,但是Django已经帮我们建好了)
      3. OneToOneField:一对一,将字段定义在任意一端中.
    • 用一访问多:
      格式:对象.模型类小写_set
      示例:grade.students_set
    • 用一访问一:
      格式:对象.模型类小写
      示例:grade.students
    • 访问id:
      格式:对象.属性_id
      示例:student.sgrade_id
  2. 元选项:
    在模型类==里面==定义一个Meta类,用于设置元信息.

    • db_table:
      修改默认的数据表名(默认为:项目名_类名).
    • ordering:
      返回结果时对数据自动排序
      (字段名前面+号表示升序(可省略)ordering=['id'],
      -号表示降序ordering=['-id'])
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Students(models.Model):
    sname =models.CharField(max_length=20)
    sgender = models.BooleanField(default=True)
    sage = models.IntegerField()
    scontend = models.CharField(max_length=20)
    sgreade = models.ForeignKey('Grades')
    isDelete = models.BooleanField(default=False)

    class Meta:
    # 修改默认的数据表名
    db_table='students'
    # 返回结果时对数据自动排序
    ordering=['id']
  3. 模型成员:

    • 类属性:

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

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

      3. 自定义模型管理器.(会覆盖掉原来的objects模型管理器)

        1
        2
        3
        4
        5
        class Students(models.Model):
        # 自定义模型管理器
        stuObj = models.Manager()

        sname = ...

        此时就不能再使用students.objects了:

        1
        2
        3
        4
        5
        # 报错
        students.objects.all()

        # 正确运行
        student.stuObj.all()

        到目前为止,我们修改了模型管理器,但是没有什么鸟用,只是修改了名称而已.

      4. 自定义管理器Manager类:

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

          1
          2
          3
          4
          5
          6
          class Students(models.Model):
          # 多个模型管理器
          stuObj1 = models.Manager()
          stuObj2 = models.Manager()

          sname = ...
        • 自定义的模型管理器的作用:

          1. 可以管理器类中添加额外的方法.
            比如说添加一个新方法让我们能更方便的在数据库中添加数据.

            1
            2
            3
            4
            5
            6
            7
            8
            9
            class Students(models.Model):
            # 定义一个类方法,让我们能更方便的创建对象
            @classmethod
            def createStudent(cls,name,age,gender,contend,greade,isDelete=Flase):
            stu = cls(sname=name,sage=age,sgender=gender,scontend=contend,sgreade=greade,isDelete=isDelete)
            return stu

            stuObj = StudentsManager()
            sname = ...
          2. 修改管理器返回的原始查询集.
            比如说,我们可以通过改写get_queryset()方法,让student.objects.all()不返回isDelete为True的数据.

            1
            2
            3
            4
            5
            6
            7
            8
            9
            # 继承models.Manager
            class StudentsManager(models.Manager):
            def get_queryset(self):
            return super(StudentManager,self).get_queryset().filter(isDelete=False)

            class Students(models.Model):
            # 自定义模型管理器,使用自定义的模型管理器
            stuObj = StudentsManager()
            sname = ...
    • 创建对象:

      1. 目的:
        向数据库中添加数据

      2. 当创建对象时,Django不会对数据库进行读写操作,,当调用save方法时才会与数据库交互,将对象保存到数据库中.

      3. 注意:__init__方法已经在父类models.Model中使用,在自定义的模型中无法使用.
        只能为模型表对象实例挨个添加属性,然后save()

      4. 第三点的解决方法有两种:

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

          1
          2
          3
          4
          5
          6
          7
          8
          9
          class Students(models.Model):
          # 定义一个类方法,让我们能更方便的创建对象
          @classmethod
          def createrStudent(cls,name,age,gender,contend,greade,isDelete=Flase):
          stu = cls(sname=name,sage=age,sgender=gender,scontend=contend,sgreade=greade,isDelete=isDelete)
          return stu

          stuObj = StudentsManager()
          sname = ...
        • 在自定义管理器中添加一个方法.

          1
          2
          3
          4
          5
          6
          7
          class StudentsManager(models.Manager):
          def get_queryset(self):
          return super(StudentManager,self).get_queryset().filter(isDelete=False)
          # 定义这个方法后,就可以使用stu = Students.objects.createrStudent(...)
          def createrStudent(self,name,age,gender,contend,greade,isDelete=Flase):
          stu = cls(sname=name,sage=age,sgender=gender,scontend=contend,sgreade=greade,isDelete=isDelete)
          return stu

          但是如果使用上面的方法,那么这个管理器就只能适用于Students,所以我们可以如下使用:

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          class StudentsManager(models.Manager):
          def get_queryset(self):
          return super(StudentManager,self).get_queryset().filter(isDelete=False)
          def createrStudent(self,name,age,gender,contend,greade,isDelete=Flase):
          # 使用self.model(),表示使用该管理器对应的模型创建一个空的实例对象
          stu = self.model()
          stu.sage = age
          stu.sname = name
          stu.sgender = gender
          stu.scontend = contend
          stu.sgreade = greade
          stu.isDelete = isDelete
          return stu
  4. 模型查询:

    • 概述:

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

      1. 在管理器中调用过滤方法返回查询集

        1
        2
        3
        class StudentsManager(models.Manager):
        def get_queryset(self):
        return super(StudentManager,self).get_queryset().filter(isDelete=False)
      2. 查询集经过过滤器筛选后返回新的查询集.
        所以我们可以写成链式调用.

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

      4. 直接访问数据的情况:

        • 迭代
        • 序列化
        • 与if合用
      5. 返回查询集的方法称为过滤器:

        • all():
          返回查询集中的所有值

        • filter():
          返回符合条件的值

          filter(键1=值1,键2=值2):
          的关系,就是说,要同时符合两种

        • exclude:
          过滤到符合条件的数据.

        • order_by():
          和MySQL一样,用于排序

        • values():
          其实数据库的一条数据就是一个字典,多个字典组成一个列表.values()就是将这个列表返回.

          values()和all()的区别:
          我们之前说过all()返回的是一个QuerySet,QuerySet就是一个类似于列表的对象.
          values()返回的是一个真正的列表,列表元素是字典(一个字典就是一条数据)

      6. 返回单个数据:

        • get():
          返回一个满足条件的对象

          注意:
          如果没有符合条件的对象,模型类会引发DoseNotExist异常.
          如果找到多条数据,会引发MutlipleObjectsReturned异常.

        • count():
          返回当前查询集的对象个数

        • find():
          返回查询集中的第一个对象

        • last():
          返回查询集中的最后一个对象

        • exists():
          判断查询集中是否有数据.

      7. 限制查询集:
        查询集返回列表,可以使用下标的方法进行限制.等同于sql中的limit语句.
        注意:下标不能是负数

      8. 查询集的缓存:

        • 概述:
          每个查询集都包含一个缓存,来最小化的对数据库访问.
          在新建的查询集中,缓存首次为空,第一次对查询集求值,会发生数据缓存,Django会见查询出来的数据做一个缓存(保存到内存中),并返回查询结构.以后的查询直接使用查询集的缓存.
      9. 字段查询:

        • 概述:
          实现了sql的where语句,作为方法filter(),exclude(),get()的参数

        • 语法:
          属性名称__比较运算符=值.

        • 外键:
          属性名_id

        • 转义:

          like语句中使用%是为了匹配占位.如果要匹配数据中的%就要使用where like \%
          但是在查询集是使用

          1
          2
          3
          # 找出sname字段存在%的数据
          # 不需要转义
          filter(sname__contains='%')
      10. 比较运算符:

        • exact:

          判断,大小写敏感.
          filter(isDelete=False)

        • contains:
          是否包含,大小写敏感.

          1
          studentList = Students.objects.filter(sname__contains='孙')
        • startswith,endswith:
          和python普通的的startswith一样,以value开头/结尾

          1
          studentList = Students.objects.filter(sname__startswith='孙')
        • 上面四个函数在前面加一个i表示不区分大小写.

          1
          2
          3
          4
          iexact
          icontains
          istartswith
          iendswith
        • isnull,isnotnull:
          是否为空

          1
          filter(sname__isnull=False)
        • in:
          是否包含

          1
          2
          # 查找id在2,4,6,8的学生
          studentList = Students.objects.fileter(id__in=[2,4,6,8])
        • gt,gte,lt,lte:
          大小于等于

          1
          2
          # 查找年龄大于30的学生
          studentList = Students.objects.filter(sage__gt=30)
        • year,month,day,week_day,hour,minute,second:
          日期时间相关:

          1
          studentList = Students.objects.filter(lastTime__year=20)
        • 跨关联关系:
          处理join查询.
          语法:模型类名__属性名__比较运算符

          1
          2
          # 班级里面有名字叫何应良的学生 的班级有哪些?
          gradeList = Gredes.objects.fileter(students__sname__contains='何应良')
        • 查询快捷:
          使用pk代表数据表中的主键

      11. 聚合函数:

        • 使用aggregate()函数返回聚合函数的值
          Avg,Count,Max,Min,Sum

          1
          2
          3
          # 先引入
          from django.db.models import Max
          maxAge = Students.objects.aggregate(Max('sage'))
        • F对象:

          可以使用模型的A属性与B属性进行比较(就是一条数据里的两个值比较)

          1
          2
          3
          from django.db.models import F
          # 字段girlnum的值比boynum字段的值要大
          Grades.objects.filter(girlnum__gt=F('boynum'))

          支持F对象的算术运算

          1
          2
          3
          from django.db.models import F
          # 字段girlnum的值比 boynum字段的值加上20 还要大
          Grades.objects.filter(girlnum__gt=F('boynum')+20)
        • Q对象:
          概述:
          过滤器的方法中的关键字参数,条件为AND模式.
          就是说filter(键1=值1,键2=值2):
          的关系,就是说,要同时符合两种条件

          现在要进行OR查询,就要使用Q对象.
          所以说:Q对象用于解决或的问题.Q()

          1
          2
          3
          4
          from django.db.models import F

          # id小于3或者年龄大于50的数据
          Students.object.filter(Q(id__lte=3) | Q(age__gt = 50))

          上面就是使用两个Q对象,然后使用|连接,
          如果只有一个Q对象,那就是用于匹配的,可以直接省去:

          1
          2
          3
          Students.object.filter(Q(id__lte=3))
          # 等同于
          Students.object.filter(id__lte=3)

          取反:在Q前面加一个波浪线~

          1
          Students.object.filter(~Q(id__lte=3)