第一部分初步认识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

​​

​(三)创建Django项目

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

cd MyDjango        # 进入该目录

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

​​

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

tree /f

​​

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

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

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

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

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

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

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

​​

python manage.py migrate

运行开发web服务器命令

python manage.py runserver 8002

​​

​​

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

​​

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

(四)模型类

模型设计类

在models.py中设计模型类

必须继承与models.Model类

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 迁移文件是根据模型类生成的。

​​

​​

2)执行迁移生成表

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

生成表名的默认格式:

应用名_模型类名小写

​​

​​

​​

第二个表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)

​​

​​

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

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

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

python manage.py migrate

​​

​​

数据库操作

​​

表1

​​

增删查改语句:

插入语句

​​

查询语句

​​

更新语句

​​

删除语句

​​

(五)后台管理

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

1)本地化

语言和时区的本地化

修改settings.py

LANGUAGE_CODE = 'zh-hans'TIME_ZONE = 'Asia/Shanghai'

2)创建管理员

python manage.py createsuperuser

​​

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

​​

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

​​

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)

​​

​​

​​

显示图书标题

​​

查看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

​​

同理,增加第二个表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

​​

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)

​​

​​

(六)视图

在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

​​

​​

  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、新建文件夹

​​

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>模板文件</title>
</head>
<body>
<h1>这是一个模板文件,{{ content }}</h1>
</body>
</html>

​​

views.py

from django.shortcuts import render
from django.http import HttpResponse
from django.template import loader,RequestContextdef 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文件夹。括号内为地址和地址对应的视图
]

​​

连接数据库

新建html

​​

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>显示图书</title>
</head>
<body>
{% for book in books %}<li>{{ book.btitle }}</li>
{% endfor %}
</body>
</html>
#views.py
from django.shortcuts import renderfrom index.models import BookInfo#导入图书模型类
from django.http import HttpResponse
from django.template import loader,RequestContextdef 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),#显示图书信息
]

​​

二、Django配置信息

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

(一)资源文件配置

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

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

资源文件配置

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

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

静态资源文件

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/#databasesDATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3','NAME': BASE_DIR / 'db.sqlite3',}
}# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validatorsAUTH_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/ShanghaiUSE_I18N = TrueUSE_L10N = TrueUSE_TZ = True# # Static files (CSS, JavaScript, Images)。
# # 静态资源的路由地址:通过浏览器访问Django的静态资源。查找功能由App列表——INSTALLED_APPS——staticfiles
STATIC_URL = '/static/'
# # 设置根目录的静态资源文件夹static
STATICFILES_DIRS = [BASE_DIR / 'static',# 设置App(index)的静态资源文件夹MystaticBASE_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-fieldDEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

运行一下python manage.py runserver 8000

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

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

媒体资源文件

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

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

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

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<path>.*)',serve,{'document_root':settings.MEDIA_ROOT},name='media'),
]

(二)templates模板配置

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

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

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

一般根目录的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

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

在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',}
}

新建一个数据库

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

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

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

如果发现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

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Hello</title>
</head>
<body><span>Hello World!!</span>
</body>
</html>

python manage.py migrate

python manage.py runserver 8001

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

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

pip install sshtunnel

下载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 应用名

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

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

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

4、路由配置

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

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

在index文件夹里添加一个空白内容的urls.py文件,是将所有属于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
]

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

