本文介绍: django基础知识详解安装Django卸载$ pip3 uninstall djangoDjango开发环境2.2 Django项目目录结构2.2.1 作用:此文件项目管理的主程序,在开发阶段用于管理整个项目的开发运行的调式特点: 包含项目管理的子命令, 如: 启动服务 创建应用 数据库迁移可以显示帮助文档查看所有选项2.2.2 mysite1 项目包文件夹特点:项目包的主文件夹(默认与项目名称一致)2.2.3 包初始化文件,当此项目包被导入(

1. 安装介绍

1.1 Django框架介绍

1.2 Django的安装

2. Django文件目录和文件介绍

2.1 创建项目的指令

- $ django-admin startproject 项目名称
- 如:
	- $ django-admin startproject mysite1
- 运行
  
  ```shell
  $ cd mysite1
  $ python3 manage.py runserver
  # 或
  $ python3 manage.py runserver 5000  # 指定只能本机使用127.0.0.1的5000端口访问本机
  ```

2.2 Django项目的目录结构

$ django-admin startproject mysite1
$ tree mysite1/
mysite1/
├── manage.py
└── mysite1
  ├── __init__.py
  ├── settings.py
  ├── urls.py
  └── wsgi.py

1 directory, 5 files

2.2.1 manage.py

2.2.2 mysite1 项目包文件夹

2.2.3 __init__.py

2.2.4 settings.py

  1. BASE_DIR

2.2.5 urls.py

2.2.6 views.py

3. URL介绍

4. 视图函数详解

4.1 FBV(Fuction base view)

用函数创建的视图

4.2 CBV(Class base view)

优点:可以直接匹配getposthead请求方式

如果平常的用FBV的话就需要匹配if—elif的方式匹配访问方式,这种方式往往显得很笨拙

views.py

# FBV模式
def home(request):
    if request.method == 'GET':
        xxxx
    elif request.method == 'POST':
        XXX

urls.py

from django.urls import path,include
from index import views

urlpatterns = [
    # FBV模式
    path('',views.index_home)
]
  • CBV模式

views.py

# CBV模式
class Index_home(View):
    def get(self,request):
        return HttpResponse('这是get主页')
    def post(self,request):
        return HttpResponse('这是post主页')

urls.py

from django.urls import path,include
from index import views

urlpatterns = [
    # FBV模式
    # path('',views.index_home)
    # CBV模式
    path('',views.Index_home.as_view())
]

5. 路由配置详解

from django.urls import path
from . import views
# path函数的第一个参数为路由地址名,第二个参数为views的函数名
urlpatterns = [
  path('',views.main_view), # 匹配127.0.0.1
  path('page/1',views.page1_view), # 127.0.0.1/page/1
  path('page/2',views.page1_view), # 127.0.0.1/page/2
]

path函数的第一个参数为路由地址名,第二个参数为views的函数名

5.1 path函数详解

5.1.1 path转换器

6. 响应请求

6.1 HTTP请求

6.1.1 基础知识概念

6.1.2 Django的 HttpRequest对象

在这里插入图片描述

6.2 HTTP 响应

6.2.1 基础知识概念

6.2.2 Django的响应对象HttpResponse

在这里插入图片描述

视图函数的返回的一个函数

HttpResponse详解

6.3 GET方式传参

6.4 POST方式

7. Django的设计模式

7.1 MVC 设计模式

7.2 MTV 模式

MTV 代表 Model-Template-View(模型模板-视图) 模式。这种模式用于应用程序分层开发

8.Django的模板前后分离的话可以不看)

8.1模板传参

8.2 模板的变量

  1. 在模板中使用变量语法

8.3 模板的标签

  1. 作用

8.4 过滤器

  1. 作用

8.5 模板的继承

8.6 url 反向解析

在这里插入图片描述

先在路由函数中取别名,然后在视图函数中利用reverse函数进行反向解析

9.django中的静态文件

静态文件

  1. 什么静态文件

  2. 静态文件配置

    • settings.py 中配置一下两项内容:
    1. 配置静态文件的访问路径

      https://oimagea1.ydstatic.com/image?id=-5337101211608292607&product=adpublish&w=640&h=480&sc=0&rm=2&gsb=0&gsbd=60

      • 通过哪个url地址找静态文件
      • 127.0.0.1:8000/static/
      • STATIC_URL = ‘/static/’
      • 说明:
        • 指定访问静态文件时是需要通过 /static/xxx或 127.0.0.1:8000/static/xxx
        • xxx 表示具体的静态资源位置
    2. 配置静态文件的存储路径 STATICFILES_DIRS

    3. 示例:

      # file: setting.py
      STATICFILES_DIRS = (
          os.path.join(BASE_DIR, "static"),
      )
      
  3. 访问静态文件

    1. 使用静态文件的访问路径进行访问

    2. 通过 {% static %}标签访问静态文件

      • {% static %} 表示的就是静态文件访问路径
      1. 加载 static
      2. 使用静态资源时

10. django中的应用

创建应用app

应用的分布式路由

  • Django中,基础路由配置文件(urls.py)可以不处理用户具体路由,基础路由配置文件的可以做请求的分发(分布式请求处理)。具体的请求可以由各自的应用来进行处理
  • 如图:
    在这里插入图片描述
include 函数
  • 作用:

    • 用于分发将当前路由转到各个应用的路由配置文件的 urlpatterns 进行分布式处理
  • 函数格式

    模块app命字/url模块名.py 文件件里必须有urlpatterns 列表
    使用前需要使用 from django.conf.urls import include 导入此函数

  • 练习:

    1.创建四个应用
        1.创建 index 应用,并注册
        2.创建 sport 应用,并注册
        3.创建 news  应用,并注册
        4.创建 music 应用,并注册
    2.创建分布式路由系统
        主路由配置只做分发
        每个应用中处理具体访问路径和视图
        1. 127.0.0.1:8000/music/index
            交给 music 应用中的 index_view() 函数处理
        2. 127.0.0.1:8000/sport/index
            交给 sport 应用中的 index_view() 函数处理
        3. 127.0.0.1:8000/news/index
            交给 news  应用中的 index_view() 处理处理
    

11.django的数据库操作

11.1 Django下配置使用 mysql 数据库

  1. 安装 pymysql

  2. 创建 和 配置数据库

    1. 创建数据库

      create database mywebdb default charset utf8 collate utf8_general_ci;
      
    2. 数据库的配置

    3. 关于数据为的SETTING设置

      1. ENGINE

        • 指定数据库的后端引擎
        'django.db.backends.mysql'
        'django.db.backends.sqlite3'
        'django.db.backends.oracle'
        'django.db.backends.postgresql'
        
      2. NAME

      3. USER

      4. PASSWORD

        • 接数据库时使用的密码
        • 'PASSWORD':'123456'
      5. HOST

        • 连接数据库时使用哪个主机。
        • 'HOST':'127.0.0.1'
      6. PORT

        • 连接数据库时使用的端口。
        • 'PORT':'3306'
    4. 添加 mysql 支持

11.2 Django 的 ORM框架

基本介绍

模型概念

模型示例:

  1. 数据库的迁移

    1. 生成更新迁移文件
    2. 执行迁移脚本程序
    • 注:
  • 每次修改完模型类再对服务程序运行之前都需要做以上两步迁移操作。

    • 生成迁移脚本文件bookstore/migrations/0001_initial.py并进行迁移

      $ python3 manage.py makemigrations
      $ python3 manage.py migrate
      
  1. 编写模型类Models

