第一部分初步认识django,第二部分具体介绍django的配置信息,第三部分一个小案例
目录
一、第一个Django项目
(一)Django的简介(二)安装
(三)创建Django项目
(四)模型类
(五)后台管理
(六)视图
(七)模板的使用
二、Django配置信息
(一)资源文件配置
(二)templates模板配置
(三)数据库配置
(四)路由
(五)第三方扩展分页
(六)富文本编辑器
(七)发送邮件
(八)站点配置
(九)表单
(十)验证码
(十一)全文检索
(十二)缓存
(十三)Ajax
(十四)中间件
(十五)本地部署
(十六)CSRF
三、实战项目:待办事项
优点: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-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另外一个作用︰根据设计的类生成数据库中的表。
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 根据迁移文件生成表.
生成表名的默认格式:
应用名_模型类名小写
# 关系属性对应的表的字段名格式:关系属性名_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
http://127.0.0.1:8000/
) 的内容。urls.py
,然后在每个应用程序中urls.py
查找包含匹配模式的文件。urls.py,admin/
不匹配的模式 ,移动到第二行空字符串(根 URL)匹配。urls.py
,查找匹配的模式。urls.py
,空字符串再次匹配。这次请求被发送到index
视图。index
视图将我们的简单 HTML 消息呈现给 aHttpResponse
并将其发送到浏览器。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、新建文件夹
模板文件
这是一个模板文件,{{ content }}
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文件夹。括号内为地址和地址对应的视图
]
新建html
显示图书
{% 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 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/#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/....对应。
打开浏览器输入网址,就可以看到图片了。
先配置媒体资源属性,然后注册到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.*)',serve,{'document_root':settings.MEDIA_ROOT},name='media'),
]
模板是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',
],
},
},
]
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条件判断注释。
pip install pymysql
settings.py数据库配置不用改,在MyDjango文件夹中的__init__.py中设置数据库连接模块即可。
import pymysql
pymysql.install_as_MySQLdb() # 设置数据库连接模块
# 数据库配置
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,数据库在项目路径下生成
},
}
在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
python manage.py runserver 8001
先在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(),
}
}
步骤:
运行python manage.py runserver,打开网址
django-admin startproject 项目名
cd 项目名
python manage.py startapp 应用名
'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 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') # 必须要返回处理结果
打开浏览器访问网址
路由变量类型:字符类型、整型、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,如果变量类型不符会报错
添加路由地址外的变量
在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)
在MyDjango项目的index文件夹的urls.py
re_path定义路由函数正则表达式
(?P
.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)
]
没有.html则可在最后一个变量之后无限输入字符串
在刚刚文件夹上新建一个应用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.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!")
不同项目应用的路由命名是可以重复的,namespace是路由函数include的可选参数,路由命名name是路由函数path或re_path的可选参数。include中如果设置name是没有实质作用的,所以没必要设。Django的路由名name是对路由进行命名的,作用是在开发中可以在视图或模板等其他功能模块里使用路由命名name来生成路由地址。
从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找到某条路由的具体信息,这样就能有效管理整个项目的路由列表。
不设置命名空间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的路由。
设置命名空间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'
反向解析:用户浏览网站,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函数
按住ctrl键点击上面的views.py中的reverse,可查看reverse的源码
- viewname:代表路由命名或可调用视图对象,一般情况下是以路由命名name来生成路由地址的。
- urlconf:设置反向解析的URLconf模块。默认情况下,使用配置文件settings.py的ROOT_URLCONF属性(MyDjango文件夹的urls.py)
- args:以列表方式传递路由地址变量,列表元素顺序和数量应与路由地址变量的顺序和数量一致。
- kwargs:以字典方式传递路由地址变量,字典的键必须对应路由地址变量名,字典的键值对数量与变量的数量一致。
- current_app:提示当前正在执行的视图所在的项目应用,主要起到提示作用,在功能上并无实质的作用。
内置的函数方法:
函数方法 | 说明 |
func | 路由的视图函数对象或视图类对象 |
args | 以列表格式获取路由的变量信息 |
kwargs | 以字典格式获取路由的变量信息 |
url_name | 获取路由命名(name) |
app_name | 获取项目路由函数include的参数arg的第二个元素值 |
app_names | 与app_name功能一致,但以列表格式表示 |
namespace | 获取命名空间(namespace) |
namespaces | 与namespace功能一致,但以列表格式表示 |
view_name | 获取整个路由名称,格式:namespace:name |
重定向: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实现网页重定向的,函数参数只需传入路由地址即可实现重定向。
模板语法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 %}
{% if articles.has_previous %}
上一页
{% else %}
上一页
{% endif %}
{% for page in articles.pages %}
{% if page %}
{% ifequal page articles.number %}
{{ page }}
{% else %}
{{ page }}
{% endifequal %}
{% else %}
...
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
下一页
{% else %}
下一页
{% endif %}
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})
#模板
#自定义表单
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})
#模板
函数full_clean()依次调用每个field的clean()函数,该函数针对field的max_length,unique等约束进行验证,如果验证成功则返回值,否则抛出ValidationError错误。如果有值返回,则放入form的cleaned_data字典中。
如果每个field的内置clean()函数没有抛出ValidationError错误,则调用以clean_开头,以field名字结尾的自定义field验证函数。验证成功和失败的处理方式同步骤1。
最后,调用form的clean()函数——注意,这里是form的clean(),而不是field的clean()——如果clean没有错误,那么它将返回cleaned_data字典。
如果到这一步没有ValidationError抛出,那么cleaned_data字典就填满了有效数据。否则cleaned_data不存在,form的另外一个字典errors填上验证错误。在template中,每个field获取自己错误的方式是:{{ form.username.errors }}。
最后,如果有错误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})
全文检索不同于特定字段的模糊查询,使用全文检索的效率更高,并且能够对于中文进行分词处理
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发起请求把数据请求回来填充到页面就可以了。
模型
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)
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")
当视图没有错误的情况
当视图出现错误的情况
中间件应用
控制访问频率
请求验证
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服务器。
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 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)与跨站请求脚本正好相反。跨站请求脚本的问题在于,客户端信任服务器端发送的数据。跨站请求伪造的问题在于,服务器信任来自客户端的数据。
视图
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运行网站。
开启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
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" % 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
登录后可以手动添加一些数据试试
3、视图和模板
Django 中的视图在模板显示数据时将数据发送到模板。
编写tasks/views.py文件,创建几个模板文件html和表单tasks/forms.py
# 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 %}
创建待办事项
{% endblock %}
update_form.html
{% block content %}
编辑待办事项
{% endblock %}
delete_form.html
{% block content %}
删除待办事项
{% 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