from django.urls import path
from . import viewsurlpatterns = [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

打开浏览器访问网址

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

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 viewsurlpatterns = [# 添加带有字符类型、整型和slug的路由。<数据格式类型:变量名>,没有设置数据类型就默认字符类型。path('<year>/<int:month>/<slug:day>', views.myvariable)
]viewsurlpatterns = [# 添加带有字符类型、整型和slug的路由。<数据格式类型:变量名>,没有设置数据类型就默认字符类型。path('<year>/<int:month>/<slug:day>', 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,如果变量类型不符会报错

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

from django.urls import path
from . import viewsurlpatterns = [# 添加带有字符类型、整型和slug的路由。<数据格式类型:变量名>,没有设置数据类型就默认字符类型。path('<year>/<int:month>/<slug:day>', 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)

2、正则表达式路由定义

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

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

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

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

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

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

3、命名空间和路由命名

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

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.pypath('', include(('index.urls','index'), namespace='index')),  # 指向index的路由文件urls.pypath('user/', include(('user.urls', 'user'), namespace='user'))  # 指向user的路由文件urls.py
]

index下的urls.py

from django.urls import re_path,path
from . import viewsurlpatterns = [# 添加带有字符类型、整型和slug的路由。<数据格式类型:变量名>,没有设置数据类型就默认字符类型。re_path('(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[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 viewsurlpatterns = [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!")

不同项目应用的路由命名是可以重复的,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设置路由分发规则

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.pypath('', include('index.urls')),  # 指向index的路由文件urls.py
]
# index的urls.py
from django.urls import path
from . import viewsurlpatterns = [# 添加带有字符类型、整型和slug的路由。<数据格式类型:变量名>,没有设置数据类型就默认字符类型。path('<year>/<int:month>/<slug:day>', 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
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
hello word!
<a href="{% url 'mydate' '2022' '01' '28' %}">查看日期</a>
</body>
</html>

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

设置命名空间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.pypath('', include('index.urls')),  # 指向index的路由文件urls.pypath('', include(('index.urls', 'index'), namespace='index')),
]
#templates的index.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
hello word!
{# <a href="{% url 'mydate' '2022' '01' '28' %}">查看日期</a> #}
<a href="{% url 'index:mydate' '2022' '01' '28' %}">查看日期</a>
</body>
</html>

路由在定义过程中使用命名空间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.pypath('', include(('index.urls', 'index'), namespace='index')),
]

index的urls.py

from django.urls import path
from . import views# 路由命名为index和mydate
urlpatterns = [# 添加带有字符类型、整型和slug的路由。<数据格式类型:变量名>,没有设置数据类型就默认字符类型。path('<year>/<int:month>/<slug:day>', 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函数

按住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 RedirectViewurlpatterns = [# 添加带有字符类型、整型和slug的路由path('<year>/<int:month>/<slug:day>', 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 reversedef 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实现网页重定向的,函数参数只需传入路由地址即可实现重定向。

模板语法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 = 1arts = Article.objects.all()p = Paginator(arts, per_page=1, request=request)articles = p.page(page)return render(request, 'index.html', locals())

路由

path('', views.index),

模板

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<ul>{% for art in articles.object_list %}<li>{{ art.title }}</li>{% endfor %}
</ul>{% include '_pagination.html' %}
</body>
</html>
_pagination.html{% load i18n %}
<div class="pagination">{% if articles.has_previous %}<a href="?{{ articles.previous_page_number.querystring }}"class="prev">上一页</a>{% else %}<span class="disabled prev">上一页 </span>{% endif %}{% for page in articles.pages %}{% if page %}{% ifequal page articles.number %}<span class="current page">{{ page }}</span>{% else %}<a href="?{{ page.querystring }}" class="page">{{ page }}</a>{% endifequal %}{% else %}...{% endif %}{% endfor %}{% if page_obj.has_next %}<a href="?{{ articles.next_page_number.querystring }}" class="next">下一页</a>{% else %}<span class="disabled next">下一页</span>{% endif %}
</div>

(六) 富文本编辑器

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 servefrom django.conf import settingsurlpatterns = [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)
#模板
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>.center {text-align: center;}</style>
</head><body><div class="center"><h1>{{ news.title }}</h1>{{ news.Content|safe }}</div></body>
</html>

(七)发送邮件

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
# 发送邮件的邮箱
EMAIL_HOST_USER = '18622881126@163.com'
# 在邮箱中设置的客户端授权密码
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 HttpResponsedef send(request):res = send_mail('元旦放假已通知','元旦放假一天','18622881126@163.com',['496155678@qq.com'],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 HttpResponsedef send(request):message1 = ('元旦放假已通知','元旦放假一天','18622881126@163.com',['496155678@qq.com', '18622881126@qq.com'])message2 = ('元旦放假已通知?','元旦放假一天','18622881126@163.com',['496155678@qq.com', '496155678@qq.com'])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):pass2、页大小
list_per_page=1003、动作栏
actions_on_top=True4、显示字段
list_display=[模型字段1,模型字段2,...]
**将方法作为列**列可以是模型字段,还可以是模型方法,要求方法有返回值。
class Article(models.Model):def show_title(self):return self.titlelist_display = ['id','show_title','title']
指定方法字段排序的依据
admin_order_field=模型类字段
class Article(models.Model):def show_title(self):return self.titleshow_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): # TabularInlinemodel = Articleextra = 2class CategoryAdmin(admin.ModelAdmin):...inlines = [AreaStackedInline]

(九)表单

# 可以用Django的表单类来简化表单书写,在应用下新建一个forms文件
from django import formsclass 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})
#模板
<form action="/your-name/" method="post">{% csrf_token %}{{ form }}<input type="submit" value="Submit" />
</form>
#自定义表单from django import forms
from django.core.exceptions import ValidationError
import redef mobile_validate(value):mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')rif 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 userdef clean(self):cleaned_data = self.cleaned_datapwd = 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 ErrorDictprint(objPost.non_field_errors())passreturn render(request, 'login.html', {'obj1': objPost})else:objGet = LoginForm()return render(request, 'login.html', {'obj1': objGet})

#模板<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title></title><style>.error_msg{color: red;}</style>
</head>
<body><form action="/login/" method="POST"><div>用户名:{{ obj1.user }}{%  if obj1.errors.user %}<span class="error_msg">{{ obj1.errors.user.0 }}</span>{% endif %}</div><div>密码:{{ obj1.pwd }}{%  if obj1.errors.pwd %}<span class="error_msg">{{ obj1.errors.pwd.0 }}</span>{% endif %}</div><div>确认密码:{{ obj1.pwd2 }}{%  if obj1.errors.pwd2 %}<span class="error_msg">{{ obj1.errors.pwd2.0 }}</span>{% endif %}</div><div>数字:{{ obj1.num }}{%  if obj1.errors.num %}<span class="error_msg">{{ obj1.errors.num.0 }}</span>{% endif %}</div><div>电话:{{ obj1.phone }}{%  if obj1.errors.phone %}<span class="error_msg">{{ obj1.errors.phone.0 }}</span>{% endif %}</div><div>{%  if obj1.non_field_errors %}{% for item in obj1.non_field_errors %}<span class="error_msg">{{ item }}</span>{% endfor %}{% endif %}</div><input type="submit" value="提交"/></form></body>
</html>
  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_<field>&()的最后必须返回验证完毕或修改后的值.

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

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

<div class="fieldWrapper">{{ form.subject.errors }}{{ form.subject.label_tag }}{{ form.subject }}
</div>

(十)验证码

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

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.pyfrom django import forms
from django.core.exceptions import ValidationError
from captcha.fields import CaptchaField
from django.forms import widgets
import redef 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})
<form id="contactForm" action="/contact/" method="post">{% csrf_token %}<h3>在线表单</h3><div class="contactFormItem"><div class="contactFormField"><span class="contactFormLabel">姓名</span>{{ contactform.name }}{% if obj.errors.name %}<span class="error_msg">{{ obj.errors.name }}</span>{% endif %}</div></div><div class="contactFormItem"><div class="contactFormField"><span class="contactFormLabel">手机</span>{{ contactform.phone }}</div>{% if obj.errors.phone %}<span class="error_msg">{{ obj.errors.phone }}</span>{% endif %}</div><div class="contactFormItem">{{ contactform.captcha }}</div>{% if obj.errors.captcha %}<span class="error_msg">{{ obj.errors.captcha }}</span>{% endif %}<div class="contactFormSubmit"><input type="submit" value="提交" class="contactFormSubmitBtn"></div></form>

