Django3(一)

  第一部分初步认识django,第二部分具体介绍django的配置信息,第三部分一个小案例 

目录

一、第一个Django项目
(一)Django的简介

(二)安装

(三)创建Django项目

(四)模型类

(五)后台管理

(六)视图

(七)模板的使用

二、Django配置信息

(一)资源文件配置

(二)templates模板配置

(三)数据库配置

(四)路由

(五)第三方扩展分页

(六)富文本编辑器

(七)发送邮件

(八)站点配置

(九)表单

(十)验证码

(十一)全文检索

(十二)缓存

(十三)Ajax

(十四)中间件

(十五)本地部署

(十六)CSRF

三、实战项目:待办事项

 一、第一个Django项目 

(一)Django的简介

优点:Python 实现,代码干净、整洁,提供管理后台,能够快速开发,复用度高,设计使用上遵循DRY原则、易于扩展复用的中间件、内置的安全框架、丰富的第三方类库

缺点:单体应用-不易并行开发,单点扩展、不适合非常小的几行代码的项目、不适合于高并发的to C互联网项目

Django的设计思想:DRY (Don't repeat yourself) 不重复造轮子、MVT、快速开发、灵活易于扩展、松耦合、显式优于隐式。

流程:

客户端请求web页面——>controller(url.py) 去调用view(views.py)视图——>view保存请求,向model获取数据——>model调用数据库,更新数据,获取数据返回给view——>view视图使用数据填充到模板templates(.html)中——>最后发送给web页面内容到客户端。

django的生命周期:

发送http请求——>nginx服务器——>uwsgi服务器——>中间件——>路由——>视图——>orm——>从orm获取数据返回视图——>视图将数据传递给模板文件——>中间件——>uwsgi——>nginx——>生成响应内容

                                                                        ——Django 3 Web 应用开发实战

Django 模型-模板-视图 (MTV) 模式

模型:提供了到应用程序数据库的接口;

视图:提供显示逻辑,是用户和Django 应用程序之间的接口;

控制器:管理大部分应用程序数据处理、应用程序逻辑和消息传递。

Django 的模型为底层数据库提供了对象关系映射 (ORM)。ORM 是一种强大的编程技术,它使处理数据和关系数据库变得更加容易。

​(二)安装

 anaconda下载

Anaconda | Individual Edition

Python科学计算工具包:数据科学家的工具箱
包含了Python二进制发行包
包含Numpy, Pandas,Matplotlib, SciPy, Bokeh, Jupyter,PyTorch, Tensorflow等科学处理工具
包含了一个开源的Python IDE: Spyder
包含了Conda包管理软件: conda install xxx

使用conda命令安装Django

conda install django

pycharm下载

Download PyCharm: Python IDE for Professional Developers by JetBrains

pycharm安装Django

File——setting——Project

Django3(一)_第1张图片​​

​(三)创建Django项目

django-admin startproject MyDjango        #创建的项目名:MyDjango

cd MyDjango        # 进入该目录

python manage.py startapp index  #创建应用:index

​​

可以使用cmd的tree命令查看目录树

tree /f 

Django3(一)_第2张图片​​

migrations文件夹是 Django 存储迁移或数据库更改的地方

views.py: 接收请求,进行处理,与M和T进行交互,返回应答。定义处理函数,视图函数

tests.py:包含在测试您的应用程序时运行的测试程序。

apps.py:是所有 Django 应用程序通用的配置文件

admin.py:网站后台管理相关的文件。建立应用和项目之间的联系,需要对应用进行注册,修改settings.py中的INSTALLED_APPS配置项

_init.py:说明目录是一个Python模块

models.py:写和数据库项目的内容,每个类可以关联一张数据表

Django3(一)_第3张图片​​

python manage.py migrate 

运行开发web服务器命令

python manage.py runserver 8002

Django3(一)_第4张图片​​

Django3(一)_第5张图片​​

 没有设置端口就默认端口为8000

Django3(一)_第6张图片​​

  注:没有ico图标,所以在日志中报错404,没影响

(四)模型类

模型设计类

在models.py中设计模型类

必须继承与models.Model类

Django3(一)_第7张图片

1)设计BookInfo类

2)设计HeroInfo类

Models.ForeignKey可以建立两个模型类之间一对多的关系,django在生成表的时候,就会在多的表中创建一列作为外键,建立两个表之间一对多的关系。

diango.中内嵌了ORM框架,ORM框架可以将类和数据表进行对应起来,只需要通过类和对象就可以对数据表进行操作。

设计类︰模型类。

ORM另外一个作用︰根据设计的类生成数据库中的表。

第一个表BookInfo类

from django.db import models

# Create your models here.
#图书类
class BookInfo(models.Model):#继承于models模块里的Model类
    #图书模型类
    #类属性对应表里的字段
    #图书名称,CharField说明是一个字符串,max_length指定字符串的最大长度
    btitle=models.CharField(max_length=20)
    #出版日期,DateField说明是一个日期模型
    bpub_date=models.DateField()

1)生成迁移文件

命令: python manage.py makemigrations 迁移文件是根据模型类生成的。

​​

Django3(一)_第8张图片​​

2)执行迁移生成表

命令: python manage.py migrate 根据迁移文件生成表.

生成表名的默认格式:

应用名_模型类名小写

Django3(一)_第9张图片​​

Django3(一)_第10张图片​​

Django3(一)_第11张图片​​

第二个表HeroInfo类

# 关系属性对应的表的字段名格式:关系属性名_id(外键)
from django.db import models

# Create your models here.
#一类
#图书类
class BookInfo(models.Model):#继承于models模块里的Model类
    #图书模型类
    #类属性对应表里的字段
    #图书名称,CharField说明是一个字符串,max_length指定字符串的最大长度
    btitle=models.CharField(max_length=20)
    #出版日期,DateField说明是一个日期模型
    bpub_date=models.DateField()
#多类
#人物类
class HeroInfo(models.Model):
    hname=models.CharField(max_length=20)#名
    hgender=models.BooleanField(default=False)#性别,BooleanField说明是bool类型,default指定默认值,False代表男
    #备注
    hcomment=models.CharField(max_length=128)
    # 关系属性,建立图书和物一对多关系
    # 关系属性对应的表的字段名格式:关系属性名_id(外键)
    hbook=models.ForeignKey(to="BookInfo",on_delete=models.CASCADE)

​​

Django3(一)_第12张图片​​

 如果报错TypeError: __init__() missing 1 required positional argument: 'on_delete'

 问题出在models.py,应写上:

hbook=models.ForeignKey(to="BookInfo",on_delete=models.CASCADE)

 python manage.py migrate

Django3(一)_第13张图片​​

Django3(一)_第14张图片​​

数据库操作

Django3(一)_第15张图片​​

表1

Django3(一)_第16张图片​​

增删查改语句:

插入语句

Django3(一)_第17张图片​​

查询语句

Django3(一)_第18张图片​​

更新语句

​​

删除语句

​​

(五)后台管理

Django 带有一个内置的管理界面。使用 Django 的管理员,您可以验证用户、显示和处理表单以及验证输入;全部自动。Django 还提供了一个方便的接口来管理模型数据。

1)本地化

语言和时区的本地化

修改settings.py

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

2)创建管理员

python manage.py createsuperuser

Django3(一)_第19张图片​​

 打开浏览器,输入网址http://127.0.0.1:8000/admin

Django3(一)_第20张图片​​

索引页面的顶部是Authentication and Authorization组,其中包含两种类型的可编辑内容:Groups和Users。它们由 Django 中包含的authentication framework 提供.

Django3(一)_第21张图片​​

3)注册模型类

在应用下的admin.py中注册模型类

告诉django框架根据注册的模型类来生成对应表管理页面

b=BookInfo()

 str(b)_str_

from django.contrib import admin
from index.models import BookInfo
# 后台管理相关文件
# Register your models here.
#注册模型类
admin.site.register(BookInfo)

Django3(一)_第22张图片​​

Django3(一)_第23张图片​​

Django3(一)_第24张图片​​

显示图书标题

Django3(一)_第25张图片​​

查看str返回值

​​

改变str返回值

models.py里重写方法

class BookInfo(models.Model):#继承于models模块里的Model类
    #图书模型类
    #类属性对应表里的字段
    #图书名称,CharField说明是一个字符串,max_length指定字符串的最大长度
    btitle=models.CharField(max_length=20)
    #出版日期,DateField说明是一个日期模型
    bpub_date=models.DateField()

    def __str__(self):
        # 返回书名
        return self.btitle
右侧可增加BOOK INFO

Django3(一)_第26张图片​​

同理,增加第二个表Hero infos类

admin.py

from django.contrib import admin
from index.models import BookInfo,HeroInfo
# 后台管理相关文件
# Register your models here.
#注册模型类
admin.site.register(BookInfo)
admin.site.register(HeroInfo)

models.py

from django.db import models

# Create your models here.
#一类
#图书类
class BookInfo(models.Model):#继承于models模块里的Model类
    #图书模型类
    #类属性对应表里的字段
    #图书名称,CharField说明是一个字符串,max_length指定字符串的最大长度
    btitle=models.CharField(max_length=20)
    #出版日期,DateField说明是一个日期模型
    bpub_date=models.DateField()

    def __str__(self):
        # 返回书名
        return self.btitle

#多类
#人物类
class HeroInfo(models.Model):
    hname=models.CharField(max_length=20)#名
    hgender=models.BooleanField(default=False)#性别,BooleanField说明是bool类型,default指定默认值,False代表男
    #备注
    hcomment=models.CharField(max_length=128)
    # 关系属性,建立图书和物一对多关系
    # 关系属性对应的表的字段名格式:关系属性名_id(外键)
    hbook=models.ForeignKey(to="BookInfo",on_delete=models.CASCADE)
    def __str__(self):
        # 返回名字
        return self.hname

Django3(一)_第27张图片​​

4)自定义管理页面

自定义模型管理类,模型管理类就是生成django在生成的管理页面上显示哪些内容

 admin.py

from django.contrib import admin
from index.models import BookInfo,HeroInfo
# 后台管理相关文件
# Register your models here.
#自定义模型管理类
#图书模型管理类
class BookInfoAdmin(admin.ModelAdmin):#继承于admin.ModelAdmin
    # list_display页面显示的内容
    list_display=['id','btitle','bpub_date']#类属性
#英雄人物管理类
class HeroInfoAdmin(admin.ModelAdmin):
    list_display = ['id', 'hname', 'hcomment']
#注册模型类:只能各写一个,不能重复写
admin.site.register(BookInfo,BookInfoAdmin)
admin.site.register(HeroInfo,HeroInfoAdmin)

