Django教程

环境搭建

安装虚拟环境

1
2
3
4
5
6
7
8
9
10
11
12
# 安装虚拟环境
pip3 install virtualenv
# 安装虚拟环境拓展包
pip3 install virtualenvwrapper

# 用户home目录下的.bashrc文件的末端添加如下两行
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 # 导入python3应用程序的路径
export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh # 使用virtual的虚拟环境时需要导入该脚本

# 文件修改完成后,将.bashrc配置文件导入到环境中去
source .bashrc

创建虚拟环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 创建虚拟环境
mkvirtualenv 虚拟环境名

# 创建python3的虚拟环境
mkvirtualenv -p python3 虚拟环境名

# 进入虚拟环境工作
workon 虚拟环境名

# 查看机器上有多少虚拟环境
workon + [tab按键]

# 退出虚拟环境
deactivate

# 删除虚拟环境
rmvirtualenv 虚拟环境名

安装包

1
2
3
4
5
6
7
8
9
10
# 安装包需要进入对应的虚拟环境,则安装的包内容只作用于该虚拟环境
# 注意,在虚拟环境中不能够用sudo pip install 包名,这样会将包安装到真实的主机环境下
pip install 包名

# 安装指定版本的包
pip install 包名==版本号

# 查看当前安装了哪些包
pip list
pip freeze # 显示格式不同

Django初始化

创建项目

1
2
# 创建django项目,前提:必须进入到虚拟环境下
django-admin startproject 项目名

项目结构

image-20201014234757112

  • __init__.py:说明Django3是一个包
  • settings:项目的配置文件,如数据库的配置
  • urls.py:进行url路由的配置
  • wsgi.py:web服务器和Django交互的入口
  • manage.py:项目的管理文件,通过该文件可以管理整个django的项目

创建应用

1
2
3
# 在django中,一个项目由多个应用组成,每个应用完成一个特定的功能
# 创建应用,创建应用的时候需要进入项目的根目录下
python manage.py startapp 应用名称

应用结构

image-20201015000448685

  • __init__:标识booktest是一个包
  • models.py:数据库相关的操作
  • views.py:接受请求并进行处理,与model和templete及逆行交互。它定义处理函数,每个页面对应一个处理函数
  • test.py:写测试代码的文件,目前不需要开发去写
  • admin.py:负责网站管理后台

应用与项目关联

1
2
3
# 开发项目前需要将创建的应用与项目之间建立关系,则需要对应用进行注册
# 修改项目文件中settings.py文件中INSTALLED_APPS配置项
在列表的末尾追加【新增应用】的文件夹名称即可

启动项目

1
2
# 位于项目的根目录下
python manage.py runserver 127.0.0.1:8001

Django基本使用

ORM框架

1
2
3
4
# O:Object,R:数据库,M:映射
# django中内嵌了ORM框架,ORM框架可以将类和数据表进行对应起来,只需要通过类和对象就可以对数据表进行操作
# ORM另一个作用:根据设计的类生成数据库中的表
# 对应应用下的models.py文件中创建数据库操作的各种对象

模型

创造模型类

  1. 设计模型类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # 操作对应的应用下的models.py文件
    # django会自动的生成表的主键ID
    from django.db import models

    # 创建的类必须要继承models.Model类
    class BookInfo(models.Model):
    '''创建一个bookinfo的类,回头会创建一个【应用名_bookinfo】的表'''

    # charField:表示创建的字段是字符类型,max_length表示该字段的字符长度
    btitle = models.CharField(max_length=256)
    # DateField:表示创建一个日期格式的表
    bpub_date = models.DateField()
    # BooleanField:表示布尔类型,default表示该字段的默认值
    bgender = models.BooleanField(default=False)
    # IntegerField:表示整数类型
    bread = models.IntegerField(default=0)
    # Foreign:创建外键,内部参数是外键对应的类名,数据库中生成的外键名为【关系属性名_id】
    # on_delete:外键创建的时候要添加的参数
    hook = models.ForeignKey("Book", on_delete=models.CASCADE)
  2. 创造迁移文件

    1
    2
    # 迁移文件是根据models.py文件生成的
    python manage.py makemigrations
  3. 执行迁移生成表

    1
    2
    # 会自动根据生成文件生成对应的数据库中的数据表
    python manage.py migrate
  4. 数据库配置

    1
    2
    3
    4
    5
    6
    7
    # 数据库配置在项目的settings.py文件中,默认为sqllite3
    DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.sqlite3',
    'NAME': BASE_DIR / 'db.sqlite3',
    }
    }