刷新验证码

<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script>$('.captcha').click(function () {$.getJSON("/captcha/refresh/", function (result) {$('.captcha').attr('src', result['image_url']);$('#id_captcha_0').val(result['key'])});});
</script>

(十一)全文检索

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

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

创建搜索表单

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form action="/search/" method="get"><input type="text" name="q" value="" placeholder="请输入搜索内容"/><input type="submit" value="提交"/>
</form></body>
</html>

创建结果显示页面

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

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
{% if query %}<ul class="list-pro" style="margin-top: 20px">{% for result in page %}<li><a href="{% url 'app:detail' result.object.pk %}"></a><div class="shop-list-mid" style="width: 65%;"><div class="tit"><a href="{% url 'app:detail' result.object.pk %}">{{ result.object.name }}</a></div></div></li>{% empty %}<li>没有找到您搜索的内容</li>{% endfor %}</ul>
{% endif %}</body>
</html>

支持中文

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

import jieba
from whoosh.analysis import Tokenizer, Tokenclass 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 = wt.boost = 1.0if 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 tdef 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

关键词高亮与分页
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title></head>
<style>span.highlighted {color: red;}
</style>
<body>{% if query %}{% load highlight %}<ul class="list-pro" style="margin-top: 20px">{% for result in page %}<li><a href="{% url 'app:detail' result.object.pk %}"></a><div class="shop-list-mid" style="width: 65%;"><div class="tit"><a href="{% url 'app:detail' result.object.pk %}">{#                            {{ result.object.name }}#}{% highlight result.object.name with query %}{% highlight result.object.content with query %}</a></div></div></li>{% empty %}<li>没有找到您搜索的内容</li>{% endfor %}</ul>{% if page.has_previous or page.has_next %}<div>{% if page.has_previous %}<a href="?q={{ query }}&amp;page={{ page.previous_page_number }}">{% endif %}&laquo; 上一页{% if page.has_previous %}</a>{% endif %}|{% if page.has_next %}<a href="?q={{ query }}&amp;page={{ page.next_page_number }}">{% endif %}下一页 &raquo;{% if page.has_next %}</a>{% endif %}</div>{% endif %}
{% else %}
{% endif %}</body>
</html>

(十二)缓存

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

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('大家好')

模板缓存

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>{% load cache %}{% cache 900 content %}<span>大家好</span><span>我们好</span>
{% endcache %}</body>
</html>

(十三)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})