Meta

  1. app_label 如果模型是在 INSTALLED_APPS 中的应用程序之外定义的,它必须声明属于哪个应用程序
  2. base_manager_name用于模型的 _base_manager管理器的属性名称,例如“对象”
  3. db_table用于模型的数据库表的名称
  4. … 具体见(https://docs.djangoproject.com/zh-hans/2.2/ref/models/options/)

例如:

from django.db import models
class 模型类名(models.Model):
    字段名 = models.字段类型(字段选项)
    class Meta:
    	db_table = 'xxxx'

字段类型

  1. BooleanField()

    • 数据库类型:tinyint(1)
    • 编程语言中:使用True或False来表示值
    • 在数据库中:使用1或0来表示具体的值
  2. CharField()

  3. DateField()

  4. DateTimeField()

  5. DecimalField()

  6. FloatField()

  7. EmailField()

  8. IntegerField()

  9. URLField()

  10. ImageField()

  11. TextField()

11.3 数据库迁移的错误处理方法

11.4 数据库的基本操作

管理器对象

  • 每个继承自 models.Model 的模型类,都会有一个 objects 对象被同样继承下来。这个对象叫管理器对象

  • 数据库的增删改查可以通过模型的管理器实现

    class MyModel(models.Model):
        ...
    MyModel.objects.create(...) # objects 是管理器对象
    

创建数据对象

Django shell 的使用

拓展:

settings.py里 APPEND_SLASH

APPEND_SLASH -> 自动补全 /

案例

url(r’^page1/$’, xx) ,访问浏览器时 地址栏输入 127.0.0.1:8000/page1 ,此时 django接到请求后

返回301【永久重定向】,并在响应头中指定重定向地址为 /page1/ ,从而出现自动补全 / 效果

若要关闭功能,可将 APPEND_SLASH = False

出现8000端口已占用 解决方案

1,查看是否有django进程启动

ps aux|grep ‘runserver

2,若grep中出现 相关进程,直接干!

kill -9 pid pid

案例如下

执行 查!
tarena@tedu:~/aid1906/django/day03/mysite3$ ps aux|grep 'runserver'
tarena    13984  0.0  0.4 125980 39604 pts/0    S+   15:39   0:00 python3 manage.py runserver
tarena    14914  1.2  0.5 202864 41312 pts/0    Sl+  16:10   0:05 /usr/bin/python3 manage.py runserver
tarena    15056  0.0  0.0  21532  1156 pts/4    S+   16:17   0:00 grep --color=auto runserv

#执行 干!
kill -9 13984 14914

11.5 CRUD增删改查

插入数据

插入一条数据

MyModel.objects.create(obj1)

批量创建数据

MyModel.objects.bulk_create([obj1, obj2, obj3])

查询数据

all()方法
  1. 在模型类中定义 def __str__(self): 方法可以将自定义默认的字符串

    class Book(models.Model):
        title = ...
        def __str__(self):
            return "书名: %s, 出版社: %s, 定价: %s" % (self.title, self.pub, self.price)
    
查询返回指定列(字典表示)
  • 方法: values(‘列1’, ‘列2’)

  • 用法: MyModel.objects.values(…)

  • 作用: 查询部分列的数据并返回

  • 返回值: QuerySet

  • 示例:

    from bookstore import models
    books = models.Book.objects.values("title", "pub")
    for book in books:
        print("书名", book["title"], '出版社:', book['pub'])
        print("book=", book)
    
查询返回指定列(元组表示)
  • 方法:values_list(‘列1’,‘列2’)

  • 用法:MyModel.objects.values_list(…)

  • 作用:

    • 返回元组形式的查询结果
  • 返回值: QuerySet容器对象,内部存放 元组

  • 示例:

    from bookstore import models
    books = models.Book.objects.values_list("title", "pub")
    for book in books:
    print("book=", book)  # ('Python', '清华大学出版社')...
    
排序查询
  • 方法:order_by

  • 用法:MyModel.objects.order_by(‘-列’,‘列’)

  • 作用:

    • 与all()方法不同,它会用SQL 语句的ORDER BY 子句对查询结果进行根据某个字段选择性的进行排序
  • 说明:

  • 默认是按照升序排序,降序排序则需要在列前增加’-‘表示

  • 示例:

    from bookstore import models
    books = models.Book.objects.order_by("-price")
    for book in books:
    print("书名:", book.title, '定价:', book.price)
    
  • 根据条件查询多条记录

    • 方法: filter(条件)

    • 语法:

      MyModel.objects.filter(属性1=1, 属性2=2)
      
    • 返回值:

    • 说明:

      • 多个属性在一起时为”与”关系,即当Books.objects.filter(price=20, pub="清华大学出版社") 返回定价为20 出版社为”清华大学出版社”的全部图书
    • 示例:

      # 查询书中出版社为"清华大学出版社"的图书
      from bookstore import models
      books = models.Book.objects.filter(pub="清华大学出版社")
      for book in books:
          print("书名:", book.title)
      
      2. 查询Author实体中id1并且isActive为True- authors=Author.objects.filter(id=1,isActive=True)
      
字段查找
  • 字段查询是指如何指定SQL语句中 WHERE 子句的内容。

  • 字段查询需要通过QuerySet的filter(), exclude() and get()的关键字参数指定。

  • 非等值条件的构建,需要使用字段查询

  • 示例:

    # 查询作者中年龄大于30
    Author.objects.filter(age__gt=30)
    # 对应
    # SELECT .... WHERE AGE > 30;
    
查询谓词
  1. __exact : 等值匹配

    Author.objects.filter(id__exact=1)
    # 等同于select * from author where id = 1
    
  2. __contains : 包含指定值

    Author.objects.filter(name__contains='w')
    # 等同于 select * from author where name like '%w%'
    
  3. __startswith : 以 XXX 开始

  4. __endswith : 以 XXX 结束

  5. __gt : 大于指定值

    Author.objects.filer(age__gt=50)
    # 等同于 select * from author where age > 50
    
  6. __gte : 大于等于

  7. __lt : 小于

  8. __lte : 小于等于

  9. __in : 查找数据是否在指定范围

    • 示例
    Author.objects.filter(country__in=['中国','日本','韩国'])
    # 等同于 select * from author where country in ('中国','日本','韩国')
    
  10. __range: 查找数据是否在指定的区间范围内

    # 查找年龄在某一区间内的所有作者
    Author.objects.filter(age__range=(35,50))
    # 等同于 SELECT ... WHERE Author BETWEEN 35 and 50;
    
  11. 详细内容参见: https://docs.djangoproject.com/en/1.11/ref/models/querysets/#field-lookups

  • 示例

    MyModel.objects.filter(id__gt=4)
    # 等同于 SELECT ... WHERE id > 4;
    
  • 练习:

    1. 查询Book表中price大于等于50的信息

      Book.objects.filter(price__gte=50)

    2. 查询Author表中姓王的人的信息

      Author.objects.filter(name__startswith=‘王’)

    3. 查询Author表中Email中包含”wc“的人的信息

      Author.objects.filter(email__contains=‘wc’)

  1. 不等的条件筛选

    • 语法:
      MyModel.objects.exclude(条件)

    • 作用:

      • 返回不包含此 条件 的 全部的数据集
    • 示例:

      • 查询 清华大学出版社,定价大于50 以外的全部图书
      books = models.Book.objects.exclude(pub="清华大学出版社", price__gt=50)
      for book in books:
          print(book)
      
查询指定的一条数
  • 语法:
    MyModel.objects.get(条件)

  • 作用:

    • 返回满足条件的唯一一条数据
  • 返回值:

    • MyModel 对象
  • 说明:

    • 该方法只能返回一条数据
    • 查询结果多余一条数据则抛出,Model.MultipleObjectsReturned异常
    • 查询结果如果没有数据则抛出Model.DoesNotExist异常
  • 示例:

    from bookstore import models
    book = models.Book.objects.get(id=1)
    print(book.title)
    

修改数据记录

修改单个实体的某些字段值的步骤:
    • 通过 get() 得到要修改的实体对象
    • 通过 对象.属性 的方式修改数据
  1. 保存
    • 通过 对象.save() 保存数据
  • 如:

    from bookstore import models
    abook = models.Book.objects.get(id=10)
    abook.market_price = "10.5"
    abook.save()
    
通过 QuerySet 批量修改 对应的全部字段
  • 直接调用QuerySet的update(属性=值) 实现批量修改

  • 如:

    # 将 id大于3的所有图书价格定为0元
    books = Book.objects.filter(id__gt=3)
    books.update(price=0)
    
    # 将所有书的零售价定为100元
    books = Book.objects.all()
    books.update(market_price=100)
    

练习:修改图书得零售

路由: /bookstore/mod/5

删除记录

  • 删除记录是指删除数据库中的一条或多条记录
  • 删除单个MyModel对象或删除一个查询结果集(QuerySet)中的全部对象都是调用 delete()方法
  1. 删除单个对象

  2. 删除查询结果集

    • 步骤

      1. 查找查询结果集中满足条件的全部QuerySet查询集合对象
      2. 调用查询集合对象的delete()方法实现删除
    • 示例:

      # 删除全部作者中,年龄大于65的全部信息
      auths = Author.objects.filter(age__gt=65)
      auths.delete()
      

聚合查询

  • 聚合查询是指对一个数据表中的一个字段的数据进行部分或全部进行统计查询,查bookstore_book数据表中的全部书的平均价格,查询所有书的总个数等,都要使用聚合查询
  1. 不带分组聚合

    • 不带分组的聚合查询是指导将全部数据进行集中统计查询

    • 聚合函数:

      • 定义模块: django.db.models
      • 用法: from django.db.models import *
      • 聚合函数:
        • Sum, Avg, Count, Max, Min
    • 语法:

      • MyModel.objects.aggregate(结果变量名=聚合函数(‘列’))
    • 返回结果:

      • 由 结果变量名和值组成的字典
      • 格式为:
        • `{“结果变量名”: 值}
    • 示例:

      # 得到所有书的平均价格
      from bookstore import models
      from django.db.models import Count
      result = models.Book.objects.aggregate(myAvg=Avg('price'))
      print("平均价格是:", result['myAvg'])
      print("result=", result)  # {"myAvg": 58.2}
      
      # 得到数据表里有多少本书
      from django.db.models import Count
      result = models.Book.objects.aggregate(mycnt=Count('title'))
      print("数据记录总个数是:", result['mycnt'])
      print("result=", result)  # {"mycnt": 10}
      
      
  2. 分组聚合

    • 分组聚合是指通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值总和),即为查询集的每一项生成聚合。

    • 语法:

      • QuerySet.annotate(结果变量名=聚合函数(‘列’))
    • 用法步骤:

      1. 通过先用查询结果MyModel.objects.value. 查找查询要分组聚合的列

        • MyModel.objects.value(‘列1’, ‘列2’)

        • 如:

          pub_set = models.Book.objects.values('pub')
          print(books)  # <QuerySet [{'pub': '清华大学出版社'}, {'pub': '清华大学出版社'}, {'pub_hou {'pub': '机械工业出版社'}, {'pub': '清华大学出版社'}]>
          
          
      2. 通过返回结果的 QuerySet.annotate 方法分组聚合得到分组结果

        • QuerySet.annotate(名=聚合函数(‘列’))

        • 返回 QuerySet 结果集,内部存储结果的字典

        • 如:

          pub_count_set = pub_set.annotate(myCount=Count('pub'))
          print(pub_count_set)  # <QuerySet [{'pub': '清华大学出版社', 'myCount': 7}, {'pub': '机械工业出版社', 'myCount': 3}]>
          
    • 示例:

      def test_annotate(request):
         - from django.db.models import Count
      from . import models
      
          # 得到所有出版社的查询集合QuerySet
          pub_set = models.Book.objects.values('pub')
          # 根据出版社查询分组,出版社和Count的分组聚合查询集合
          pub_count_set = pub_set.annotate(myCount=Count('pub'))  # 返回查询集合
          for item in pub_count_set:
              print("出版社:", item['pub'], "图书有:", item['myCount'])
          return HttpResponse('请查看服务器端控制台获取结果')
      

F对象

  • 一个F对象代表数据库中某条记录的字段的信息
  1. 作用:

    • 通常是对数据库中的字段值在不获取的情况下进行操作
    • 用于类属性(字段)之间的比较
  2. 用法

    • F对象在数据包 django.db.models 中,使用时需要先导入
      • from django.db.models import F
  3. 语法:

    from django.db.models import F
    F('列名')
    
  4. 说明:

    • 一个 F() 对象代表了一个model的字段的值
    • F对象通常是对数据库中的字段值在不加载内存中的情况下直接在数据库服务器端进行操作,可以避免资源竞争
  5. 示例1

    models.Book.objects.all().update(market_price=F('market_price')+10)
    # 以s做法好于如下代码
    books = models.Book.objects.all()
    for book in books:
        book.update(market_price=book.marget_price+10)
        book.save()
    
  6. 示例2

    from django.db.models import F
    from bookstore import models
    books = models.Book.objects.filter(market_price__gt=F('price'))
    for book in books:
        print(book.title, '定价:', book.price, '现价:', book.market_price)
    

Q对象 – Q()

  • 当在获取查询结果集 使用复杂的逻辑或 | 、 逻辑非 ~ 等操作时可以借助于 Q对象进行操作

  • 如: 想找出定价低于20元 或 清华大学出版社的全部书,可以写成

    models.Book.objects.filter(Q(price__lt=20)|Q(pub="清华大学出版社"))
    
  • Q对象在 数据包 django.db.models 中。需要先导入再使用

    • from django.db.models import Q
  1. 作用

    • 在条件中用来实现除 and(&) 以外的 or(|) 或 not(~) 操作
  2. 运算符:

    • & 与操作
    • | 或操作
    • 〜 非操作
  3. 语法

    from django.db.models import Q
    Q(条件1)|Q(条件2)  # 条件1成立或条件2成立
    Q(条件1)&Q(条件2)  # 条件1和条件2同时成立
    Q(条件1)&~Q(条件2)  # 条件1成立且条件2不成立
    ...
    
  4. 示例

    from django.db.models import Q
    # 查找清华大学出版社的书或价格低于50的书
    models.Book.objects.filter(Q(market_price__lt=50) | Q(pub_house='清华大学出版社'))
    # 查找不是机械工业出版社的书且价格低于50的书
    models.Book.objects.filter(Q(market_price__lt=50) & ~Q(pub_house='机械工业出版社'))
    

原生的数据库操作方法

  • 使用MyModel.objects.raw()进行 数据库查询操作查询

    • 在django中,可以使用模型管理器的raw方法来执行select语句进行数据查询
    1. 语法:

      • MyModel.objects.raw(sql语句)
    2. 用法

      • MyModel.objects.raw('sql语句')
    3. 返回值:

      • QuerySet 集合对象
  1. 示例

    books = models.Book.objects.raw('select * from bookstore_book')
    

for book in books:
​ print(book)
​ “`

12. admin 后台数据库管理

自定义后台管理数据表

  • 若要自己定义的模型类也能在 /admin 后台管理界中显示和管理,需要将自己的类注册到后台管理界面

  • 添加自己定义模型类的后台管理数据表的,需要用admin.site.register(自定义模型类) 方法进行注册

    • 配置步骤如下:

      1. 在应用app中的admin.py中导入注册要管理的模型models类, 如:

        from . import models
        
      2. 调用 admin.site.register 方法进行注册,如:

        from django.contrib import admin
        admin.site.register(自定义模型类)
        
    • 如: 在 bookstore/admin.py 添加如下代码对Book类进行管理

    • 示例:

      # file: bookstore/admin.py
      from django.contrib import admin
      # Register your models here.
      
      from . import models
      ...
      admin.site.register(models.Book)  # 将Book类注册为可管理页面
      

修改后台Models的展现形式

模型管理器类

数据库表管理

  1. 修改模型类字段的显示名字

    • 模型类各字段的第一个参数为 verbose_name,此字段显示的名字会在后台数据库管理页面显示

    • 通过 verbose_name 字段选项,修改显示名称示例如下:

      title = models.CharField(
          max_length = 30,
          verbose_name='显示名称'
      )
      
  2. 通过Meta内嵌类 定义模型类的属性及展现形式

    • 模型类可以通过定义内部类class Meta 来重新定义当前模型类和数据表的一些属性信息

    • 用法格式如下:

      class Book(models.Model):
          title = CharField(....)
          class Meta:
              1. db_table = '数据表名'
                  - 该模型所用的数据表的名称。(设置完成后需要立马更新步数据库)
              2. verbose_name = '单数名'
                  - 给模型对象的一个易于理解的名称(单数),用于显示在/admin管理界面3. verbose_name_plural = '复数名'
                  - 该对象复数形式的名称(复数),用于显示在/admin管理界面
  • 练习:
    • 将Book模型类 和 Author 模型类都加入后台管理
    • 制作一个AuthorManager管理器类,让后台管理Authors列表中显示作者的ID、姓名、年龄信息
    • 用后台管理程序 添加三条 Author 记录
    • 修改其中一条记录的年龄
    • 删除最后一条添加的记录
    • 将bookstore_author 数名表名称改为myauthor (需要重新迁移数据库)

13. 数据表关联关系映射

一对一映射

  • 一对一是表示现实事物间存在的一对一的对应关系。
  • 如:一个家庭只有一个户主,一个男人有一个妻子,一个人有一个唯一的指纹信息等
  1. 语法

    class A(model.Model):
        ...
    
    class B(model.Model):
        属性 = models.OneToOneField(A)
    
  2. 用法示例

    1. 创建作家和作家妻子类

      # file : xxxxxxxx/models.py
      from django.db import models
      
      class Author(models.Model):
          '''作家模型类'''
          name = models.CharField('作家', max_length=50)
          #wife 隐式定义
      
      class Wife(models.Model):
          '''作家妻子模型类'''
          name = models.CharField("妻子", max_length=50)
          author = models.OneToOneField(Author)  # 增加一对一属性
      
    2. 查询

      • 在 Wife 对象中,通过 author 属性找到对应的author对象
      • 在 Author 对象中,通过 wife 属性找到对应的wife对象
    3. 创始一对一的数据记录

      from . import models
      author1 = models.Author.objects.create(name='王老师')
      
      
      wife1 = models.Wife.objects.create(name='王夫人', author=author1)  # 关联王老师
      
      #wife1=models.wife.objects.create(name='王夫人', author_id=author1.id)
      
      author2 = models.Author.objects.create(name='小泽老师')  # 一对一可以没有数据对应的数据 
      
    4. 一对一数据的相互获取

      1. 正向查询

        • 直接通过关联属性查询即可
        # 通过 wife 找 author
        from . import models
        wife = models.Wife.objects.get(name='王夫人')
        print(wife.name, '的老公是', wife.author.name)
        
      2. 反向查询

        • 通过反向关联属性查询
        • 反向关联属性为实例对象.引用类名(小写),如作家的反向引用为作家对象.wife
        • 当反向引用不存在时,则会触发异常
        # 通过 author.wife 关联属性 找 wife,如果没有对应的wife则触发异常
        author1 = models.Author.objects.get(name='王老师')
        print(author1.name, '的妻子是', author1.wife.name)
        author2 = models.Author.objects.get(name='小泽老师')
        try:
            print(author2.name, '的妻子是', author2.wife.name)
        except:
            print(author2.name, '还没有妻子')
        
  • 作用:

  • 练习:

    1. 创建一个Wife模型类,属性如下
      1. name
      2. age
    2. 在Wife类中增加一对一关联关系,引用 Author
    3. 同步回数据库并观察结果

一对多映射

  • 一对多是表示现实事物间存在的一对多的对应关系。
  • 如:一个学校有多个班级,一个班级有多个学生, 一本图书只能属于一个出版社,一个出版社允许出版多本图书
  1. 用法语法

    • 当一个A类对象可以关联多个B类对象时
    class A(model.Model):
        ...
    
    class B(model.Model):
        属性 = models.ForeignKey(多对一中"一"的模型类, ...)
    
  2. 外键类ForeignKey

  3. 示例

    • 有二个出版社对应五本书的情况.
      1. 清华大学出版社 有书

        1. C++
        2. Java
        3. Python
      2. 北京大学出版社 有书

        1. 西游记
        2. 水浒
    1. 定义一对多类

      # file: one2many/models.py
      from django.db import models
      class Publisher(models.Model):
          '''出版社'''
          name = models.CharField('名称', max_length=50, unique=True)
      
      class Book(models.Model):
          title = models.CharField('书名', max_length=50)
          publisher = models.ForeignKey(Publisher, null=True)
      
      
    • 创建一对多的对象

      # file: xxxxx/views.py
      from . import models
      pub1 = models.Publisher.objects.create(name='清华大学出版社')
      models.Book.objects.create(title='C++', publisher=pub1)
      models.Book.objects.create(title='Java', publisher=pub1)
      models.Book.objects.create(title='Python', publisher=pub1)
      
      pub2 = models.Publisher.objects.create(name='北京大学出版社')
      models.Book.objects.create(title='西游记', publisher=pub2)
      models.Book.objects.create(title='水浒', publisher=pub2)
      
    • 查询:

      • 通过多查一
      # 通过一本书找到对应的出版社
      abook = models.Book.objects.get(id=1)
      print(abook.title, '的出版社是:', abook.publisher.name)
      
      • 通过一查多
      # 通过出版社查询对应的书
      pub1 = models.Publisher.objects.get(name='清华大学出版社')
      books = pub1.book_set.all()  # 通过book_set 获取pub1对应的多个Book数据对象
      # books = models.Book.objects.filter(publisher=pub1)  # 也可以采用此方式获取
      print("清华大学出版社的书有:")
      for book in books:
          print(book.title)
      
  • 练习:
    1. 完成Book 和 Publisher 之间的一对多
    2. 查看数据库效果
    3. 登录到后台,查看Book实体
  1. 数据查询

    1. 通过 Book 查询 Publisher

      通过 publisher 属性查询即可
      练习:
          查询 西游记 对应的出版社信息,打印终端
    2. 通过 Publisher 查询 对应的所有的 Books

      Django会在Publisher中增加一个属性来表示对对应的Book们的查询引用
      属性:book_set(MyModel.objects)
      

多对多映射

  • 多对多表达对象之间多对多复杂关系,如: 每个人都有不同的学校(小学,初中,高中,…),每个学校都有不同的学生
  1. 语法

    • 在关联的两个类中的任意一个类中,增加:
    属性 = models.ManyToManyField(MyModel)
    
  2. 示例

    • 一个作者可以出版多本图书
    • 一本图书可以被多名作者同时编写
    class Author(models.Model):
        ...
    
    class Book(models.Model):
        ...
        authors = models.ManyToManyField(Author)
    
  3. 数据查询

    1. 通过 Book 查询对应的所有的 Authors

      book.authors.all() -> 获取 book 对应的所有的author的信息
      book.authors.filter(age__gt=80) -> 获取book对应的作者中年龄大于80岁的作者的信息
      
    2. 通过 Author 查询对应的所有的Books

      • Django会生成一个关联属性 book_set 用于表示对对应的book的查询对象相关操作
      author.book_set.all()
      author.book_set.filter()
      author.book_set.create(...)  # 创建新书并联作用author
      author.book_set.add(book)   # 添加已有的书为当前作者author
      author.book_set.clear()  # 删除author所有并联的书
      
  4. 示例:

    • 多对多模型
    class Author(models.Model):
        '''作家模型类'''
        name = models.CharField('作家', max_length=50)
        def __str__(self):
            return self.name
    class Book(models.Model):
        title = models.CharField('书名', max_length=50)
        author = models.ManyToManyField(Author)
        def __str__(self):
            return self.title
    
    • 多对多视图操作
    from django.http import HttpResponse
    
    from . import models
    
    def many2many_init(request):
        # 创建两人个作者
        author1 = models.Author.objects.create(name='吕泽')
        author2 = models.Author.objects.create(name='王老师')
    
        # 吕择和王老师同时写了一本Python
        book11 = author1.book_set.create(title="Python")
        author2.book_set.add(book11)  #
    
        # 王老师还写了两本书
        book21 = author2.book_set.create(title="C")  # 创建一本新书"C"
        book22 = author2.book_set.create(title="C++")  # 创建一本新书"C++"
    
        return HttpResponse("初始化成功")
    
    def show_many2many(request):
        authors = models.Author.objects.all()
        for auth in authors:
            print("作者:", auth.name, '发出版了', auth.book_set.count(), '本书: ')
            for book in books:
                print('    ', book.title)
        print("----显示书和作者的关系----")
        books = models.Book.objects.all()
        for book in books:
            auths = book.author.all()
            print(book.title, '的作者是:', '、'.join([str(x.name) for x in auths]))
        return HttpResponse("显示成功,请查看服务器端控制终端")
    
    • 多对多最终的SQL结果
    mysql> select * from many2many_author;
    +----+-----------+
    | id | name      |
    +----+-----------+
    | 11 | 吕泽      |
    | 12 | 王老师    |
    +----+-----------+
    2 rows in set (0.00 sec)
    
    mysql> select * from many2many_book;
    +----+--------+
    | id | title  |
    +----+--------+
    | 13 | Python |
    | 14 | C      |
    | 15 | C++    |
    +----+--------+
    3 rows in set (0.00 sec)
    
    mysql> select * from many2many_book_author;
    +----+---------+-----------+
    | id | book_id | author_id |
    +----+---------+-----------+
    | 17 |      13 |        11 |
    | 20 |      13 |        12 |
    | 18 |      14 |        12 |
    | 19 |      15 |        12 |
    +----+---------+-----------+
    4 rows in set (0.00 sec)
    

14. cookiessession

cookies

  • cookies是保存在客户端浏览器上的存储空间,通常用来记录浏览器端自己的信息和当前连接的确认信息

  • cookies 在浏览器上是以键-值对的形式进行存储的,键和值都是以ASCII字符串的形存储(不能是中文字符串)

  • cookies 的内部的数据会在每次访问此网址时都会携带到服务器端,如果cookies过大会降低响应速度

  • 在Django 服务器端来设置 设置浏览器的COOKIE 必须通过 HttpResponse 对象来完成

  • HttpResponse 关于COOKIE的方法

  • Django中的cookies

    • 使用 响应对象HttpResponse 等 将cookie保存进客户端

      1. 方法1

        from django.http import HttpResponse
        resp = HttpResponse()
        resp.set_cookie('cookies名', cookies值, 超期时间)
        
        • 如:
        resp = HttpResponse()
        resp.set_cookie('myvar', "weimz", 超期时间)
        
      2. 方法二, 使用render对象

        from django.shortcuts import render
        resp = render(request,'xxx.html',locals())
        resp.set_cookie('cookies名', cookies值, 超期时间)
        
    1. 获取cookie

      • 通过 request.COOKIES 绑定的字典(dict) 获取客户端的 COOKIES数据

        value = request.COOKIES.get('cookies名', '没有值!')
        print("cookies名 = ", value)
        
    2. 注:

  • cookies 示例

    • 以下示例均在视图函数中调用

    • 添加cookie

      # 为浏览器添加键为 my_var1,值为123,过期时间为1个小时的cookie
      responds = HttpResponse("已添加 my_var1,值为123")
      responds.set_cookie('my_var1', 123, 3600)
      return responds
      
    • 修改cookie

      # 为浏览器添加键为 my_var1,修改值为456,过期时间为2个小时的cookie
      responds = HttpResponse("已修改 my_var1,值为456")
      responds.set_cookie('my_var1', 456, 3600*2)
      return responds
      
    • 删除cookie

      # 删除浏览器键为 my_var1的cookie
      responds = HttpResponse("已删除 my_var1")
      responds.delete_cookie('my_var1')
      return responds
      
    • 获取cookie

      # 获取浏览器中 my_var变量对应的值
      value = request.COOKIES.get('my_var1', '没有值!')
      print("cookie my_var1 = ", value)
      return HttpResponse("my_var1:" + value)
      
  • 综合练习:

session 会话控制

  • 什么session

  • session又名会话控制,是在服务器上开辟一段空间用于保留浏览器和服务器交互时的重要数据

  • session的起源

    • http协议是无状态的:每次请求都是一次新的请求,不会记得之前通信的状态
    • 实现状态保持的方式:在客户端或服务器端存储与会话有关的数据
    • 推荐使用sesison方式,所有数据存储在服务器端
  • 实现方式

    • 使用 session 需要在浏览器客户端启动 cookie,且用在cookie中存储sessionid
    • 每个客户端都可以在服务器端有一个独立的Session
    • 注意:不同的请求者之间不会共享个数据,与请求者一一对应
  • Django启用Session

    • 在 settings.py 文件中

    • 向 INSTALLED_APPS 列表中添加:

      INSTALLED_APPS = [
          # 启用 sessions 应用
          'django.contrib.sessions',
      ]
      
    • 向 MIDDLEWARE_CLASSES 列表中添加:

      MIDDLEWARE = [
          # 启用 Session 中间件
          'django.contrib.sessions.middleware.SessionMiddleware',
      ]
      
  • session的基本操作:

    • session对于象是一个在似于字典的SessionStore类型的对象, 可以用类拟于字典的方式进行操作
    • session 只能够存储能够序列化的数据,如字典,列表等。
    1. 保存 session 的值到服务器
      • request.session['KEY'] = VALUE
    2. 获取session的值
      • VALUE = request.session['KEY']
      • VALUE = request.session.get('KEY', 缺省值)
    • 删除session的值
      • del request.session['KEY']
    • 在 settings.py 中有关 session 的设置
      1. SESSION_COOKIE_AGE
        • 作用: 指定sessionid在cookies中的保存时长(默认是2周),如下:
        • SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2
      2. SESSION_EXPIRE_AT_BROWSER_CLOSE = True
        设置只要浏览器关闭时,session就失效(默认为False)
    • session 缺省配置
  • 注: 当使用session时需要迁移数据库,否则会出现错误

15. 网络云笔记项目

数据库设计

  • 模型类

    1. 用户模型类

      class User(models.Model):
          username = models.CharField("用户名", max_length=30, unique=True)
          password = models.CharField("密码", max_length=30)
      create_time = models.DateTimeField('创建时间', auto_now_add=True)
      
          def __str__(self):
              return "用户" + self.username
      
    2. 笔记模型类

    from django.db import models
    from user.models import User
    class Note(models.Model):
        title = models.CharField('标题', max_length=100)
        content = models.TextField('内容')
        create_time = models.DateTimeField('创建时间', auto_now_add=True)
        mod_time = models.DateTimeField('修改时间', auto_now=True)
    user = models.ForeignKey(User)
    
    ```
    

设计规范

  • 登陆设计规范(在user应用中写代码)

    路由正则 视图函数 模板位置 说明
    /user/login def login_view(request): templates/user/login.html 用户登陆
    /user/reg def reg_view(request): templates/user/register.html 用户注册
    /user/logout def logout_view(request): 退出用户登陆
    • 参考界面:
      • 登陆界面
        在这里插入图片描述

      • 注册界面
        在这里插入图片描述

  • 主页设计规范(在index应用中写代码)

    路由正则 视图函数 模板位置 说明
    / def index_view(request): templates/index/index.html 主页
    • 参考界面
      • 登陆前
        在这里插入图片描述

      • 登陆后
        在这里插入图片描述

  • 云笔记设计规范

    路由正则 视图函数 模板位置 说明
    /note/ def list_view(request): templates/note/list_note.html 显示笔记列表功能
    /note/add def add_view(request): templates/note/add_note.html 添加云笔记
    /note/mod/(d+) def mod_view(request, id): templates/note/mod_note.html 修改之前云笔记
    /note/del/(d+) def del_view(request, id): 无(返回列表页) 删除云笔记
    /note/(d+) def show_view(request, id): templates/note/note.html 查看单个云笔记
    • 参考界面
      • 登陆界面
        在这里插入图片描述

      • 注册界面
        在这里插入图片描述

      • 添加新笔记界面
        在这里插入图片描述

      • 显示笔记列表
        在这里插入图片描述

      • 修改云笔记
        在这里插入图片描述

      • 主页

        • 登陆前
          在这里插入图片描述

        • 登陆后
          在这里插入图片描述

16. 缓存

什么缓存

缓存是一类可以更快的读取数据的介质统称,也指其它可以加快数据读取的存储方式。一般用来存储临时数据,常用介质的是读取速度很快的内存

为什么使用缓存

视图渲染有一定成本,对于低频变动的页面可以考虑使用缓存技术,减少实际渲染次数

案例分析

from django.shortcuts import render

def index(request):
    # 时间复杂度极高的渲染
    book_list = Book.objects.filter()  #-> 此处假设耗时2s
    return render(request, 'index.html', locals())

优化思想

given a URL, try finding that page in the cache
if the page is in the cache:
    return the cached page
else:
    generate the page
    save the generated page in the cache (for next time)
    return the generated page

使用缓存场景

1,博客列表页

2,电商商品详情页

3,缓存导航页脚

Django中设置缓存

https://docs.djangoproject.com/en/1.11/topics/cache/

Django中提供多种缓存方式,如需使用需要在settings.py中进行配置

1,数据库缓存

Django可以将其缓存的数据存储在您的数据库中

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',
        'OPTIONS':{
   
            'MAX_ENTRIES': 300, #当前最大缓存
            'CULL_FREQUENCY': 3 #删除频率  1/cull_frequency
        }
        
        
    }
}

创建缓存表

python3 manage.py createcachetable

2,文件系统缓存

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',#这个是文件夹的路径
        #'LOCATION': 'c:testcache',#windows下示例
    }
}

3, 本地内存缓存

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake'
    }
}

Django中使用缓存

  • 在视图View中使用
  • 在路由URL中使用
  • 在模板中使用

在视图View中使用cache

from django.views.decorators.cache import cache_page

@cache_page(30)  -> 单位s
def my_view(request):
    ...

在路由中使用

from django.views.decorators.cache import cache_page

urlpatterns = [
    path('foo/', cache_page(60)(my_view)),
]

在模板中使用

{% load cache %}  
{% cache 50 sidebar  request.user.username %}   
    .. sidebar for logged in user ..
{% endcache %}

cache_key = sidebar + username

guoxiaonao访问 时 cache_key = sidebar + guoxiaonao

浏览器中的缓存

在这里插入图片描述

浏览器缓存分类:

强缓存

不会向服务器发送请求,直接从缓存中读取资源

1,Expires

缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点

Expires=max-age + 请求时间 UTC绝对时间

2019 10 27 xxx

Expires 是 HTTP/1 的产物,受限于本地时间,如果修改了本地时间,可能会造成缓存失效

2, Cache-Control

在HTTP/1.1中,Cache-Control主要用于控制网页缓存。比如Cache-Control:max-age=120 代表请求创建时间后的120秒,缓存失效

横向对比 Expires VS Cache-Control

协商缓存

**协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程

1,Last-Modified和If-Modified-Since

​ 第一次访问时,服务器会返回

Last-Modified: Fri, 22 Jul 2016 01:47:00 GMT

​ 浏览器下次请求时 携带If-Modified-Since这个header , 该值为 Last-Modified

​ 服务器接收请求后,对比结果,若资源未发生改变,则返回304, 否则返回200并将新资源返回给浏览器

​ 缺点:只能精确到秒,容易发生单秒内多次修改,检测不到

2,ETag和If-None-Match

​ Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成),只要资源有变化,Etag就会重新生成

流程同上

横向对比 Last-Modified VS ETag

17. 中间件 Middleware

  • 中间件是 Django 请求/响应处理的钩子框架。它是一个轻量级的、低级的“插件系统,用于全局改变 Django 的输入或输出

  • 每个中间件组件负责做一些特定的功能。例如,Django 包含一个中间件组件 AuthenticationMiddleware,它使用会话将用户与请求关联起来。

  • 他的文档解释了中间件是如何工作的,如何激活中间件,以及如何编写自己的中间件。Django 具有一些内置的中间件,你可以直接使用。它们被记录在 built-in middleware reference 中。

  • 中间件类:

    • 中间件类须继承自 django.utils.deprecation.MiddlewareMixin
    • 中间件类须实现下列五个方法中的一个或多个:
      • def process_request(self, request): 执行路由之前被调用,在每个请求上调用,返回None或HttpResponse对象
      • def process_view(self, request, callback, callback_args, callback_kwargs): 调用视图之前被调用,在每个请求上调用,返回None或HttpResponse对象
      • def process_response(self, request, response): 所有响应返回浏览器之前被调用,在每个请求上调用,返回HttpResponse对象
      • def process_exception(self, request, exception): 当处理过程中抛出异常时调用,返回一个HttpResponse对象
      • def process_template_response(self, request, response): 在视图刚好执行完毕之后被调用,在每个请求上调用,返回实现了render方法的响应对象
    • 注: 中间件中的大多数方法在返回None时表示忽略当前操作进入下一项事件,当返回HttpResponese对象时表示此请求结束,直接返回给客户端
  • 编写中间件类:

# file : middleware/mymiddleware.py
from django.http import HttpResponse, Http404
from django.utils.deprecation import MiddlewareMixin

class MyMiddleWare(MiddlewareMixin):
    def process_request(self, request):
        print("中间件方法 process_request 被调用")

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("中间件方法 process_view 被调用")

    def process_response(self, request, response):
        print("中间件方法 process_response 被调用")
        return response

    def process_exception(self, request, exception):
        print("中间件方法 process_exception 被调用")

    def process_template_response(self, request, response):
        print("中间件方法 process_template_response 被调用")
        return response
  • 注册中间件:
# file : settings.py
MIDDLEWARE = [
    ...
    'middleware.mymiddleware.MyMiddleWare',
]

在这里插入图片描述

  • 转折点在于视图,类似于出栈入栈,也类似于c/c++的构造析构函数
#单个中间件输出
MyMW process_request do---
MyMW process_views do ---
----this is test cache views ----
MyMW process_response do ---


#多个中间件时 输出
MyMW process_request do---
MyMW2 process_request do---
MyMW process_views do ---
MyMW2 process_views do ---
----this is test cache views ----
MyMW2 process_response do ---
MyMW process_response do ---

  • 中间件的执行过程
    在这里插入图片描述

  • 练习

    • 用中间件实现强制某个IP地址只能向/test 发送 5 次GET请求

    • 提示:

      • request.META[‘REMOTE_ADDR’] 可以得到远程客户端的IP地址
      • request.path_info 可以得到客户端访问的GET请求路由信息
    • 答案:

      from django.http import HttpResponse, Http404
      from django.utils.deprecation import MiddlewareMixin
      import re
      class VisitLimit(MiddlewareMixin):
          '''此中间件限制一个IP地址对应的访问/user/login 的次数不能改过10次,超过后禁止使用'''
          visit_times = {}  # 此字典用于记录客户端IP地址有访问次数
          def process_request(self, request):
              ip_address = request.META['REMOTE_ADDR']  # 得到IP地址
              if not re.match('^/test', request.path_info):
                  return
              times = self.visit_times.get(ip_address, 0)
              print("IP:", ip_address, '已经访问过', times, '次!:', request.path_info)
              self.visit_times[ip_address] = times + 1
              if times < 5:
                  return
      
              return HttpResponse('你已经访问过' + str(times) + '次,您被禁止了')
      

跨站请求伪造保护 CSRF

18. 分页

  • 分页是指在web页面有大量数据需要显示,为了阅读方便在每个页页中只显示部分数据。
  • 好处:
    1. 方便阅读
    2. 减少数据提取量,减轻服务器压力。
  • Django提供了Paginator类可以方便的实现分页功能
  • Paginator类位于django.core.paginator 模块中。

Paginator对象

  • 对象的构造方法

    • Paginator(object_list, per_page)
    • 参数
      • object_list 需要分类数据的对象列表
      • per_page 每页数据个数
    • 返回值:
  • Paginator属性

    • count:需要分类数据的对象总数
    • num_pages分页后的页面总数
    • page_range:从1开始的range对象, 用于记录当前面码数
    • per_page 每页数据的个数
  • Paginator方法

  • Paginator异常exception

    • InvalidPage:当向page()传入一个无效页码时抛出
    • PageNotAnInteger:当向page()传入一个不是整数的值时抛出
    • EmptyPage:当向page()提供一个有效值,但是那个页面上没有任何对象时抛出

Page对象

  • 创建对象
    Paginator对象的page()方法返回Page对象,不需要手动构造

  • Page对象属性

    • object_list:当前页上所有数据对象的列表
    • number:当前页的序号,从1开始
    • paginator:当前page对象相关的Paginator对象
  • Page对象方法

  • 说明:

    • Page 对象是可迭代对象,可以用 for 语句来 访问当前页面中的每个对象
  • 参考文档https://docs.djangoproject.com/en/1.11/topics/pagination/

  • 分页示例:

    • 视图函数
    from django.core.paginator import Paginator
    def book(request):
        bks = models.Book.objects.all()
        paginator = Paginator(bks, 10)
        print('当前对象的总个数是:', paginator.count)
        print('当前对象的面码范围是:', paginator.page_range)
        print('总页数是:', paginator.num_pages)
        print('每页最大个数:', paginator.per_page)
    
        #  /index?page=1
        cur_page = request.GET.get('page', 1)  # 得到默认的当前页
        page = paginator.page(cur_page)
        return render(request, 'bookstore/book.html', locals())
    
    • 模板设计
    <html>
    <head>
        <title>分页显示</title>
    </head>
    <body>
    {% for b in page %}
        <div>{{ b.title }}</div>
    {% endfor %}
    
    {# 分页功能 #}
    {# 上一页功能 #}
    {% if page.has_previous %}
    <a href="{% url 'book' %}?page={{ page.previous_page_number }}">上一页</a>
    {% else %}
    上一页
    {% endif %}
    
    {% for p in paginator.page_range %}
        {% if p == page.number %}
            {{ p }}
        {% else %}
            <a href="{% url 'book' %}?page={{ p }}">{{ p }}</a>
        {% endif %}
    {% endfor %}
    
    {#下一页功能#}
    {% if page.has_next %}
    <a href="{% url 'book' %}?page={{ page.next_page_number }}">下一页</a>
    {% else %}
    下一页
    {% endif %}
    总页数: {{ page.len }}
    </body>
    </html>
    

19. 文件上传

  • 文件上传必须为POST提交方式

  • 表单<form>中文件上传时必须有带有enctype="multipart/form-data" 时才会包含文件内容数据。

  • 表单中用<input type="file" name="xxx">标签上传文件

    • 名字xxx对应request.FILES['xxx'] 对应的内存缓冲文件流对象。可通能过request.FILES['xxx'] 返回的对象获取上传文件数据
    • file=request.FILES['xxx'] file 绑定文件流对象,可以通过文件流对象的如下信息获取文件数据
      file.name 文件名
      file.file 文件的字节流数据
  • 上传文件的表单书写方式

    <!-- file: index/templates/index/upload.html -->
    <html>
    <head>
        <meta charset="utf-8">
        <title>文件上传</title>
    </head>
    <body>
        <h3>上传文件</h3>
        <form method="post" action="/upload" enctype="multipart/form-data">
            <input type="file" name="myfile"/><br>
            <input type="submit" value="上传">
        </form>
    </body>
    </html>
    
  • 在setting.py 中设置一个变量MEDIA_ROOT 用来记录上传文件的位置

    # file : settings.py
    ...
    MEDIA_ROOT = os.path.join(BASE_DIR, 'static/files')
    
  • 在当前项目文件夹下创建 static/files 文件夹

    $ mkdir -p static/files
    
  • 添加路由及对应的处理函数

    # file urls.py
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^upload', views.upload_view)
    ]
    
  • 上传文件的视图处理函数

    # file views.py
    from django.http import HttpResponse, Http404
    from django.conf import settings
    import os
    
    def upload_view(request):
        if request.method == 'GET':
            return render(request, 'index/upload.html')
        elif request.method == "POST":
            a_file = request.FILES['myfile']
            print("上传文件名是:", a_file.name)
    
            filename =os.path.join(settings.MEDIA_ROOT, a_file.name)
            with open(filename, 'wb') as f:
                data = a_file.file.read()
                f.write(data)
                return HttpResponse("接收文件:" + a_file.name + "成功")
        raise Http404
    
  • 访问地址: http://127.0.0.1:8000/static/upload.html

后端缓存:

1, 将视图函数最终结果 转存到其他介质里

【mysql表里,文件里, 内存里】

2,解决了 views重复计算问题 【有效降低视图层时间复杂度

3,http 1.1 cache头 触发了 浏览器强缓存

浏览器缓存:

1,带有强缓存的响应头 的响应数据,存储自己的硬盘中或内存

2,当强缓存有数据时,可以完全不给服务器发送请求,直接读取缓存内容 【减少 浏览器与服务器之间的请求次数】

20. Django中的用户认证 (使用Django认证系统)

mysql> use myauth;
mysql> desc auth_user;
+--------------+--------------+------+-----+---------+----------------+
| Field        | Type         | Null | Key | Default | Extra          |
+--------------+--------------+------+-----+---------+----------------+
| id           | int(11)      | NO   | PRI | NULL    | auto_increment |
| password     | varchar(128) | NO   |     | NULL    |                |
| last_login   | datetime(6)  | YES  |     | NULL    |                |
| is_superuser | tinyint(1)   | NO   |     | NULL    |                |
| username     | varchar(150) | NO   | UNI | NULL    |                |
| first_name   | varchar(30)  | NO   |     | NULL    |                |
| last_name    | varchar(30)  | NO   |     | NULL    |                |
| email        | varchar(254) | NO   |     | NULL    |                |
| is_staff     | tinyint(1)   | NO   |     | NULL    |                |
| is_active    | tinyint(1)   | NO   |     | NULL    |                |
| date_joined  | datetime(6)  | NO   |     | NULL    |                |
+--------------+--------------+------+-----+---------+----------------+
11 rows in set (0.00 sec)

auth基本模型操作:

  • 创建用户

    • 创建普通用户create_user

      from django.contrib.auth import models
      user = models.User.objects.create_user(username='用户名', password='密码', email='邮箱',...)
      
      ...
      user.save()
      
    • 创建超级用户create_superuser

      from django.contrib.auth import models
      user = models.User.objects.create_superuser(username='用户名', password='密码', email='邮箱',...)
      ...
      user.save()
      
  • 删除用户

    from django.contrib.auth import models
    try:
        user = models.User.objects.get(username='用户名')
        user.is_active = False  # 记当前用户无效
        user.save()
        print("删除普通用户成功!")
    except:
        print("删除普通用户失败")
    return HttpResponseRedirect('/user/info')
    
  • 修改密码set_password

    from django.contrib.auth import models
    try:
        user = models.User.objects.get(username='xiaonao')
        user.set_password('654321')
        user.save()
        return HttpResponse("修改密码成功!")
    except:
        return HttpResponse("修改密码失败!")
    
  • 检查密码是否正确check_password

    from django.contrib.auth import models
    try:
        user = models.User.objects.get(username='xiaonao')
        if user.check_password('654321'):  # 成功返回True,失败返回False
            return HttpResponse("密码正确")
        else:
            return HttpResponse("密码错误")
    except:
        return HttpResponse("没有此用户!")
    

21. 生成CSV文件

Django可直接在视图函数中生成csv文件 并响应给浏览器

import csv
from django.http import HttpResponse
from .models import Book

def make_csv_view(request):
    response = HttpResponse(content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="mybook.csv"'
	all_book = Book.objects.all()
    writer = csv.writer(response)
    writer.writerow(['id', 'title'])
    for b in all_book:    
    	writer.writerow([b.id, b.title])
    return response
  • 响应获得一个特殊的MIME类型text / csv。这告诉浏览器该文档是CSV文件,而不是HTML文件
  • 响应会获得一个额外Content-Disposition标头,其中包含CSV文件的名称。它将被浏览器用于“另存为…”对话框
  • 对于CSV文件中的每一行,调用writer.writerow传递一个可迭代对象,如列表或元组。

22. 电子邮件发送

# 发送邮件设置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' # 固定写法
EMAIL_HOST = 'smtp.qq.com' # 腾讯QQ邮箱 SMTP 服务器地址
EMAIL_PORT = 25  # SMTP服务的端口号
EMAIL_HOST_USER = 'xxxx@qq.com'  # 发送邮件的QQ邮箱
EMAIL_HOST_PASSWORD = '******'  # 邮箱的授权码(即QQ密码)
EMAIL_USE_TLS = True  # 与SMTP服务器通信时,是否启动TLS链接(安全链接)默认false

mail.send_mail(subject='test1111', message='123',from_email='ding_t_f@163.com',recipient_list=['572708691@qq.com'], auth_password='gjy19881227')


视图函数中

from django.core import mail
mail.send_mail(
            subject,  #题目
            message,  # 消息内容
            from_email,  # 发送者[当前配置邮箱]
            recipient_list=['xxx@qq.com'],  # 接收者邮件列表
            auth_password='xxxxxxx'  # 在QQ邮箱->设置->帐户->“POP3/IMAP......服务” 里得到的在第三方登录QQ邮箱授权
            )

23. 项目部署

  1. 安装同版本的数据库

  2. django 项目迁移

    1. 安装python

      • $ sudo apt install python3
    2. 安装相同版本的包

    3. 将当前项目源代码复制远程主机上(scp 命令)

      • $ sudo scp -a 当前项目源代码 远程主机地址和文件夹

      • sudo scp -a /home/tarena/django/mysite1.zip root@88.77.66.55:/home/root/xxx
        请输入root密码:
        

WSGI Django工作环境部署

uWSGI 网关接口配置 (ubuntu 18.04 配置)

nginx 反向代理配置

nginx 配置静态文件路径

  • 解决静态路径问题

    # file : /etc/nginx/sites-available/default
    # 新添加location /static 路由配置,重定向到指定的绝对路径
    server {
        ...
        location /static {
            # root static文件夹所在的绝对路径,如:
            root /home/tarena/my_django_project; # 重定向/static请求的路径,这里改为你项目的文件夹
        }
        ...
    }
    
  • 修改配置文件后需要重新启动 nginx 服务

404 界面

  • 在模板文件夹内添加 404.html 模版,当视图触发Http404 异常时将会被显示

  • 404.html 仅在发布版中(即setting.py 中的 DEBUG=False时) 才起作用

  • 当向应处理函数触发Http404异常时就会跳转到404界面

    from django.http import Http404
    def xxx_view(request):
        raise Http404  # 直接返回404
    

原文地址:https://blog.csdn.net/weixin_46187354/article/details/130659907

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_32056.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注