模型类操作数据表

  1. 进入项目的shell

    1
    python manage.py shell
  2. 操作数据

    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    # 导入模型类,从应用的【models.py】文件中导入对应的类名
    from bookinfo.models import BookInfo
    from datetime import date

    # 插入数据
    ob = BookInfo() # 创建对象
    ob.btitle = "帅" # 添加对象的实例属性
    ob.pub_date = date(1992,2,15)
    ob.save() # 实例属性修改完毕后,save即可修改

    # 查询数据,通过【类名.objects.get(查询条件)】返回对象,然后直接打印出对象的实例属性即可
    b2 = BookInfo.objects.get(id=1)
    b2.btitle

    # 修改数据,先获取数据对象,然后修改其属性后,再save()
    b2 = BookInfo.objects.get(id=1)
    b2.btitle = "霸气"
    b2.save()

    # 删除数据,先获取数据对象,调用delete()
    b2 = BookInfo.objects.get(id=1)
    b2.delete()

    # 查询表中所有的数据
    BookInfo.objects.all()

    # 添加外键,先获取外键指向的主键对象,然后将外键字段的属性设置为主键对象
    b = Book.objects.get(id=1)
    fb = BookInfo.objects.get(id=2)
    fb.hook = b
    fb.save()

    # 访问外键的ID,其字段为:外键名_id
    b = BookInfo.objects.get(id=1)
    b.hook_id

    # 访问外键指向的对象
    b = BookInfo.objects.get(id=1)
    foreign_obj = b.hook
    foreign_obj.btitle # 访问外键对象的标题

    # 访问一张表中,关联主键的所有外键的内容,
    b = Book.objects.get(id=1)
    b.bookinfo_set.all() # 获取到该外键的所有对象

django后台管理

  1. 本地化,修改项目【settings.py】文件中如下内容:

    1
    2
    LANGUAGE_CODE = 'zh-hans'  # 设置语言
    TIME_ZONE = 'Asia/Shanghai' # 设置时区
  2. 创建管理员

    1
    python manage.py createsupperuser
  3. 注册模型类,在应用【admin.py】下注册模型类,告诉django框架根据注册的模型类生成对应表的管理页面

    1
    2
    3
    4
    5
    6
    7
    from django.contrib import admin
    # 需要将models.py中的类导入到模块下
    from wuxiang.models import Book

    # 将数据库中表对应的类注册到【应用】对应的admin.py文件中
    # 模型类不可重复注册
    admin.site.register(Book)
  4. 自定义模型类,自定义admin管理页面的显示参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from django.contrib import admin
    from wuxiang.models import Book, Hero

    # Register your models here.
    class BookAdmin(admin.ModelAdmin):
    '''定义图书模型管理类,类名格式:【models.py类名+Admin】'''
    '''list_display:列表中填写的是数据库中对应的列名'''
    list_display = ['btitle', 'bcontent', 'bpub_date']

    # 自定义注册的页面,同时需要添加自定义的模型管理类
    admin.site.register(Book, BookAdmin)
  5. (自定义模型修改更好)修改admin管理页面表详情页面数据的显示,通过修改models.py对应数据类中的__str__()方法的打印值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from django.db import models

    class Book(models.Model):
    btitle = models.CharField(max_length=256)
    bcontent = models.CharField(max_length=256)
    bpub_date = models.DateField()

    # 修改数据类的__str__()中的返回值
    def __str__(self):
    return self.btitle

视图

访问配置

在django中,通过浏览器去请求一个页面,使用视图函数来处理这个请求,视图函数处理完以后,给浏览器返回页面内容

  1. 定义视图函数

    1
    2
    3
    4
    5
    6
    7
    8
    # 在【应用】下的【views.py】文件中定义视图函数
    # 本质是对用户请求的链接进行处理,并返回响应的数据
    # 视图函数需要返回内容,必须通过HttpResponse对象
    from django.shortcuts import render
    from django.http import HttpResponse

    def index(request):
    return HttpResponse("返回给页面的内容")
  2. url路由配置,建立url地址和视图的对应关系

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
       # 配置的地方有两个,一个是项目下的【urls.py】(已自动创建),一个是应用下的【urls.py】(需要手动创建)
    # 应用下的【urls.py】,是具体的路径配置,内容如下:
    from django.conf.urls import url
    from wuxiang import views
    urlpatterns = [
    # url的方法是1.x版本的django方法,现在都适用path方法
    url('^index$', views.index),
    # 正则中用括号包裹分组,则在匹配的时候会将分组匹配的内容传递给视图函数
    url('^index/(\d+)$', views.index),
    ]

    # 项目下的【urls.py】是总的路由配置,用于汇总app下的路由配置,内容如下:
    # path函数并不支持正则表达式,如果要支持正则表达式,则可使用re_path方法
    from django.contrib import admin
    from django.urls import path, include, re_path
    urlpatterns = [
    path('admin/', admin.site.urls),
    # 第一个参数是正则,第二个参数是app的路由配置文件
    # 此处匹配符合的内容会从url中去除, 然后会拿剩余的字段到app对应的文件中进行匹配
    re_path('a/\d+', include('wuxiang.urls')) # 导入app下路由配置文件
    ]