模板

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><html>
<head><title>省市区列表</title><script type="text/javascript" src="http://code.jquery.com/jquery-2.1.4.min.js"></script><script type="text/javascript">$(function () {//页面加载完成后获取省信息,并添加到省select$.get('/app01/get_parent', function (res) {pro = $('#pro')$.each(res.data, function (index, item) {pro.append('<option value=' + item.id + '>' + item.name + '</option>');})});//为省select绑定change事件,获取市信息,并添加到市select$('#pro').change(function () {$.get('/app01/get_son/' + $(this).val() + '/', function (dic) {city = $('#city');city.empty().append('<option value="">请选择市</option>');dis = $('#dis');dis.empty().append('<option value="">请选择区县</option>');$.each(dic.data, function (index, item) {city.append('<option value=' + item.id + '>' + item.name + '</option>');})});});//为市select绑定change事件,获取区县信息,并添加到区县select$('#city').change(function () {$.get('/app01/get_son/' + $(this).val() + '/', function (dic) {dis = $('#dis');dis.empty().append('<option value="">请选择区县</option>');$.each(dic.data, function (index, item) {dis.append('<option value=' + item.id + '>' + item.name + '</option>');})})});});</script>
</head>
<body>
<select id="pro"><option value="">请选择省</option>
</select>
<select id="city"><option value="">请选择市</option>
</select>
<select id="dis"><option value="">请选择区县</option>
</select>
</body>
</html></body>
</html>

(十四)中间件

介于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 Nonedef process_response(self, request, response):"""视图函数调用之后,内容返回浏览器之前调用"""print("自定义 process_response 1--->必须要有返回值")return responsedef process_view(self, request, callback, callback_args, callback_kwargs):"""url匹配之后,视图函数调用之前调用"""print("自定义 process_view 1")return Nonedef process_exception(self, request, exception):print("自定义 process_exception 1")

当视图没有错误的情况

当视图出现错误的情况

中间件应用

控制访问频率

请求验证

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):# 获取访问者IPip=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 Noneelse:# 如果大于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服务器。

Django运行流程

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 FQDNcharset     utf-8;# max upload sizeclient_max_body_size 75M;   # adjust to taste# Django medialocation /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 root@39.105.46.49

更新服务器

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)与跨站请求脚本正好相反。跨站请求脚本的问题在于,客户端信任服务器端发送的数据。跨站请求伪造的问题在于,服务器信任来自客户端的数据。