Django3(一)_第28张图片​​

Django3(一)_第29张图片​​

(六)视图

 在Django中,视图从数据库(或外部数据源或服务)获取数据并将其传递到模板。

通过浏览器去请求一个页面时,使用视图函数来处理这个请求的,视图函数处理之后,要给浏览器返回页面内容。

视图函数的使用

1)定义视图函数

视图函数定义在views.py中

index/urls.py

导入path对所有urls.py文件都是通用的。导入本地views.py文件,. 是当前包的简写,表示“从当前包导入所有视图。

urlpatterns 列出了为此应用注册的 URL 模式。该列表分为多行,每行一个 URL 模式。
比如:from . import views            path('', views.index, name='index')
单引号 '' 匹配一个空字符串。它也会匹配“/”,Django会自动删除斜杠。比如匹配http://xxxxxx.com和http://xxxxxxxxx.com/。
views.index指向index。即点运算符指向导入的文件中的index视图。views.py
name='index'虽然它是可选的,但应该命名URL,以方便可以在代码中引用(反向查找)。

from django.urls import path
from . import views
# 创建一个列表
# url地址和视图的对应
urlpatterns=[
    # 通过url函数设置url路由配置项,要先在项目的urls中加配置项
    # 建立/index和视图index之间的关系
    path('index',views.index), #左边index:index文件夹。括号内为地址和地址对应的视图
    path('index2',views.index2),
]

Mydjango/urls.py

空字符串 ( '') 将匹配域名之后的所有内容。

from django.urls import path
from django.conf.urls import include, url
from django.contrib import admin

# 项目的urls文件#这里容易报错
urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include('index.urls')),#包括booktest应用中的url文件
]

views.py

from django.http import HttpResponse

# Create your views here.
# 1.定义视图函数,HttpRequest
# 2.进行url配置,建立url地址和视图的对应关系
# http://127.0.0.1:8000/index
def index(request):
    # 进行处理,和M和T进行交互
    return HttpResponse('hello~')  # 返回给浏览器
def index2(request):
    # 进行处理,和M和T进行交互
    return HttpResponse('你好~')  # 返回给浏览器
python manage.py runserver

Django3(一)_第30张图片​​