重定向配置

  • 复杂写法

    1
    2
    3
    4
    5
    6
    7
    # 重定向配置需要用到HttpResponseRedirect
    from django.http import HttpResponseRedirect

    def wuxiang(request):
    # HttpResponseRedirect表示重定向
    # 第一个参数:重定向后访问的域名
    return HttpResponseRedirect('/index')
  • 精简写法

    1
    2
    3
    4
    5
    # 利用redirect函数重定向
    from django.shortcuts import render, redirect
    def wuxiang(request):
    # 第一个参数:重定向后访问的域名
    return redirect('/index')

模板

  1. 创建模板文件夹

    1
    2
    # 在项目的根目录下创建一个文件夹templates
    touch templates
  2. 配置模板目录,在项目的配置文件【settings.py】中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # 注意修改其中的【DIRS】配置项
    # 为了便于区分模板被用于哪个App,我们会在templates文件夹中创建与app同名的文件夹,用于存放该App的模板
    TEMPLATES = [
    {
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    # 配置模板的具体目录位置
    'DIRS': [os.path.join(BASE_DIR, 'templates')],
    'APP_DIRS': True,
    'OPTIONS': {
    'context_processors': [
    'django.template.context_processors.debug',
    'django.template.context_processors.request',
    'django.contrib.auth.context_processors.auth',
    'django.contrib.messages.context_processors.messages',
    ],
    },
    },
    ]
  3. 创建模板文件

    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
    # 在对应App的模板文件夹中创建html格式的模板文件
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>这是一个模板文件</title>
    </head>
    <body>
    <h1>有本事你就来呀</h1>
    <h2>{{ content }}</h2>
    <h3>模板中循环列表内容进行展示</h3>
    <ul>
    {# 将for循环语句包裹在{% 循环语句 %} #}
    {% for i in list %}
    {# 循环的变量:{{ 变量名 }} #}
    <li>{{ i }}</li>

    {# 当循环对象为空时则会执行empty下面的语句 #}
    {% empty %}
    <li>没有英雄的信息</li>

    {% endfor %}
    {# 结尾需要表示{% endfor %} #}
    </ul>
    <!-- 开发时,a标签的href中内容不加/,则会直接在原url后直接拼接,导致报错,正确的做法是以/开头 -->
    <a href="/index">内容</a>
    </body>
    </html>
  4. 使用模板文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # 在对应app的models.py文件中进行定义
    from django.http import HttpResponse
    # 加载和编辑模板时,需要以下两个函数
    from django.shortcuts import render
    from django.template import loader

    def index2(request):
    # 加载模板文件,参数是对应模板文件的路径,该路径是相对于templates文件夹路径而言的
    temp = loader.get_template('wuxiang/index.html')

    # 定义模板上下文:给模板文件传递数据, 内容可以是字符串、列表等
    content = {"content": "姓名区域", 'list':list(range(1,10))}

    # 模板渲染:返回完整的html内容
    # 格式:模板对象.render(模板上下文)
    res_html = temp.render(content)

    return HttpResponse(res_html)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
       
    上述内容也可以简写

    ```python
    # 利用gender函数可以一次性生成对应的html返回内容
    from django.shortcuts import render

    def index2(request):
    # 第一个参数:request
    # 第二个参数:模板文件的路径
    # 第三个参数:模板文件中各参数对应的值所组成的字典数据
    return render(request, 'wuxiang/index.html', {"content": "姓名区域", "list": list(range(1, 10))})

模型详解

配置数据库

  1. 安装pymysql模块

    1
    pip install pymysql
  2. 修改django的项目文件【__init__.py】文件,导入pymysql的模块

    1
    2
    3
    4
    5
    6
    # 修改项目文件夹下的__init__.py文件,不导入的话,项目启动报错
    # 也有可能让安装mysqlclient
    import pymysql
    # 2,0,1是数据库版本
    pymysql.version_info = (2, 0, 1, 'final', 0)
    pymysql.install_as_MySQLdb()
  3. 修改django项目配置文件【settings.py】文件中的数据库链接方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    DATABASES = {
    'default': {
    # 'ENGINE': 'django.db.backends.sqlite3',
    'ENGINE': 'django.db.backends.mysql',
    # 'NAME': BASE_DIR / 'db.sqlite3',
    'NAME': 'django', # 数据库的名称,需要提前创建好
    'USER': 'root', # 数据库的登录用户名
    'PASSWORD': 'qwer1234', # 数据库的登录密码
    'HOST': '192.168.85.131', # 数据库所在的服务器IP
    'PORT': '3306', # 数据库的连接端口号
    }
    }

模型类属性

  • 模型类属性定义格式

    1
    2
    3
    4
    # 每修改一次模型类属性的结构,就都需要重新生成迁移文件和迁移表,除了null和blank属性
    from django.db import models

    属性名 = models.字段类型(选项)
  • 模型类属性名限制

    1. 不能是python的保留关键字
    2. 不允许连续的下划线
    3. 定义属性的时候需要指定字段类型,通过字段类型的参数指定选项
  • 字段类型种类

    类型 描述
    AutoField 自动增长的IntegerField,通常无需指定,不指定的时候Django会自动创建属性名为id的自动增长属性
    BooleanField 布尔字段类型,值为True、False
    NullBooleanField 支持Null、False、True三种数据类型
    CharField(max_length=最大长度) 字符串,参数max_length表示最大字符个数,是一定需要设定的
    TextField 大文本字段,一般超过4000字
    IntegerField 整数
    DecimalField(max_digits=None, decimal_places=None) 十进制浮点数,参数max_digits表示总的位数,decimal_places表示小数的位数
    FloatField 浮点数,参数同上。该属性的字段相比较DecimalField而言精确度低
    DateField(auto_now=False) 日期,表示年月日。
    auto_now参数表示更新该字段的修改时间为当前时间,每修改一次都会更新,默认为False。
    auto_now_add参数表示第一次创建时更新该字段的时间为当前时间,此后修改便不会更新该字段,默认为False。
    auto_now和auto_now_add属性互斥,不可同时设定
    TimeField 时间,表示时分秒,参数同上
    DateTimeField 日期+时间,参数同上
    FileField 上传文件字段
    ImageField 继承于FileField,对上传的内容进行校验,确保是有效的图片
  • 选项

    选项名 描述
    default 设置默认值。该属性无需修改表结构
    primary_key 设置主键,默认为False,一般与AutoField一起使用
    unique 唯一性约束,默认为False,若为True,则表示字段的内容必须唯一
    db_index 字段建立索引,默认为False。若为True,则会为该字段建立索引
    db_column 自定义数据库中字段的名称,如果为指定则使用属性的名称
    null 字段是否可以为空,默认False,若为True,表示允许为空
    blank 表示字段是否允许为空白,默认为False,若为True,表示允许为空白。该属性无需修改表结构

    null属性是数据库中约束的范畴,blank是django后台约束的范畴

查询操作

配置数据库日志

1
2
3
# 修改mysql的配置文件,打开general_log_file
general_log_file = /var/log/mysql/query.log
general_log = 1

查询函数

  • 使用格式:

    1
    2
    3
    # 数据表的查询方式
    # 当返回结果为查询集合时,可直接在后面直接调用方法
    模型类.objects属性.方法(筛选条件).方法(筛选条件)
  • 方法分类

    方法 功能
    get 返回表中满足条件的一条且只能一条的数据, 是一个模型对象。参数写查询条件
    查询返回多条数据,返回异常:MultipleObjectsReturned。
    查询无符合条件的数据,返回异常:DoesNotExist。
    all 返回模型类对应表中的所有数据,返回的是一个查询集(QuerySet类型)
    filter 返回满足条件的数据,参数写查询条件,返回值是查询集(QuerySet类型)
    exclude 返回不满足条件的数据,参数写查询条件,返回值是查询集(QuerySet类型)
    order_by 对查询结果进行排序,参数中填写根据那些字段进行排序,返回值是查询集(QuerySet类型)

    order_by排序案例:

    1
    2
    3
    4
    5
    6
    # 按照id降序排列(字段前加-号),read升序排列
    BookInfo.objects.all().order_by('-id', 'read')
    BookInfo.objects.order_by('-id', 'read') # 对所有数据进行操作时,都可省略all()

    # 根据筛选数据进行排序
    BookInfo.objects.filter(bpub_time__gt=date(1992,6,25)).order_by('bpub_time')
  • 筛选条件分类,适用于filter、exclude、get方法

    1
    2
    # 条件的编写格式
    模型类属性名__条件名=值
    条件名 作用
    exact 判定等于,也可直接省略该条件名。【字段名__exact=1】
    contains 模糊查询,包含。【字段名__contains=’帅’】
    startswith 模糊查询,开头。【字段名__startswith=’shuai’】
    endswith 模糊查询,结尾。【字段名__endswith=’shuai’】
    isnull 空查询,判定是否为空。【字段名__isnull=True】
    in 范围查询。【字段名__in=[1, 2, 3]】
    gt、lt、gte、lte 比较查询。gt(大于)、lt(小于)、gte(大于等于)、lte(小于等于)。【字段名__gt=3】
    year 日期查询,也可不使用year,直接使用字段跟日期比较。【字段名___year=1998】
  • 逻辑比较

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # Q对象:用于查询时条件之间的逻辑关系。not and or,可以使用Q对象进行&|~
    # 使用前需导入
    from django.db.models import Q

    # 与关系:Q(条件)&Q(条件)
    BookInfo.objects.filter(id_gt=3, id_lt=6)
    BookInfo.objects.filter(Q(id_gt=3)&Q(id_lt=6))

    # 或关系:Q(条件)|Q(条件)
    BookInfo.objects.filter(Q(id_gt=3)|Q(id_lt=6))

    # 非关系:~Q(条件)
    BookInfo.objects.filter(~Q(id_gt=3))
  • 属性比较

    1
    2
    3
    4
    5
    6
    7
    # F对象:用于类属性之间的比较
    # 使用前需要导入
    from django.db.models import F

    # 将比较的属性放在F对象中
    # 查询图书阅读量大于两倍评论量的数据
    BookInfo.objects.filter(bread__gt=F('bcomment')*2)
  • 聚合函数:aggregate

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 格式:筛选.aggregate(聚合函数(字段名))

    # 使用前,需导入会用到的聚合类
    from django.db.models import Sum, Count, Max, Min, Avg

    # 对查询结果进行聚合前需要先调用aggregate进行聚合,结果返回值是一个字典,主键名为:字段名__聚合类(小写)
    # 获取id大于6的所有id和,查询返回结果为:{"id__sum": 100}
    BookInfo.objects.filter(id_gt=6).aggregate(Sum('id'))

    # 获取id大于6的数据总数
    BookInfo.objects.filter(id_gt=6).aggregate(Count('id'))
    # 只获取数据总量值的话,聚合部分可直接用count()代替
    BookInfo.objects.filter(id_gt=6).count()

查询集

查询集合特性

  • 惰性查询

    只有在实际使用查询集中的数据的时候,才会对数据库进行真正的查询

  • 缓存

    当使用同一个查询集的时候,第一次会发生实际数据库的查询,然后将查询结果缓存起来,之后再使用这个查询集时,使用的是缓存中的结果

限制查询集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 可以使用切片和下标对查询集进行限制
# 下标不能够为负数
list1 = BookInfo.objects.all()

# 切片操作会产生一个新的查询集,但是其不会重新查询数据库
list2 = list1[0:3]

# 下标可访问指定的查询数据,若该数据不存在则抛出IndexError()异常
list1[2]

# exists方法:可以判断一个查询集中是否有数据,有则True,否则False
list2.exists()

# 获取查询集第一个数据的方式
list1[0:1].get()

备注

  • Django基础使用导图:脑图

    Django

  • Django模型导图:脑图

数据库忘记密码

1
2
3
4
5
# 若数据库密码忘记,则在mysql配置文件中添加如下内容重启登录
skip-grant-tables

# 然后直接用root登录
mysql -u root

Image的base64存放

1
2
3
4
5
6
7
8
9
10
11
// image转base64的网站:http://tool.chinaz.com/tools/imgtobase/

// Base64 在CSS中的使用
.box{
background-image: url("data:image/jpg;base64,/9j/4QMZR...");
}

// 对应的image格式
.box{
background-image: url("/image/1.png");
}