视图
from django.shortcuts import render
from django.http import HttpResponsedef 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 viewsurlpatterns = [path('transfer/', views.transfer),
]
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>transfer</title>
</head>
<body>
<h1>银行网站</h1>
<form action="/transfer/" method="post"><p><input type="text" name="key" value="aaaaa" style="display: none"></p><p>转出方账号:<input type="text" name='from'>转入方账号:<input type="text" name='to'></p><p>金额:<input type="text" name="money"></p><p><input type="submit" value="转账"></p>
</form>
</body>
</html>

取消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')

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

编写钓鱼网站模板

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>transfer</title>
</head>
<body>
<h1>钓鱼网站</h1>
<form action="http://127.0.0.1:8000/transfer/" method="post"><p>转出方账号:<input type="text" name='from'>转入方账号:<input type="text" name=''><input type="text" name='to' style="display: none;" value="kkkkk"></p><p>金额:<input type="text" name="money"></p><p><input type="submit" value="转账"></p>
</form>
</body>
</html>

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

开启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标签

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>transfer</title>
</head>
<body>
<h1>银行网站</h1>
<form action="/transfer/" method="post">{% csrf_token %}<p><input type="text" name="key" value="aaaaa" style="display: none"></p><p>转出方账号:<input type="text" name='from'>转入方账号:<input type="text" name='to'></p><p>金额:<input type="text" name="money"></p><p><input type="submit" value="转账"></p>
</form>
</body>
</html>

类视图取消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")

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" % idprint(sql)cursor.execute(sql)rows = cursor.fetchall()ctx = {'rows': rows}return render(request, 'app04/show.html', ctx)

编写模板

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<ul>{% for row in rows %}<li>{{ row.1 }}</li>{% endfor %}</ul></body>
</html>

如果用户传的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.pyINSTALLED_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.pyfrom 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

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

3、视图和模板

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

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

# views.pyfrom 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 = TaskItemtemplate_name = 'tasks/list.html'class TodoItemCreateView(CreateView):model = TaskItemtemplate_name = 'tasks/create_form.html'form_class = TaskItemCreateFormsuccess_url = '/todo/list'class TodoItemUpdateView(UpdateView):model = TaskItemtemplate_name = 'tasks/update_form.html'form_class = TaskItemUpdateFormsuccess_url = '/todo/list'class TodoItemDeleteView(DeleteView):model = TaskItemtemplate_name = 'tasks/delete_form.html'success_url = "/todo/list"

list.html

{% block content%}
{% for task in object_list %}
<li>{{task.body}}</li>
<li>{{task.due_date}}</li>
<li>{{task.category}}</li>
{% endfor %}
{% endblock %}

create_form.html

{% block content %}
<h2>创建待办事项</h2>
<form method="post">
<div>{% csrf_token %} {{ form.as_p }}<input type="submit" value="提交" />
</div>
</form>
{% endblock %}

update_form.html

{% block content %}
<h2>编辑待办事项</h2>
<form method="post">
<div>{% csrf_token %} {{ form.as_p }}<input type="submit" value="提交" />
</div>
</form>
{% endblock %}

delete_form.html

{% block content %}
<h2>删除待办事项</h2>
<form method="post">
<div>{% csrf_token %}<p>删除"{{ object }}"?</p><input type="submit" value="提交" />
</div>
</form>
{% endblock %}
# forms.pyfrom django import forms
from .models import TaskItemclass TaskItemCreateForm(forms.ModelForm):class Meta:model = TaskItemfields =('title', 'body','due_date','category')class TaskItemUpdateForm(forms.ModelForm):class Meta:model = TaskItemfields =('body','due_date','task_finished','category')

路由