Django3(一)_第31张图片​​

  1. 浏览器向 Django 开发服务器发送了一条消息,请求它返回位于根 URL ( http://127.0.0.1:8000/) 的内容。
  2. Django 查找与请求匹配的 URL 模式,首先搜索urls.py,然后在每个应用程序中urls.py查找包含匹配模式的文件。
  3. Django检查第一个urls.py,admin/不匹配的模式 ,移动到第二行空字符串(根 URL)匹配。
  4. urls.py,查找匹配的模式。
  5. 进入urls.py,空字符串再次匹配。这次请求被发送到index视图。
  6. 然后index视图将我们的简单 HTML 消息呈现给 aHttpResponse并将其发送到浏览器。
  7. 浏览器呈现响应,看到页面。

(七)模板的使用

1、模板语法

显示逻辑。例如,{% if %}...{% endif %}
回路控制。例如,{% for x in y %}...{% endfor %}
块声明。例如,{% block content %}...{% endblock %}
内容导入。例如,{% include "header.html" %}
继承。例如,{% extends "base.html"%}
简单变量。例如,{{ title }}
对象属性。例如,{{ page.title }}
字典查找。例如,{{ dict.key }}
列出索引。例如,{{ list_items.0 }}
方法调用。例如{{ var.upper }},{{ mydict.pop }}
改变变量过滤器语法{ { 变量|过滤器 }}。例如,{{ name|title }}或{{ units|lower }}
截断。例如,{{ post_content|truncatewords:50 }}
日期格式。例如,{{ order_date|date:"D M Y" }}
列表切片。例如,{{ list_items|slice:":3" }}
默认值。例如,{{ item_total|default:"nil" }}
多行注释。例如,{ % comment % }...{ % endcomment % }

2、新建文件夹

Django3(一)_第32张图片​​




    
    模板文件


这是一个模板文件,{{ content }}

Django3(一)_第33张图片​​

views.py

from django.shortcuts import render
from django.http import HttpResponse
from django.template import loader,RequestContext


def my_render(request, template_path, context_dict={}):
    #使用模板文件
    #1.加载模板文件,模板对象
    temp=loader.get_template(template_path)
    #2.定义模板上下文:给模板文件传递数据
    # context=RequestContext(request,context_dict)#这个会报错
    context =context_dict
    #3.模板渲染:产生标准的html内容
    res_html=temp.render(context)
    #4.返回给浏览器
    return HttpResponse(res_html)

# Create your views here.
# 1.定义视图函数,HttpRequest
# 2.进行url配置,建立url地址和视图的对应关系
# http://127.0.0.1:8000/index
def index(request):
    # 进行处理,和M和T进行交互
    # return HttpResponse('hello~')  # 返回给浏览器
    return my_render(request,'index/index.html',{'content':'hello word'})
index/urls.py
from django.urls import path
from . import views
# 创建一个列表
# url地址和视图的对应
urlpatterns=[
    # 通过url函数设置url路由配置项,要先在项目的urls中加配置项
    # 建立/index和视图index之间的关系
    path('index',views.index), #左边index:index文件夹。括号内为地址和地址对应的视图
]

Django3(一)_第34张图片​​

连接数据库

新建html

Django3(一)_第35张图片​​




    
    显示图书


{% for book in books %}
    
  • {{ book.btitle }}
  • {% endfor %}
    #views.py
    from django.shortcuts import render
    
    from index.models import BookInfo#导入图书模型类
    from django.http import HttpResponse
    from django.template import loader,RequestContext
    
    
    def my_render(request, template_path, context_dict={}):
        #使用模板文件
        #1.加载模板文件,模板对象
        temp=loader.get_template(template_path)
        #2.定义模板上下文:给模板文件传递数据
        # context=RequestContext(request,context_dict)#这个会报错
        context =context_dict
        #3.模板渲染:产生标准的html内容
        res_html=temp.render(context)
        #4.返回给浏览器
        return HttpResponse(res_html)
    
    # Create your views here.
    # 1.定义视图函数,HttpRequest
    # 2.进行url配置,建立url地址和视图的对应关系
    # http://127.0.0.1:8000/index
    def index(request):
        # 进行处理,和M和T进行交互
        # return HttpResponse('hello~')  # 返回给浏览器
        return my_render(request,'index/index.html',{'content':'hello word'})
    
    def index2(request):
        # 进行处理,和M和T进行交互
        return HttpResponse('你好~')  # 返回给浏览器
    
    def show_books(request):
        books=BookInfo.objects.all()
        return render(request,'index/show_books.html',{'books':books})
    #MyDjango/urls.py
    from django.urls import path
    from django.conf.urls import include
    from django.contrib import admin
    
    # 项目的urls文件
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('',include('index.urls')),#包括booktest应用中的url文件
    #index/urls.py
    from django.urls import path
    from . import views
    # 创建一个列表
    # url地址和视图的对应
    urlpatterns=[
        # 通过url函数设置url路由配置项,要先在项目的urls中加配置项
        # 建立/index和视图index之间的关系
        path('index',views.index), #左边index:index文件夹。括号内为地址和地址对应的视图
        path('index2',views.index2),
        path('books',views.show_books),#显示图书信息
    ]

    Django3(一)_第36张图片​​

    二、Django配置信息

                                                                                            ——参考Django3 web应用开发实战

    (一)资源文件配置

    Django配置文件settings.py:用于配置整个网站的环境和功能。

    核心配置:项目路径、密钥配置、域名访问权限、App列表、中间件、资源文件、模板配置、数据库的连接方式。

    资源文件配置

    先建4个文件夹,放一些图片进去,名字如图

    Django3(一)_第37张图片

    这里有两个static文件,系统默认的是index下的static文件

    Django3(一)_第38张图片

    静态资源文件

    settings.py文件中先在INSTALLED_APPS注册应用index,第39行。

    然后配置静态文件信息 ,添加以下代码119行——123行

    """
    Django settings for MyDjango project.
    
    Generated by 'django-admin startproject' using Django 3.2.9.
    
    For more information on this file, see
    https://docs.djangoproject.com/en/3.2/topics/settings/
    
    For the full list of settings and their values, see
    https://docs.djangoproject.com/en/3.2/ref/settings/
    """
    import os
    from pathlib import Path
    
    # 项目目录的绝对路径。主要通过os模块读取当前项目在计算机系统的具体路径。
    # 创建项目时系统自动生成,一般不用改。
    BASE_DIR = Path(__file__).resolve().parent.parent
    
    # 密钥配置。用于重要数据的加密处理,提高项目的安全性。
    # 密钥主要用于用户密码(Auth认证系统,将用户密码加密)、CSRF机制(表单提交,防窃取用户信息制造恶意请求)和会话Session(存放在Cookie中)等数据加密。
    # 创建项目时系统自动生成随机值,一般不用改。
    SECRET_KEY = 'django-insecure-70+4nbazxyc#v6l5axu=l29yf-(69)-8&jo4*wu=t^i2vt$_71'
    
    # 调试模式,开发阶段为True,项目部署上线就要改为False,否则会泄露项目相关信息。
    DEBUG = True
    
    # 域名访问权限。设置可访问的域名,当DEBUG = True,ALLOWED_HOSTS = []空列表时,项目只允许localhost在浏览器访问。
    # 当DEBUG = False,ALLOWED_HOSTS = 必填,否则程序无法启动。如果要所有域名都可以访问可设为ALLOWED_HOSTS = [‘*’]
    ALLOWED_HOSTS = []
    
    # App列表
    INSTALLED_APPS = [
        'django.contrib.admin',  # 内置的后台管理系统
        'django.contrib.auth',  # 用户认证系统
        'django.contrib.contenttypes',  # 记录项目中所有model元数据(orm框架)
        'django.contrib.sessions',  # 会话功能,标识当前访问网站用户身份,记录相关用户信息
        'django.contrib.messages',  # 消息提示功能
        'django.contrib.staticfiles',  # 查找静态资源路径
        'index'  # 在项目中创建了app,就必须在这列表里添加app名称
    ]
    
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    
    ROOT_URLCONF = 'MyDjango.urls'
    
    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',
                ],
            },
        },
    ]
    
    WSGI_APPLICATION = 'MyDjango.wsgi.application'
    
    # Database
    # https://docs.djangoproject.com/en/3.2/ref/settings/#databases
    
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': BASE_DIR / 'db.sqlite3',
        }
    }
    
    # Password validation
    # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
    
    AUTH_PASSWORD_VALIDATORS = [
        {
            'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
        },
    ]
    
    # Internationalization
    # https://docs.djangoproject.com/en/3.2/topics/i18n/
    
    # LANGUAGE_CODE = 'en-us'#后台管理中的本地化语言,中文:zh-hans
    LANGUAGE_CODE = 'zh-hans'
    
    # TIME_ZONE = 'UTC' 使用国际标准时间UTC:
    # 所有时间在存入数据库前,必须转换成UTC时间。当使用时区时,Django存储在数据库中的所有日期时间信息都以UTC时区为准,在后台使用有时区的datetime,前台用户使用时,在网页上翻译成用户所在的时区。
    # 后台向数据库输入日期时间时,日期时间应该带有时区信息,如果没有,输入数据库时会有警告
    TIME_ZONE = 'Asia/Shanghai'  # 中国时间:Asia/Shanghai
    
    USE_I18N = True
    
    USE_L10N = True
    
    USE_TZ = True
    
    # # Static files (CSS, JavaScript, Images)。
    # # 静态资源的路由地址:通过浏览器访问Django的静态资源。查找功能由App列表——INSTALLED_APPS——staticfiles
    STATIC_URL = '/static/'
    # # 设置根目录的静态资源文件夹static
    STATICFILES_DIRS = [BASE_DIR / 'static',
                        # 设置App(index)的静态资源文件夹Mystatic
                        BASE_DIR / 'index/Mystatic', ]
    
    # 资源部署:在服务器上部署项目,实现服务器和项目之间的映射。STATIC_ROOT主要收集整个项目的静态资源并存放在一个新的文件夹,由该文件夹与服务器之间构建映射关系。
    # 项目部署上线DEBUG = False,Django不在提供静态文件代理服务,需要设置STATIC_ROOT。项目开发阶段就不需要设置,会自动提供。
    # STATIC_ROOT=BASE_DIR/'AllStatic'
    
    # Default primary key field type
    # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
    
    DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

    运行一下python manage.py runserver 8000

    STATIC_URL名字(static)就是指浏览器网址地址,所以和网址名字.../static/....对应。

    打开浏览器输入网址,就可以看到图片了。

    Django3(一)_第39张图片

    Django3(一)_第40张图片

    媒体资源文件

    先配置媒体资源属性,然后注册到Django里。

    settings.py文件下添加以下代码

    # 媒体资源配置
    # 设置媒体路由地址信息
    MeDIA_URL='/media/'
    # 获取media文件夹的完整路径信息
    MEDIA_ROOT=BASE_DIR/'media'

    Django3(一)_第41张图片

    Django3(一)_第42张图片

    MyDjango—urls.py文件如下

    from django.urls import path,re_path
    from django.conf.urls import include
    from django.contrib import admin
    from django.views.static import serve
    from django.conf import settings
    
    # 项目的urls文件
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('',include('index.urls')), 
        # 配置媒体文件的路由地址
        re_path('media/(?P.*)',serve,{'document_root':settings.MEDIA_ROOT},name='media'),
    ]

    (二)templates模板配置

    模板是Django里面的MTV框架模式的T部分,配置模板路径是在解析模板时,找到模板的所在的位置。

    模板配置通常配置DIRS的属性即可。

    创建两个templates文件夹,并在文件夹下分别创建两个html

    Django3(一)_第43张图片

    一般根目录的templates存放共用模板文件

    settings.py文件模板配置如下:

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',       # 定义模板引擎,用于识别模板里面的变量和指令。内置模板引擎有Django Templates和jinja2.Jinja2,每个模板引擎都有自己的变量和指令语法。
           #注册根目录和index的templates文件夹
           'DIRS': [os.path.join(BASE_DIR, 'templates',
                                  BASE_DIR, 'index/templates')],  # 设置模板文件路径,每个模板引擎都有自己的变量和指令语法。
            'APP_DIRS': True,   # 是否在App里查找模板文件
            'OPTIONS': {    # 用于填充在RequestContext的上下文(模板里面的变量和指令),一般情况下不做修改
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]

    (三)数据库配置

    1、mysqlclient连接mysql

    Django提供4种数据库引擎

    django.db.backends.postgresql

    django.db.backends.mysql

    django.db.backends.sqlite3

    django.db.backends.oracle

    下载mysqlclient,版本要和Python版本相匹配

    https://www.lfd.uci.edu/~gohlke/pythonlibs/#mysqlclient

    Django3(一)_第44张图片

    安装pip install E:\1203\mysqlclient-1.4.6-cp39-cp39-win_amd64.whl

    Django3(一)_第45张图片

     在settings.py中配置MySQL数据库连接信息,

    # 数据库配置
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',#选择的数据库引擎mysql
            'NAME': 'django_db',    # 创建默认Sqlite3,轻型数据库,用于切入式系统开发,占用资源少
            'USER':'root',
            'PASSWORD':'1234',
            'HOST':'127.0.0.1',
            'PORT':'3306',
        }
    }

    新建一个数据库

    Django3(一)_第46张图片

    创建Django内置功能(如Admin后台系统、Auth用户系统和会话机制等功能)的数据表:python manage.py migrate将内置的迁移文件生成数据表

    Django3(一)_第47张图片

    就可以看到在数据库中已经生成相应的表了

    Django3(一)_第48张图片

    注意Django对应的mysqlclient的版本要求,

    Django3(一)_第49张图片

    Django3(一)_第50张图片

     如果发现mysqlclient版本过低,可以将if条件判断注释。

    2、pymysql连接MySQL

    pip install pymysql

     settings.py数据库配置不用改,在MyDjango文件夹中的__init__.py中设置数据库连接模块即可。

    import pymysql
    pymysql.install_as_MySQLdb()    # 设置数据库连接模块

    3、多个数据库的连接方式

    # 数据库配置
    DATABASES = {
        # 第一个数据库,default是默认的数据库不可删除,可留空{}
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'django_db',
            'USER':'root',
            'PASSWORD':'1234',
            'HOST':'127.0.0.1',
            'PORT':'3306',
        },
        # 第二个数据库
        'MyDjango': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'mydjango_db',
            'USER': 'root',
            'PASSWORD': '1234',
            'HOST': '127.0.0.1',
            'PORT': '3306',
        },
        # 第三个数据库
        'MySqlite3': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': BASE_DIR/'django_db',  # BASE_DIR,数据库在项目路径下生成
        },
    }

    4、使用配置文件动态连接数据库

    在MyDjango目录下创建配置文件my.cnf,写入MySOL数据库的连接信息。

    [client]客户端设置,即客户端默认的连接参数
    [client]
    database=django_db
    user=root
    password=1234
    host=127.0.0.1
    port=3306

    在settings.py写配置信息。default--OPTIONS--read_default_file中设置配置文件my.cnf的路径,Django读取配置文件my.cnf的数据库连接信息,连接数据库。

    # 数据库配置
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'OPTIONS': {'read_default_file':str(BASE_DIR / 'my.cnf')},
        },
    
    }

    在MyDjango的urls.py中设置路由index,路由的视图函数indexView()在项目应用index的view.py中定义。

    from django.urls import path
    from django.contrib import admin
    from index.views import index  # 导入项目应用index
    # 项目的urls文件
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('',index,name='index'),
    ]

    在项目应用index的view.py中定义路由index的视图函数indexView()。

     indexView()读取并输出Django内置函数ContentType的数据,请求响应的内容为templates文件夹的app_index.html

    from django.shortcuts import render
    from django.contrib.contenttypes.models import ContentType
    def indexView(request):
        c=ContentType.objects.values_list().all()
        print(c)
        return render(request,'app_index.html')

    app_index.html

    
    
    
        
        Hello
    
    
        Hello World!!
    
    

    python manage.py migrate

    Django3(一)_第51张图片

     python manage.py runserver 8001

    Django3(一)_第52张图片

    5、通过SSH隧道远程连接MySQL

     先在SSH栏设置,然后在常规栏设置。

    Django3(一)_第53张图片

    Django3(一)_第54张图片

     pip install sshtunnel

    Django3(一)_第55张图片

     下载sshtunnel,通过SSH方式连接到目标服务器,生成服务器的SSH连接对象,在settings.py文件的DATABASES中设置数据库连接

    # ssh_:实现SSH连接目标服务器,在sshtunnel模块中使用
    
    # 数据库服务器的ip地址或主机名
    ssh_host = "192.168.xx.xx"
    # 数据库服务器的SSH连接端口号,一般都是22,必须是数字
    ssh_port = 22
    # 数据库服务器的用户名
    ssh_user = "root"
    # 数据库服务器的用户密码
    ssh_password = "1234"
    
    # mysql_:在目标服务器基础上连接MySQL数据库,在配置属性DATABASES和sshtunnel模块中均被使用
    
    # 数据库服务器的mysql的主机名或ip地址
    mysql_host = "localhost"
    # 数据库服务器的mysql的端口,默认为3306,必须是数字
    mysql_port = 6603
    # 数据库服务器的mysql的用户名
    mysql_user = "root"
    # 数据库服务器的mysql的密码
    mysql_password = "1234"
    # 数据库服务器的mysql的数据库名
    mysql_db = "mydjango"
    
    # 分别定义服务器的SSH连接信息和数据库的连接信息
    # 定义服务器的SSH连接函数get_ssh(),使用sshtunnel模块的open_tunnel函数实现,并设置相应的函数参数
    from sshtunnel import open_tunnel
    def get_ssh():
        server = open_tunnel(
            (ssh_host, ssh_port),
            ssh_username=ssh_user,
            ssh_password=ssh_password,
            # 绑定服务器的MySQL数据库
            remote_bind_address=(mysql_host, mysql_port))#remote_bind_address是绑定服务器的MySQL数据库
        # ssh通道服务启动
        server.start()
        return str(server.local_bind_port)
    # 在DATABASES的PORT中调用get_ssh(),Django就会连接到服务器的MySQL数据库
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': mysql_db,
            'USER': mysql_user,
            'PASSWORD': mysql_password,
            'HOST': mysql_host,
            'PORT': get_ssh(),
        }
    }

    (四)路由

    路由(一)路由配置

    步骤:

    1. 创建项目
    2. settings.py文件配置(注册index和TEMPLATES)
    3. 新建一个index.html
    4. 路由配置:MyDjango文件夹的urls.py、index的urls.py、index 的views.py
    5. 运行python manage.py runserver,打开网址

    1、创建项目

    django-admin startproject 项目名

    cd 项目名

    python manage.py startapp 应用名

    Django3(一)_第56张图片

    2、settings.py文件中,注册index

    Django3(一)_第57张图片

     3、新建一个文件夹templates,新建一个index.html,并在settings.py文件的TEMPLATES添加DIRS

    'DIRS': [os.path.join(BASE_DIR, 'templates')]

    Django3(一)_第58张图片

    Django3(一)_第59张图片

    4、路由配置

    完整路由:路由地址、视图函数(视图类)、可选变量、路由命名。

    路由编写规则和使用方法:路由定义规则、命名空间与路由命名、路由的使用方式。

    在index文件夹里添加一个空白内容的urls.py文件,是将所有属于index应用的路由都写入该文件。

    Django3(一)_第60张图片

    MyDjango文件夹的urls.py如下:

    from django.contrib import admin
    from django.urls import path, include  # 导入Django的路由函数模块
    
    # urlpatterns代表整个项目的路由集合
    # 两个路由:一个Admin站点管理(创建时已自动生成,一般不用改),一个首页地址index(index文件夹下的urls.py),
    urlpatterns = [
        # 'admin/'代表127.0.0.1:8000/admin的路由地址,admin.site.urls指向内置Admin功能所定义的路由信息
        path('admin/', admin.site.urls),  # 指向内置Admin后台系统的路由文件sites.py
        # '' 代表路由地址为’\‘,即127.0.0.1:8000,一般是网站首页,路由函数include是将该路由信息分发给index的urls.py处理。
        path('', include('index.urls')),  # 指向index的路由文件urls.py
    ]

    index的urls.py导入index的views.py文件,views.index是指视图函数的index处理网站首页用户的用户请求和响应过程。路由信息如下:

    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('', views.index)
    ]

    index 的views.py文件用于编写视图函数或视图类,主要处理当前请求信息并返回响应内容给用户。处理过程如下:

    from django.shortcuts import render
    
    
    # Create your views here.
    def index(request):     # index函数必须要设置一个参数,常用request,表示当前用户的请求对象,该对象包含当前请求的用户名、请求内容和请求方式等。
        value = 'This is test!'
        print(value)
        return render(request, 'index.html')  # 必须要返回处理结果

    5、运行python manage.py runserver

    打开浏览器访问网址

    Django3(一)_第61张图片

     路由(二)路由变量、正则路由定义、命名空间和路由命名

    1、设置路由变量

    路由变量类型:字符类型、整型、slug(注释、后缀或附属等,常作为路由解释性字符)和uuid(匹配一个uuid格式的对象,用‘-’且字母必须为小写)。

    先创建项目MyDjango,新建应用index

    然后注册应用在settings.py

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'index',  # 注册应用
    ]

    MyDjango的urls.py

    from django.contrib import admin
    from django.urls import path, include  # 导入Django的路由函数模块
    
    # urlpatterns代表整个项目的路由集合
    # 两个路由:一个Admin站点管理(创建时已自动生成,一般不用改),一个首页地址index(index文件夹下的urls.py),
    urlpatterns = [
        # 'admin/'代表127.0.0.1:8000/admin的路由地址,admin.site.urls指向内置Admin功能所定义的路由信息
        path('admin/', admin.site.urls),  # 指向内置Admin后台系统的路由文件sites.py
        # '' 代表路由地址为’\‘,即127.0.0.1:8000,一般是网站首页,路由函数include是将该路由信息分发给index的urls.py处理。
        path('', include('index.urls')),  # 指向index的路由文件urls.py
    ]

    在MyDjango项目的index文件夹的urls.py里新定义路由

    from django.urls import path
    from . importfrom django.urls import path
    from . import views
    
    urlpatterns = [
        # 添加带有字符类型、整型和slug的路由。<数据格式类型:变量名>,没有设置数据类型就默认字符类型。
        path('//', views.myvariable)
    ]
     views
    
    urlpatterns = [
        # 添加带有字符类型、整型和slug的路由。<数据格式类型:变量名>,没有设置数据类型就默认字符类型。
        path('//', views.myvariable)
    ]

    index的views.py编写myvariable视图函数的处理过程

    from django.http import HttpResponse
    
    
    # Create your views here.
    def myvariable(request, year, month, day):return HttpResponse(str(year) + '/' + str(month) + '/' + str(day))

    启动项目python manage.py runserver,打开浏览器输入网址127.0.0.1:8000/ 字符型 / 整型 / slug,如果变量类型不符会报错

    Django3(一)_第62张图片

    Django3(一)_第63张图片

    添加路由地址外的变量
    在MyDjango项目的index文件夹的urls.py

    from django.urls import path
    from . import views
    
    urlpatterns = [
        # 添加带有字符类型、整型和slug的路由。<数据格式类型:变量名>,没有设置数据类型就默认字符类型。
        path('//', views.myvariable),
        # 添加路由地址外的变量month,参数只能以字典的形式表示
        path('',views.index,{'month':'2025/10/10'})
    ]
    index的views.py
    from django.http import HttpResponse
    
    
    # Create your views here.
    def myvariable(request, year, month, day):
        return HttpResponse(str(year) + '/' + str(month) + '/' + str(day))
    
    def index(request,month):
        return HttpResponse('这是路由地址之外的变量:'+month)

    Django3(一)_第64张图片

    2、正则表达式路由定义

     在MyDjango项目的index文件夹的urls.py

    re_path定义路由函数正则表达式

    (?P[0-9]{4})以小括号为单位,?P必须大写,为变量,长度4,只取0~9

    .html:将网址设为静态网址,为变量终止符

    from django.urls import re_path
    from . import views
    
    urlpatterns = [
        # 添加带有字符类型、整型和slug的路由。<数据格式类型:变量名>,没有设置数据类型就默认字符类型。
        re_path('(?P[0-9]{4})/(?P[0-9]{2})/(?P[0-9]{2}).html', views.myvariable)
    ]

    Django3(一)_第65张图片

     没有.html则可在最后一个变量之后无限输入字符串

    Django3(一)_第66张图片

    3、命名空间和路由命名

    在刚刚文件夹上新建一个应用user,这样这里就有两个应用了:index和user

    Django3(一)_第67张图片

    Django3(一)_第68张图片

     MyDjango下的urls

    from django.contrib import admin
    from django.urls import path, include  # 导入Django的路由函数模块
    
    # urlpatterns代表整个项目的路由集合
    # 3个路由:一个Admin站点管理(创建时已自动生成,一般不用改),一个index文件夹下的urls.py),一个user文件下的urls.py
    urlpatterns = [
        path('admin/', admin.site.urls),  # 指向内置Admin后台系统的路由文件sites.py
        path('', include(('index.urls','index'), namespace='index')),  # 指向index的路由文件urls.py
        path('user/', include(('user.urls', 'user'), namespace='user'))  # 指向user的路由文件urls.py
    ]

    index下的urls.py

    from django.urls import re_path,path
    from . import views
    
    urlpatterns = [
        # 添加带有字符类型、整型和slug的路由。<数据格式类型:变量名>,没有设置数据类型就默认字符类型。
        re_path('(?P[0-9]{4})/(?P[0-9]{2})/(?P[0-9]{2})', views.mydate),
        path('',views.index,name='index')
    ]

    index下的views.py

    from django.http import HttpResponse
    from django.shortcuts import render
    
    # Create your views here.
    def mydate(request, year):
        return HttpResponse(str(year))
    def index(request):
        return render(request,'index.html')

    user下的urls.py

    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('index', views.index, name='index'),
        path('login', views.userLogin, name='userLogin')
    ]

    user下的views.py

    from django.http import HttpResponse
    
    
    # Create your views here.
    def index(request):
        return HttpResponse("this is test userindex!")
    def userLogin(request):
        return HttpResponse("this is test userLogin!")

    Django3(一)_第69张图片

    不同项目应用的路由命名是可以重复的,namespace是路由函数include的可选参数,路由命名name是路由函数path或re_path的可选参数。include中如果设置name是没有实质作用的,所以没必要设。Django的路由名name是对路由进行命名的,作用是在开发中可以在视图或模板等其他功能模块里使用路由命名name来生成路由地址。

    路由(三)路由的使用方式

    1. 在模板中使用路由

    2. 反向解析reverse与resolve

    3. 路由重定向

    从MyDjango文件夹的urls.py定义的路由信息得知,每个项目应用(App)的路由地址交给项目应用的urls.py自行管理,这是路由的分发规则,使路由按照一定的规则进行分类管理。整个路由设计模式的工作原理说明如下:

    (1)当运行babys项目时,Django从babys文件夹的urls.py找到各个项目应用(App)的urls.py,然后读取每个项目应用(App)的urls.py定义的路由信息,从而生成完整的路由列表。

    (2)用户在浏览器上访问某个路由地址时,Django就会收到该用户的请求信息。

    (3)Django从当前请求信息中获取路由地址,并在路由列表里匹配相应的路由信息,再执行路由信息所指向的视图函数(或视图类),从而完成整个请求响应过程。

                    ——精通Django 3 Web开发3.1设置路由分发规则

    Django3(一)_第70张图片

    django的路由命名name是对路由进行命名,作用是在开发过程中可以在视图或模板等其他功能模块里使用路由命名name来生成路由地址。

    命名空间namespace可以为我们快速定位某个项目应用的urls.py,再结合路由命名name就能快速地从项目应用的urls.py找到某条路由的具体信息,这样就能有效管理整个项目的路由列表。

    1、在模板中使用路由

    不设置命名空间namespace

    # MyDjango的urls.py
    from django.contrib import admin
    from django.urls import path, include  # 导入Django的路由函数模块
    # urlpatterns代表整个项目的路由集合
    urlpatterns = [
        path('admin/', admin.site.urls),  # 指向内置Admin后台系统的路由文件sites.py
        path('', include('index.urls')),  # 指向index的路由文件urls.py
    ]
    # index的urls.py
    from django.urls import path
    from . import views
    
    urlpatterns = [
        # 添加带有字符类型、整型和slug的路由。<数据格式类型:变量名>,没有设置数据类型就默认字符类型。
        path('//', views.mydate, name='mydate'),
        path('',views.index)
    ]
    #index的views.py
    from django.http import HttpResponse
    from django.shortcuts import render
    
    # Create your views here.
    def mydate(request, year,month,day):
        return HttpResponse(str(year)+'/'+str(month)+'/'+str(day))
    def index(request):
        return render(request,'index.html')
    #templates的index.html
    
    
    
        
        Title
    
    
    hello word!
    查看日期
    
    

    模板语法url来生成路由地址
    {% url 'mydate' '2022' '01' '28' %}中的mydate代表命名为mydate的路由,即index的urls.py设有字符类型、整型和slug的路由。

    Django3(一)_第71张图片

    Django3(一)_第72张图片

     设置命名空间namespace

    # Django的urls.py
    from django.contrib import admin
    from django.urls import path, include  # 导入Django的路由函数模块
    # urlpatterns代表整个项目的路由集合
    urlpatterns = [
        path('admin/', admin.site.urls),  # 指向内置Admin后台系统的路由文件sites.py
        path('', include('index.urls')),  # 指向index的路由文件urls.py
        path('', include(('index.urls', 'index'), namespace='index')),
    ]
    #templates的index.html
    
    
    
        
        Title
    
    
    hello word!
    {# 查看日期 #}
    查看日期
    
    

    路由在定义过程中使用命名空间namespace,模板语法url也要添加命名空间。

    如:'命名空间namespace:命名路由name'

    2、反向解析reverse与resolve

    反向解析:用户浏览网站,Django根据网址在路由列表里查找相应的路由,再从路由里找到视图函数或视图类进行处理,将处理结果作为响应内容返回给浏览器并生成网页内容。这是不可逆的,在视图里使用路由则为反向解析。
    反向解析由函数reverse和resolve实现。

    reverse通过路由命名或可调用视图对象来生成路由地址的;

    resolve通过路由地址来获取路由对象信息的。

    在使用这两个函数时,需要注意两者所传入的参数类型和返回值的数据类型。
    MyDjango的urls.py

    from django.contrib import admin
    from django.urls import path, include  # 导入Django的路由函数模块
    # urlpatterns代表整个项目的路由集合
    urlpatterns = [
        path('admin/', admin.site.urls),  # 指向内置Admin后台系统的路由文件sites.py
        path('', include(('index.urls', 'index'), namespace='index')),
    ]

    index的urls.py

    from django.urls import path
    from . import views
    
    # 路由命名为index和mydate
    urlpatterns = [
        # 添加带有字符类型、整型和slug的路由。<数据格式类型:变量名>,没有设置数据类型就默认字符类型。
        path('//', views.mydate, name='mydate'),
        # 定义首页的路由
        path('',views.index,name='index')
    ]

    index的views.py

    from django.http import HttpResponse
    from django.shortcuts import reverse
    from django.urls import resolve
    
    
    # Create your views here.
    def mydate(request, year, month, day):
        args = ['2022', '01', '29']
        result = resolve(reverse('index:mydate', args=args))
        print('kwargs:', result.kwargs)
        print('url_name:', result.url_name)
        print('namespace:', result.namespace)
        print('view_name:', result.view_name)
        print('app_name:', result.app_name)
        return HttpResponse(str(year) + '/' + str(month) + '/' + str(day))
    
    # index主要使用反向解析函数reverse来生成路由mydate的路由地址。
    
    def index(request):
        kwargs = {'year': 2022, 'month': 2, 'day': 10}
        args = ['2022', '01', '29']
        # 使用reverse生成路由地址
        print(reverse('index:mydate', args=args))
        print(reverse('index:mydate', kwargs=kwargs))
        return HttpResponse(reverse('index:mydate', args=args))
    python manage.py runserver

    启动服务器后会调用views中index函数

    Django3(一)_第73张图片

    按住ctrl键点击上面的views.py中的reverse,可查看reverse的源码

    1. viewname:代表路由命名或可调用视图对象,一般情况下是以路由命名name来生成路由地址的。
    2. urlconf:设置反向解析的URLconf模块。默认情况下,使用配置文件settings.py的ROOT_URLCONF属性(MyDjango文件夹的urls.py)
    3. args:以列表方式传递路由地址变量,列表元素顺序和数量应与路由地址变量的顺序和数量一致。
    4. kwargs:以字典方式传递路由地址变量,字典的键必须对应路由地址变量名,字典的键值对数量与变量的数量一致。
    5. current_app:提示当前正在执行的视图所在的项目应用,主要起到提示作用,在功能上并无实质的作用。

    内置的函数方法:

    函数方法 说明
    func 路由的视图函数对象或视图类对象
    args 以列表格式获取路由的变量信息
    kwargs 以字典格式获取路由的变量信息
    url_name 获取路由命名(name)
    app_name 获取项目路由函数include的参数arg的第二个元素值
    app_names 与app_name功能一致,但以列表格式表示
    namespace 获取命名空间(namespace)
    namespaces 与namespace功能一致,但以列表格式表示
    view_name 获取整个路由名称,格式:namespace:name

    3、路由重定向

    重定向:HTTP协议重定向,也称为网页跳转,就是在浏览器访问某个网页的时候,这个网页不提供响应内容,而是自动跳转到其他网址,由其他网址来生成响应内容。

    django的网页重定向有两种方式:第一种方式时路由重定向;第二种方式是自定义视图的重定向。两种重定向方式各有千秋,前者是使用django内置的视图类RedirectView实现的,默认支持HTTP的GET请求;后者是在自定义视图的响应状态设置重定向,能让开发者实现多方面的开发需求。

    index的urls.py

    from django.urls import path
    from . import views
    from django.views.generic import RedirectView
    
    urlpatterns = [
        # 添加带有字符类型、整型和slug的路由
        path('//', views.mydate, name='mydate'),
        # 定义首页的路由
        path('', views.index, name='index'),
        # 设置路由跳转
        path('turnTo', RedirectView.as_view(url='/'), name='turnTo'),
    ]

    在路由里使用视图类RedirectView必须使用as_view方法将视图实例化,参数url用于设置网页跳转的路由地址,“/”表示网站首页(路由命名为index的路由地址),然后在index的view.py定义视图函数mydate和index

    index的view.py

    from django.http import HttpResponse
    from django.shortcuts import redirect
    from django.shortcuts import reverse
    
    def mydate(request, year, month, day):
        return HttpResponse(str(year) + '/' + str(month) + '/' + str(day))
    
    def index(request):
        print(reverse('index:turnTo'))
        return redirect(reverse('index:mydate', args=[2019,12,12]))

    视图函数index是使用重定向函数redirect实现网页重定向的,函数参数只需传入路由地址即可实现重定向。

    Django3(一)_第74张图片

    模板语法url的参数设置与路由定义是相互关联的:

    • 若路由地址存在变量,则模板语法url需要设置响应的参数值,参数值之间使用空格隔开。
    • 若路由地址不存在变量,则模板语法url只需设置路由命名name即可,无须设置额外的参数。
    • 若路由地址的变量与模板语法url的参数数量不相同,则在浏览器访问网页的时候会提示NoReverseMatch at的错误信息

    以下原文【侵权删】:https://edu.51cto.com/center/course/lesson/index?id=463346 

    (五)第三方扩展分页

    pip install django-pure-pagination

    INSTALLED_APPS = (
        'pure_pagination',
    )
    
    
    PAGINATION_SETTINGS = {
        'PAGE_RANGE_DISPLAYED': 1,
        'MARGIN_PAGES_DISPLAYED': 2,
        'SHOW_FIRST_PAGE_WHEN_INVALID': True,
    }

     视图

    def index(request):
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        arts = Article.objects.all()
        p = Paginator(arts, per_page=1, request=request)
        articles = p.page(page)
        return render(request, 'index.html', locals())

    路由

    path('', views.index),

    模板

    
    
    
        
        Title
    
    
    
      {% for art in articles.object_list %}
    • {{ art.title }}
    • {% endfor %}
    {% include '_pagination.html' %}
    _pagination.html
    
    
    {% load i18n %}
    

     

    (六) 富文本编辑器

    python setup.py install

    # 上传图片
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media').replace("\\", "/")
    MEDIA_URL = '/media/'
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app.apps.AppConfig',
        'DjangoUeditor'
    ]
    # 模型类
    class News(models.Model):
        title = models.CharField(verbose_name='产品标题', max_length=20)
        Content = UEditorField(width=600, height=300, toolbars="full",
                               imagePath="news/%(basename)s_%(datetime)s.%(extname)s", filePath="files/")
        vnum = models.IntegerField(verbose_name='浏览量', default=100)
        is_top = models.BooleanField(verbose_name='是否置顶', default=False)
        is_show = models.BooleanField(verbose_name='是否展示', default=True)
        created_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
        updated_time = models.DateTimeField(verbose_name='更新时间', auto_now=True)
    
        class Meta:
            verbose_name = '新闻'
            verbose_name_plural = '新闻'
    
        def __str__(self):
            return self.title
    
    
    # *width,height* :编辑器的宽度和高度,以像素为单位。
    
    # imagePath* :图片上传后保存的路径,如"images/",实现上传到"{{MEDIA_ROOT}}/images"文件夹。 注意:如果imagePath值只设置文件夹,则未尾要有"/" imagePath可以按python字符串格式化:如"images/%(basename)s_%(datetime)s.%(extname)s"。这样如果上传test.png,则文件会 被保存为"{{MEDIA_ROOT}}/images/test_20140625122399.png"。 imagePath中可以使用的变量有:
    
    #time :上传时的时间,datetime.datetime.now().strftime("%H%M%S")
    #date :上传时的日期,datetime.datetime.now().strftime("%Y%m%d")
    #datetime :上传时的时间和日期,datetime.datetime.now().strftime("%Y%m%d%H%M%S")
    #year : 年
    #month : 月
    #day : 日
    #rnd : 三位随机数,random.randrange(100,999)
    #basename : 上传的文件名称,不包括扩展名
    #extname : 上传的文件扩展名
    #filename : 上传的文件名全称
    #路由
    
    from django.contrib import admin
    from django.urls import path, include, re_path
    from django.conf.urls.static import static
    from django.views.static import serve
    
    from django.conf import settings
    
    urlpatterns = [
                      path('admin/', admin.site.urls),
                      path('', include(('app.urls', 'app'), namespace='app')),
                      path('ueditor/', include('DjangoUeditor.urls')),
                  ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    
    
    #模板
    
    
    
        
        Title
        
    
    
    
    
    

    {{ news.title }}

    {{ news.Content|safe }}

    (七)发送邮件

    EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
    EMAIL_HOST = 'smtp.163.com'
    EMAIL_PORT = 25
    # 发送邮件的邮箱
    EMAIL_HOST_USER = '[email protected]'
    # 在邮箱中设置的客户端授权密码
    EMAIL_HOST_PASSWORD = 'abc1234567'
    # 设置是否启用安全链接
    EMAIL_USER_TLS = True
    from django.shortcuts import render
    from pure_pagination import Paginator, PageNotAnInteger
    from django.conf import settings
    from django.core.mail import send_mail, send_mass_mail, EmailMultiAlternatives
    from django.http import HttpResponse
    
    
    
    def send(request):
    
        res = send_mail('元旦放假已通知',
                        '元旦放假一天',
                        '[email protected]',
                        ['[email protected]'],
                        fail_silently=False)
        # 值1:邮件标题   
        # 值2:邮件主人  
        # 值3:发件人  
        # 值4:收件人  
        # 值5:如果失败,是否抛出错误
        if res == 1:
            return HttpResponse('邮件发送成功')
        else:
            return HttpResponse('邮件发送失败')
    from django.shortcuts import render
    from pure_pagination import Paginator, PageNotAnInteger
    from django.conf import settings
    from django.core.mail import send_mail, send_mass_mail, EmailMultiAlternatives
    from django.http import HttpResponse
    
    
    
    def send(request):
        message1 = ('元旦放假已通知',
                    '元旦放假一天',
                    '[email protected]',
                    ['[email protected]', '[email protected]'])
    
        message2 = ('元旦放假已通知?',
                    '元旦放假一天',
                    '[email protected]',
                    ['[email protected]', '[email protected]'])
        res = send_mass_mail((message1, message2))
        if res == 2:
            return HttpResponse('多封邮件发送成功')
        else:
            return HttpResponse('多封邮件发送失败')
    
    #路由
    path('send/',views.send),

    (八)站点配置

    1、注册模型管理
    
    class ArticleAdmin(admin.ModelAdmin):
        pass
    
    参数注册
    admin.site.register(AreaInfo,AreaAdmin)
    
    装饰器注册
    @admin.register(AreaInfo)
    class AreaAdmin(admin.ModelAdmin):
        pass
    
    2、页大小
    list_per_page=100
    
    3、动作栏
    actions_on_top=True
    
    4、显示字段
    list_display=[模型字段1,模型字段2,...]
    **将方法作为列**
    
    列可以是模型字段,还可以是模型方法,要求方法有返回值。
    class Article(models.Model):
        def show_title(self):
            return self.title
    
    list_display = ['id','show_title','title']
    指定方法字段排序的依据
    admin_order_field=模型类字段
    class Article(models.Model):
        def show_title(self):
            return self.title
        show_title.admin_order_field='vnum'
    
    5、列标题
    short_description='列标题'
    
    6、搜索框
    search_fields=[]
    
    7、编辑页
    fields=[]
    
    8、分组显示
    fieldsets=(
        ('标题1',{'fields':('字段1','字段2')}),
        ('标题2',{'fields':('字段3','字段4')}),
    )
    注意:fields与fieldsets只能用一个。
    
    9、关联对象
    class CategoryStackedInline(admin.StackedInline): # TabularInline
        model = Article
        extra = 2
    
    class CategoryAdmin(admin.ModelAdmin):
        ...
        inlines = [AreaStackedInline]
    
    
    

    (九)表单

    # 可以用Django的表单类来简化表单书写,在应用下新建一个forms文件
    from django import forms
    
    class LoginForm(forms.Form):
        name = forms.CharField(label='name', max_length=100)
    
    #视图
    def login(request):
        if request.method == 'POST':
            form = LoginForm(request.POST)
            # 判断数据是否合法
            if form.is_valid():
                # 处理业务
                name = form.cleaned_data['name']
                return HttpResponse('登录成功')
    
        # 如果是GET方法,返回一个空的表单
        else:
            form = LoginForm()
    
        return render(request, 'login.html', {'form': form})
    
    
    
    #模板
    
    {% csrf_token %} {{ form }}
    #自定义表单
    
    from django import forms
    from django.core.exceptions import ValidationError
    import re
    
    
    def mobile_validate(value):
        mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')r
        if not mobile_re.match(value):
            raise ValidationError('手机号码格式错误')
    
    
    class LoginForm(forms.Form):
        user = forms.CharField(required=True, error_messages={'required': '用户名不能为空.'})
        pwd = forms.CharField(required=True,
                              min_length=6,
                              max_length=10,
                              error_messages={'required': '密码不能为空.', 'min_length': "至少6位"}, widget=forms.PasswordInput())
    
        pwd2 = forms.CharField(required=True,
                               min_length=6,
                               max_length=10,
                               error_messages={'required': '密码不能为空.', 'min_length': "至少6位"},
                               widget=forms.PasswordInput(attrs={'class': 'pwd pwd1'}))
    
        num = forms.IntegerField(error_messages={'required': '数字不能空.', 'invalid': '必须输入数字'})
    
        phone = forms.CharField(validators=[mobile_validate, ], )
    
        def clean_user(self):
            user = self.cleaned_data.get('user')
            if user == '123456':
                raise forms.ValidationError('用户名是我的!')
    
            return user
    
        def clean(self):
            cleaned_data = self.cleaned_data
            pwd = cleaned_data['pwd']
    
            pwd2 = cleaned_data['pwd2']
            if pwd != pwd2:
                raise forms.ValidationError('二次输入密码不匹配')
            return cleaned_data  # 注意此处一定要return clean_data,否则会报错
    
    #视图
    def login(request):
        if request.POST:
            objPost = LoginForm(request.POST)
            ret = objPost.is_valid()
            if ret:
                print(objPost.clean())
            else:
                from django.forms.utils import ErrorDict
                print(objPost.non_field_errors())
    
                pass
            return render(request, 'login.html', {'obj1': objPost})
        else:
            objGet = LoginForm()
            return render(request, 'login.html', {'obj1': objGet})
    
    
    
    
    #模板
    
    
    
    
        
        
        
    
    
        
    用户名: {{ obj1.user }} {% if obj1.errors.user %} {{ obj1.errors.user.0 }} {% endif %}
    密码: {{ obj1.pwd }} {% if obj1.errors.pwd %} {{ obj1.errors.pwd.0 }} {% endif %}
    确认密码: {{ obj1.pwd2 }} {% if obj1.errors.pwd2 %} {{ obj1.errors.pwd2.0 }} {% endif %}
    数字: {{ obj1.num }} {% if obj1.errors.num %} {{ obj1.errors.num.0 }} {% endif %}
    电话: {{ obj1.phone }} {% if obj1.errors.phone %} {{ obj1.errors.phone.0 }} {% endif %}
    {% if obj1.non_field_errors %} {% for item in obj1.non_field_errors %} {{ item }} {% endfor %} {% endif %}
    1. 函数full_clean()依次调用每个field的clean()函数,该函数针对field的max_length,unique等约束进行验证,如果验证成功则返回值,否则抛出ValidationError错误。如果有值返回,则放入form的cleaned_data字典中。

    2. 如果每个field的内置clean()函数没有抛出ValidationError错误,则调用以clean_开头,以field名字结尾的自定义field验证函数。验证成功和失败的处理方式同步骤1。

    3. 最后,调用form的clean()函数——注意,这里是form的clean(),而不是field的clean()——如果clean没有错误,那么它将返回cleaned_data字典。

    4. 如果到这一步没有ValidationError抛出,那么cleaned_data字典就填满了有效数据。否则cleaned_data不存在,form的另外一个字典errors填上验证错误。在template中,每个field获取自己错误的方式是:{{ form.username.errors }}。

    5. 最后,如果有错误is_valid()返回False,否则返回True。

      注意一点:自定义验证机制时:clean()和clean_&()的最后必须返回验证完毕或修改后的值.

    手动渲染表单字段
    直接{{ form }}虽然好,啥都不用操心,但是往往并不是你想要的,比如你要使用CSS和JS,比如你要引入Bootstarps框架,这些都需要对表单内的input元素进行额外控制,那怎么办呢?手动渲染字段就可以了。

    可以通过{{ form.name_of_field }}获取每一个字段,然后分别渲染,如下例所示:  

    {{ form.subject.errors }} {{ form.subject.label_tag }} {{ form.subject }}

    (十)验证码

     验证码主要的作用是为了验证作用,有很多类型,比如滑动、点击、倒立点击特别多,这些都是为了加强网站的安全。

    pip install django-simple-captcha

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'captcha'
    ]
    
    
    urlpatterns = [
                      path('admin/', admin.site.urls),
                      path('captcha/', include('captcha.urls')),
                  ] 
    
    #forms.py
    
    from django import forms
    from django.core.exceptions import ValidationError
    from captcha.fields import CaptchaField
    from django.forms import widgets
    import re
    
    
    def mobile_validate(value):
        mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
        if not mobile_re.match(value):
            raise ValidationError('手机号码格式错误')
    
    
    class ContactForm(forms.Form):
        name = forms.CharField(required=True, error_messages={'required': '姓名不能为空.'},
                               widget=widgets.Input(attrs={"class": 'contactFormText', 'placeholder': '请填写姓名'}))
        phone = forms.CharField(validators=[mobile_validate],
                                widget=widgets.TextInput(attrs={"class": 'contactFormText', 'placeholder': '请填写手机号码'}))
        captcha = CaptchaField(required=True, error_messages={'invalid': '验证码错误'})
    

    python manage.py miragte

    def contact(request):
        contactform = ContactForm()
        if request.method == 'GET':
            return render(request, 'contact.html', {'contactform': contactform})
        else:
            obj = ContactForm(request.POST)
            if obj.is_valid():
                data = obj.clean()
                return HttpResponse('OK')
            else:
                return render(request, 'contact.html', {'contactform': contactform, 'obj': obj})
    
    {% csrf_token %}

    在线表单

    姓名 {{ contactform.name }} {% if obj.errors.name %} {{ obj.errors.name }} {% endif %}
    手机 {{ contactform.phone }}
    {% if obj.errors.phone %} {{ obj.errors.phone }} {% endif %}
    {{ contactform.captcha }}
    {% if obj.errors.captcha %} {{ obj.errors.captcha }} {% endif %}

    刷新验证码  

    
    

    (十一)全文检索

    全文检索不同于特定字段的模糊查询,使用全文检索的效率更高,并且能够对于中文进行分词处理

    whoosh:纯Python编写的全文搜索引擎。

    jieba:一款免费的中文分词包,当然也有收费的。

    haystack:全文检索的框架,支持whoosh、solr、Xapian、Elasticsearc四种全文检索引擎。

    pip install django-haystack whoosh jieba

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app.apps.AppConfig',
        'haystack'
    ]
    
    
    
    # 全文检索框架的配置
    HAYSTACK_CONNECTIONS = {
        'default': {
            # 配置搜索引擎
            'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
            # 配置索引文件目录
            'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
        },
    }
    # 指定每页显示的结果数量
    HAYSTACK_SEARCH_RESULTS_PER_PAGE = 10
    
    #当添加、修改、删除数据时,自动生成索引
    HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
    
    
    
    class Goods():
        name = models.CharField(verbose_name='名字', max_length=200)
        content = models.CharField(verbose_name='内容', max_length=200)
    
    
    #在应用下创建名字为search_indexes.py的文件
    # 导入全文检索框架索引类
    from haystack import indexes
    from app.models import Goods
    class GoodsSearchIndex(indexes.SearchIndex, indexes.Indexable):
        # 设置需要检索的主要字段内容 use_template表示字段内容在模板中
        text = indexes.CharField(document=True, use_template=True)
        # 获取检索对应对的模型
        def get_model(self):
            return Goods
        # 设置检索需要使用的查询集
        def index_queryset(self, using=None):
            """Used when the entire index for model is updated."""
            return self.get_model().objects.all()
    
    
    
    

    在模板下创建如下文件夹和文件,格式为:templates/search/indexes/应用名/模型名小写_text.txt

    {{object.name}} #object就代表get_model()方法返回的对象
    {{object.content}}
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('search/', include('haystack.urls')),
        path('', include(('app.urls', 'app'), namespace='app')),
    ]

    生成索引文件

    python manage.py rebuild_index

    创建搜索表单

    
    
    
        
        Title
    
    
    

    创建结果显示页面

    在search文件夹下面创建search.html文件

    
    
    
        
        Title
    
    
    {% if query %}
        
    {% endif %}
    
    
    
    

    支持中文

    在路径site-packages/haystack/backends/下创建ChineseAnalyzer.py

    import jieba
    from whoosh.analysis import Tokenizer, Token
    
    class ChineseTokenizer(Tokenizer):
        def __call__(self, value, positions=False, chars=False,
                     keeporiginal=False, removestops=True,
                     start_pos=0, start_char=0, mode='', **kwargs):
            t = Token(positions, chars, removestops=removestops, mode=mode,
                      **kwargs)
            seglist = jieba.cut(value, cut_all=True)
            for w in seglist:
                t.original = t.text = w
                t.boost = 1.0
                if positions:
                    t.pos = start_pos + value.find(w)
                if chars:
                    t.startchar = start_char + value.find(w)
                    t.endchar = start_char + value.find(w) + len(w)
                yield t
    
    def ChineseAnalyzer():
        return ChineseTokenizer()

    复制 whoosh_backend.py 改名为 whoosh_cn_backend.py

    更改词语分析类
    from .ChineseAnalyzer import ChineseAnalyzer
    查找
    analyzer=StemmingAnalyzer()
    改为
    analyzer=ChineseAnalyzer()
    
    
    更改设置
    # 全文检索框架的配置
    HAYSTACK_CONNECTIONS = {
        'default': {
            # 配置搜索引擎
            # 'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
            # 中文分词 使用jieba的whoosh引擎
            'ENGINE': 'haystack.backends.whoosh_cn_backend.WhooshEngine',
            # 配置索引文件目录
            'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
        },
    }
    

    重新生成索引

    python manage.py rebuild_index

    关键词高亮与分页
    
    
    
        
        Title
    
    
    
    
    
    
    {% if query %}
        {% load highlight %}
    
        
    
    
        {% if page.has_previous or page.has_next %}
            
    {% if page.has_previous %} {% endif %}« 上一页 {% if page.has_previous %}{% endif %} | {% if page.has_next %}{% endif %}下一页 » {% if page.has_next %}{% endif %}
    {% endif %} {% else %} {% endif %}

     (十二)缓存

    对于一些网站首页,例如企业官网,页面在一段时间,都不会有变化。就可以把它缓存起来,以减少服务器压力。

    pip install django-redis-cache

    利用Redis数据库缓存
    CACHES = {
        "default": {
            "BACKEND": "redis_cache.cache.RedisCache",
            "LOCATION": "127.0.0.1:6379",
            'TIMEOUT': 60,
        },
    }
    
    
    利用文件缓存
    # 缓存
    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
            'LOCATION': '/var/tmp/django_cache' 
        }
    }
    
    
    利用内存缓存
    CACHES={    
        'default': {        
            'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',        
            'TIMEOUT': 60,    
        }
    }

    视图缓存

    from django.shortcuts import render
    from django.views.decorators.cache import cache_page
    from django.http import HttpResponse
    
    # Create your views here.
    @cache_page(60 * 15)
    def index(request):
        return HttpResponse('您好')
        # return HttpResponse('大家好')
    

    模板缓存

    
    
    
        
        Title
    
    
    
    {% load cache %}
    
    {% cache 900 content %}
        大家好
        我们好
    {% endcache %}
    
    
    
    

     (十三)Ajax

    前端只关注页面,后端只关注数据,前端只要通过Ajax发起请求把数据请求回来填充到页面就可以了。

    模型
    from django.db import models
    
    
    # Create your models here.
    
    class Area(models.Model):
        name = models.CharField(verbose_name='地区名字', max_length=20)
        parent = models.ForeignKey(to='self', blank=True, null=True, on_delete=models.Model)

    导入area.sql文件

    视图

    from django.shortcuts import render
    from .models import *
    
    from django.http import HttpResponse, JsonResponse
    
    
    # Create your views here.
    
    
    def index(request):
        return render(request, 'app01/index.html')
    
    
    def get_parent(request):
        areas = Area.objects.filter(parent__isnull=True).all()
        l = []
        for item in areas:
            l.append({"id": item.id, 'name': item.name})
        return JsonResponse({'data': l})
    
    
    def get_son(request,id):
        areas = Area.objects.filter(parent_id=id).all()
        l = []
        for item in areas:
            l.append({"id": item.id, 'name': item.name})
        return JsonResponse({'data': l})
    

    模板

    
    
    
        
        Title
    
    
    
    
    
    
        省市区列表
        
        
    
    
    
    
    
    
    
    
    
    

     (十四)中间件

    介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上影响django的输入与输出。

    五个方法
    1、process_request(self,request)
    
    2、process_view(self, request, callback, callback_args, callback_kwargs)
    
    3、process_template_response(self,request,response)
    
    4、process_exception(self, request, exception)
    
    5、process_response(self, request, response)
    from django.utils.deprecation import MiddlewareMixin
    class MyMiddleware(MiddlewareMixin):
        """自定义中间件类"""
    
        def __init__(self,get_response=None):
            """服务器重启之后,接收第一个请求时调用"""
            # 重写父类方法
            super().__init__()
    
        def process_request(self, request):
            """产生request对象之后,url匹配之前调用"""
            print("自定义 process_request 1")
            return None
    
        def process_response(self, request, response):
            """视图函数调用之后,内容返回浏览器之前调用"""
            print("自定义 process_response 1--->必须要有返回值")
            return response
    
        def process_view(self, request, callback, callback_args, callback_kwargs):
            """url匹配之后,视图函数调用之前调用"""
            print("自定义 process_view 1")
            return None
    
        def process_exception(self, request, exception):
            print("自定义 process_exception 1")

    当视图没有错误的情况  

    Django3(一)_第75张图片

    当视图出现错误的情况

     Django3(一)_第76张图片

     

    中间件应用

    控制访问频率

    请求验证

    CSRF

    频率中间件
    import time
    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    # 访问IP池
    visit_ip_pool = {}
    class RequestBlockingMiddleware(MiddlewareMixin):
        def process_request(self,request):
            # 获取访问者IP
            ip=request.META.get("REMOTE_ADDR")
            # 获取访问当前时间
            visit_time=time.time()
            # 判断如果访问IP不在池中,就将访问的ip时间插入到对应ip的key值列表,如{"127.0.0.1":[时间1]}
            if ip not in visit_ip_pool:
                visit_ip_pool[ip]=[visit_time]
                return None
            # 然后在从池中取出时间列表
            history_time = visit_ip_pool.get(ip)
            # 循环判断当前ip的时间列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
            while history_time and visit_time-history_time[-1]>60:
                history_time.pop()
            # 如果访问次数小于10次就将访问的ip时间插入到对应ip的key值列表的第一位置,如{"127.0.0.1":[时间2,时间1]}
            print(history_time)
            if len(history_time)<10:
                history_time.insert(0, visit_time)
                return None
            else:
                # 如果大于10次就禁止访问
                return HttpResponse("访问过于频繁,还需等待%s秒才能继续访问"%int(60-(visit_time-history_time[-1])))
    在settings中注册中间件
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        # ip访问限制
        'app.middleware.RequestBlockingMiddleware',
    ]

     (十五)本地部署

    • wsgi web应用程序之间的接口。它的作用就像是桥梁,连接在web服务器和web应用框架之间。

    • uwsgi 是一种传输协议,用于定义传输信息的类型。

    • uWSGI 是实现了uwsgi协议WSGI的web服务器。

    Django3(一)_第77张图片 

     Django运行流程

    Django3(一)_第78张图片

     uWSGI

    # 配置Settings文件
    
    DEBUG = False # 关闭debug调试
    
    ALLOWED_HOSTS = ['*'] # 允许任何域方法
    
    
    
    # 收集静态文件
    # 静态文件
    
    STATIC_URL = '/static/'
    # 注释掉
    #STATICFILES_DIRS = [
    #    os.path.join(BASE_DIR, 'static')
    #]
    STATIC_ROOT = os.path.join(BASE_DIR,'static/')

    python manage.py collectstatic

    安装uwsgi

    pip install uwsgi

    新建uwsgi.ini文件

    #添加配置选择
    [uwsgi]
    #配置和nginx连接的socket连接
    socket = 127.0.0.1:8000
    #配置项目路径,项目的所在目录
    chdir = /Desktop/1907/test/test_common
    #配置wsgi接口模块文件路径
    wsgi-file = test_common/wsgi.py
    #配置启动的进程数
    processes = 4
    #配置每个进程的线程数
    threads = 2
    #配置启动管理主进程
    master = True
    #配置存放主进程的进程号文件
    pidfile = uwsgi.pid
    #配置dump日志记录
    daemonize = uwsgi.log`
    # 虚拟环境
    virtualenv = /home/ubuntu/.virtualenvs/django_env

    安装nginx

    ubuntu

    sudo apt install nginx

    配置nginx

    # configuration of the server
    server {
        # 你的网站监听的端口,此处先用8000端口测试,正式部署可以改为80或其他
        listen      80;
        # 你的网站的域名
        server_name *.com; # substitute your machine's IP address or FQDN
        charset     utf-8;
    
        # max upload size
        client_max_body_size 75M;   # adjust to taste
    
        # Django media
        location /media  {
            alias /home/mysite/media;  # 你的media的文件目录
        }
    
        location /static {
            alias /home/mysite/collected_static; # 你的项目收集的静态文件目录(后边会将收集静态文件)
        }
    
        # Finally, send all non-media requests to the Django server.
        location / {
            uwsgi_pass  127.0.0.1:8000;
            include     uwsgi_params; # uwsgi_params 文件所在目录
        }
    }
    

    启动

    uwsgi uwsgi --ini uwsgi.ini

    重启

    uwsgi uwsgi --reload uwsgi.pid

    关闭

    uwsgi uwsgi --stopu uwsgi.pid

    远程部署(Ubuntu举例)

    ssh root@ip #ssh [email protected]

    更新服务器

    sudo apt update sudo apt upgrade

    安装pip3

    sudo apt install python3-pip

    安装虚拟环境

    sudo pip3 install virtualenv

    sudo pip3 install virtualenvwrapper ​

    配置文件.bashrc

    export WORKON_HOME=$HOME/.virtualenvs

    export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3

    source /usr/local/bin/virtualenvwrapper.sh

    source .bashrc

    安装Mysql

    sudo apt install mysql-server

    安装Nginx

    sudo apt install nginx

    安装依赖

    pip  install -r requirements.txt ​

    pip install  uwsgi

    上传代码

    Mac或者Ubuntu可以用scp

    Windows可以用winscp ​

    或者可以用git

    错误解决

    如果遇到静态资源报403错误,把nginx配置文件 user www-data;改成 user root;

    (十六)CSRF

    跨站请求伪造(CSRF)与跨站请求脚本正好相反。跨站请求脚本的问题在于,客户端信任服务器端发送的数据。跨站请求伪造的问题在于,服务器信任来自客户端的数据。

    Django3(一)_第79张图片

     

    视图
    from django.shortcuts import render
    from django.http import HttpResponse
    
    
    def transfer(request):
        if request.method == 'POST':
            from_ = request.POST.get('from')
            to_ = request.POST.get('to')
            money = request.POST.get('money')
            print("{}给{}转账{}".format(from_, to_, money))
            return HttpResponse("转账成功")
        return render(request, 'bank.html')
    
    
    路由
    
    from django.contrib import admin
    from django.urls import path
    from news import views
    
    urlpatterns = [
        path('transfer/', views.transfer),
    ]
    
    
    
    
    
        
        transfer
    
    
    

    银行网站

    转出方账号: 转入方账号:

    金额:

    取消CSRF保护

    注销中间件

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        # 'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]
    采用装饰器
    from django.shortcuts import render
    from django.http import HttpResponse
    from django.views.decorators.csrf import csrf_exempt
    
    @csrf_exempt
    def transfer(request):
        if request.method == 'POST':
            from_ = request.POST.get('from')
            to_ = request.POST.get('to')
            money = request.POST.get('money')
            print("{}给{}转账{}".format(from_, to_, money))
            return HttpResponse("转账成功")
        return render(request, 'bank.html')
    

    关闭之后,就可以伪装请求了。

    编写钓鱼网站模板

    
    
    
        
        transfer
    
    
    

    钓鱼网站

    转出方账号: 转入方账号:

    金额:

    直接在本地运行,注意不用通过Django运行网站。

    Django3(一)_第80张图片

    开启CSRF

    打开中间件

    利用装饰器

    from django.shortcuts import render
    from django.http import HttpResponse
    from django.views.decorators.csrf import csrf_exempt,csrf_project
    
    @csrf_project
    def transfer(request):
        if request.method == 'POST':
            from_ = request.POST.get('from')
            to_ = request.POST.get('to')
            money = request.POST.get('money')
            print("{}给{}转账{}".format(from_, to_, money))
            return HttpResponse("转账成功")
        return render(request, 'bank.html')

    在form表单加上csrf_token标签

    
    
    
        
        transfer
    
    
    

    银行网站

    {% csrf_token %}

    转出方账号: 转入方账号:

    金额:

    类视图取消csrf

    from django.views.decorators.csrf import csrf_exempt,csrf_protect
    from django.utils.decorators import method_decorator
    @method_decorator(csrf_exempt,name='dispatch')
    class MyView(View):
        def get(self,request):
            return HttpResponse("get")
        def post(self,request):
            return HttpResponse("post")

    Django3(一)_第81张图片

    SQL注入

    通过非法的SQL命令,达到欺骗服务器的目录。查到的数据就会出现一些意想不到的效果。一些网站被爆一般都是通过非法的SQL命令获取

    编写视图

    from django.db import connection
    def get_data(request):
        id = request.GET.get('id')
        cursor = connection.cursor()
        sql = "select id,name from app04_user where id=%s" % id
        print(sql)
        cursor.execute(sql)
        rows = cursor.fetchall()
        ctx = {
            'rows': rows
        }
        return render(request, 'app04/show.html', ctx)

    编写模板

    
    
    
        
        Title
    
    
    
      {% for row in rows %}
    • {{ row.1 }}
    • {% endfor %}

    如果用户传的user_id是等于1 or 1=1,以上拼接后的sql语句为:  

    select id,username from front_user where id=1 or 1=1

    select id,username from front_user where 'username=xiao' or '1=1'

    • 永远要进行前端参数校验

    • 永远不要拼接SQL

    • 永远加密一下重要信息

    • 永远不要给出具体的错误类型

    • 永远不要用root去管理数据库

    如何防御sql注入 

    • 使用ORM去查询数据

    • 使用参数形式查询数据

    三、实战项目:待办事项

    创建 Django 项目,后台系统管理数据,从数据库接收到的数据渲染到网页,对数据库执行创建、更新、读取和删除等操作。实现查看、添加、更新、删除待办事项。

    以下内容涉及到:django项目的创建,数据库sqlite3,视图views,模板templates

    1、创建项目

    django-admin startproject mytodo

    cd mytodo

    django-admin startapp tasks        # 第一个应用

    django-admin startapp tasks2        # 第二个应用

    将这两个应用写到settings.py列表中,再设置一下中文和时间

    (下面的就只举例第一个应用tasks)

    # settings.py
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'tasks',
        'tasks2',
    ]
    
    LANGUAGE_CODE = 'zh-hans'
    
    TIME_ZONE = 'Asia/Shanghai'
    
    

    2、编写tasks/model.py

    from django.db import models
    from django.utils import timezone
    
    
    # Create your models here.
    
    class TaskItem(models.Model):
        DEFAULT = '默认事项'
        PERSONAL = '个人事务'
        SHOPPING = '购物清单'
        WISHLIST = '愿望清单'
        WORK = ' 工作清单'
        CATEGORIES = (
            (DEFAULT, DEFAULT),
            (PERSONAL, PERSONAL),
            (SHOPPING, SHOPPING),
            (WISHLIST, WISHLIST),
            (WORK, WORK)
        )
        title = models.CharField('标题', max_length=100, blank=True, null=True)
        body = models.TextField('内容', null=True, blank=True)
        due_date = models.DateField('日期', default=timezone.now)
        task_finished = models.BooleanField('完成', default=True)
        category = models.CharField('分类', max_length=20, choices=CATEGORIES, default=DEFAULT)
    
        class Meta:
            verbose_name = u'待办'    # 在admin管理界面中显示的中文,单数形式的显示
            verbose_name_plural = u'待办'
    
        def __str__(self):
            return f'{self.title}'    # 在admin管理界面中显示的中文
    # admin.py
    
    from django.contrib import admin
    from .models import TaskItem
    
    # Register your models here.
    admin.site.register(TaskItem)
    
    admin.site.site_title = '待办事项标签页'
    admin.site.site_header = '待办事项系统'
    admin.site.index_title = '内容管理'
    

    迁移数据库

    python manage.py makemigrations

    python manage.py migrate

    创建管理员python manage.py createsuperuser

    运行python manage.py runserver 8002

    打开网址http://127.0.0.1:8002/admin

     登录后可以手动添加一些数据试试

    Django3(一)_第82张图片

    Django3(一)_第83张图片

     Django3(一)_第84张图片

    3、视图和模板

    Django 中的视图在模板显示数据时将数据发送到模板。

    编写tasks/views.py文件,创建几个模板文件html和表单tasks/forms.py 

     Django3(一)_第85张图片 

    # views.py
    
    from django.views.generic import ListView, CreateView, UpdateView, DeleteView
    from .models import TaskItem
    from .forms import TaskItemCreateForm, TaskItemUpdateForm
    
    
    # Create your views here.
    
    class TodoItemListView(ListView):
        model = TaskItem
        template_name = 'tasks/list.html'
    
    
    class TodoItemCreateView(CreateView):
        model = TaskItem
        template_name = 'tasks/create_form.html'
        form_class = TaskItemCreateForm
        success_url = '/todo/list'
    
    
    class TodoItemUpdateView(UpdateView):
        model = TaskItem
        template_name = 'tasks/update_form.html'
        form_class = TaskItemUpdateForm
        success_url = '/todo/list'
    
    
    class TodoItemDeleteView(DeleteView):
        model = TaskItem
        template_name = 'tasks/delete_form.html'
        success_url = "/todo/list"
    

    list.html 

    {% block content%}
    {% for task in object_list %}
    
  • {{task.body}}
  • {{task.due_date}}
  • {{task.category}}
  • {% endfor %} {% endblock %}

     create_form.html

    {% block content %}
    

    创建待办事项

    {% csrf_token %} {{ form.as_p }}
    {% endblock %}

    update_form.html

    {% block content %}
    

    编辑待办事项

    {% csrf_token %} {{ form.as_p }}
    {% endblock %}

    delete_form.html

    {% block content %}
    

    删除待办事项

    {% csrf_token %}

    删除"{{ object }}"?

    {% endblock %}
    # forms.py
    
    from django import forms
    from .models import TaskItem
    
    class TaskItemCreateForm(forms.ModelForm):
        class Meta:
            model = TaskItem
            fields =('title', 'body','due_date','category')
    
    class TaskItemUpdateForm(forms.ModelForm):
        class Meta:
            model = TaskItem
            fields =('body','due_date','task_finished','category')

    路由

    # mytodo\urls.py
    
    from django.contrib import admin
    from django.urls import path
    from tasks.views import TodoItemListView, TodoItemCreateView, TodoItemUpdateView, TodoItemDeleteView
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('todo/list', TodoItemListView.as_view(), name='todo_list'),
        path('todo/create', TodoItemCreateView.as_view(), name='create_list'),
        path('todo/update/', TodoItemUpdateView.as_view(), name='update_list'),
        path('todo/delete/', TodoItemDeleteView.as_view(), name='delete_list'),
    
    ]

    四个路由地址

    查看、创建、更新、删除

    http://127.0.0.1:8002/todo/list

    http://127.0.0.1:8002/todo/create

    http://127.0.0.1:8002/todo/update/1

     http://127.0.0.1:8002/todo/delete/1

    Django3(一)_第86张图片

    Django3(一)_第87张图片

     Django3(一)_第88张图片

    Django3(一)_第89张图片

    你可能感兴趣的:(django,python,django)