# mytodo\urls.pyfrom django.contrib import admin
from django.urls import path
from tasks.views import TodoItemListView, TodoItemCreateView, TodoItemUpdateView, TodoItemDeleteViewurlpatterns = [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/<pk>', TodoItemUpdateView.as_view(), name='update_list'),path('todo/delete/<pk>', 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(一)相关推荐

  1. Anaconda3 离线安装 Django-3.2.7 及依赖项setuptools、sqlparse 、asgiref、typing_extensions等模块

    目录 一.背景 二.离线安装 setuptools.sqlparse .asgiref.typing_extensions等依赖模块 三.离线安装django 一.背景 因为信息安全管理的规定,这台服 ...

  2. 使用pyinstaller打包django3.2

    使用pyinstaller打包django3.2 虽然django项目我们一般通过部署服务器进行发布,但是也有些情况,可能就是一个小小的数据管理应用,也就内部几个人使用,想直接打包成一个应用,在没有任 ...

  3. django3数据库设计之商城项目

    django3数据库设计之商城项目图 数据关系图

  4. Linux(Centos7.8)中conda虚拟环境搭建LSTM神经网络基于django3.1.2的api接口

    目录 1.准备工作 2.项目需求 2.1 根据需求下载LSTM依赖包 2.2 代码实现 3.启动服务 4.第三方应用调用webapi服务提供的api接口 1.准备工作 由上一博客Linux(Cento ...

  5. 【绝对详细!不好使你顺着网线敲我!】Django3.1在Ubuntu16.04上的部署

    前言 转眼间Django版本更新已经到了3.1.7,在使用Django3.1时,使用以往版本的Django部署方法进行部署时许多已经都不起作用,但也能搜索到许多有帮助的技术性文章.于是特将整个部署过程 ...

  6. django3.x+DRF+simpleui+uniapp打造自己的任务推广(兼职、悬赏)平台

    开发目的 市面上也有不少有关兼职.推广.悬赏的源码和平台,基本都是php写的,而且代码存在安全隐患且无法正常运行.熟悉django的我打算自己写一个也准备做做自己的任务推广平台,项目处于内测期(暂无任 ...

  7. Django3在网页上生成二维码

    说明 自用Django3版本,但是百度搜索,搜到的生成二维码的教材都是老版本了,而且用的byteio在django3中也删了,就走了很多歪路. 最后上谷歌搜了一下,发现又更便捷的方法,故分享到这里来 ...

  8. django3.0+ 使用 xadmin

    django3.0中xadminModuleNotFoundError: No module named 'future' pip install futureImportError: cannot ...

  9. Django3创建数据库表模型及 Django 管理页面

    前提条件 Django3创建项目及应用 查看所使用的数据库 打开test01/settings.py,查看使用的是sqlite3 DATABASES = {'default': {'ENGINE': ...

  10. Django3+Vue美多商城项目的总结

    文章目录 项目说明 主要环境搭建 主要技术实现 django 的配置文件 celery的使用(异步发送短信验证码和邮箱验证链接) 容联云通讯短信平台 QQ登录 jwt实现加密解密验证实现数据的安全性 ...

最新文章

  1. ig信息增益 java_文本分类综述
  2. topcoder srm 490 div1
  3. 初学者Git和GitHub简介(教程)
  4. java获取页面点击次数_在Java中怎样得出一个按钮点击的次数
  5. *args和**kargs
  6. linux下NIS服务的配置
  7. Java之数据库基础理论
  8. 常用的限流框架都在这里了!
  9. 新员工入职表_舞钢农商银行:组织新招录员工开展反假币培训
  10. 支持APP的打印服务器,TP-LINK双频无线路由器打印服务器客户端软件
  11. TextView rotation 旋转
  12. ttyS、ttySAC、tty、ttyn的区别
  13. 成为优秀的技术管理者: 先从改变思维做起
  14. postMan请求结果中文乱码
  15. 流媒体协议之WebRTC实现p2p视频通话(二)
  16. 数据科学和人工智能技术笔记 十九、数据整理(上)
  17. 【广东工业大学】谭子真丨个人作品展示
  18. 终于有人把 Docker 讲清楚了,别再说不会 Docker 了!
  19. 数据采集之--换个IP
  20. 《也作瑶池》 ——惊闻许玮伦逝去

热门文章

  1. 住宅空调负荷可调度潜力评估 代码主要做的是住宅空调负荷的可调度潜力评估
  2. tiff/tfw, jpg/jpgw坐标文件的格式(6个参数)
  3. 视频编辑器:Wondershare Filmora x for Mac(10.4.0.14)
  4. win10系统svn服务器端安装步骤,win10系统安装TortoiseSVN的操作方法
  5. Unity3D鼠标拖拽实现相机移动
  6. Hive_Hive 中计算 新旧用户, 日活,周活,月活 ,使用 ORCFile 增量更新的方式
  7. 程序员看世界之中关村与切糕(11)2012-12-16
  8. 《软件工程》总结——序
  9. 华为打印console_华为交换机console命令与调试记录
  10. 头歌C++面向对象实训二