python_Django
1、Python用具 - pip
1、作用:
Python的软件包管理器,有一些python包被集成到了pip中。只要被集成到pip中的包,都允许通过pip直接安装
2、安装 pip
sudo apt install python-pip(python2)
sudo apt install python3-pip(python3)
3、使用pip/ pip3
1、安装/下载/更新/删除 python包
1、安装python包(下载并安装)
sudo pip3 install SomePackage
sudo pip3 install PyMySQL==0.7.11(如果不写版本号默认为最新的版本)
2、下载python包(值下载不安装)
sudo pip3 download SomePackage
3、删除python包
sudo pip3 uninstall SomePackage
4、更新(升级)python包
sudo pip3 upgrade SomePackage
2、查看当前环境中所安装的包
pip3 list
3、搜索
pip3 search SomePackage
4、展示
pip3 show SomePackage
5、记录现有环境的python包
1、pip3 freeze > requirements.txt
将当前python环境中所安装的内容打包成一个txt文件
2、pip3 install -r requirements.txt
允许在当前系统下,逐一安装requirements.txt中所有列出的内容
2、Python工具 - VirtualEnv
1、什么是VirtualEnv - 虚拟环境
virtualEnv是python中的虚拟环境,在做python应用开发时,如果不想在大的python环境中安装各种各样的包的话,则可以虚拟出一个python环境,可以让虚拟环境专门为某一应用而存在。允许在虚拟环境中安装各种包且不影响大的python环境
2、安装VirtualEnv
sudo pip3 install virtualenv
3、创建 和 使用 虚拟环境
1、准备工作
mkdir my_env
cd my_env
2、创建虚拟环境
virtualenv 虚拟环境名称
示例:virtualenv default
创建指定版本的虚拟环境
virtualenv -p /usr/bin.python2.7 名称
virtualenv -p /usr/bin.python3.6 名称
3、启动虚拟环境
注意:不能在bin目录中启动虚拟环境(根目录下的bin目录)
source bin/activate
4、退出虚拟环境
deactivate
5、删除虚拟环境
rm 虚拟环境目录 -rf
注意:在虚拟环境中使用pip安装和卸载内容时,不要使用sudo进行授权,如果使用则操作的是大环境
4、虚拟环境管理工具 - VirtualenvWrapper
1、作用
第三方的管理工具,能够快速,高效且方便的管理虚拟环境
2、安装虚拟环境管理工具
sudo pip3 install virtualenvwrapper
3、配置virtualenvwrapper
在~(家目录)目录下,有一个终端管理文件 .bashrc(在~目录下,输入ll查看)
配置.bashhrc,以便在启动终端时,就自动启动虚拟环境管理工具
修改.bashrc: sudo vi .bashrc
在.bashrc 最底部增加一下内容
1、export WORKON_HOME=~/my_env:
将~/my_env 作为虚拟环境的管理目录,所有使用virtualenvwrapper创建的虚拟环境都默认保存于此
2、如果系统中包含多个python执行环境的话,则添加一下内容
export VIRTUALENVWRPPER_PYTHON=/usr/bin/python3
3、source /usr/local/bin/virtualenvwrapper.sh:默认启动刮管理工具
4、在~目录下,执行一遍.bashrc
source .bashrc
4、使用虚拟环境管理工具
1、创建并进入虚拟环境管理工具
1、mkvirtualenv 虚拟环境名称
2、mkvirtualenv --python=/usr/bin/python2.7 env2.7
2、查看当前所维护的所有虚拟环境
workon
3、切换虚拟环境
workon 虚拟环境名称
4、退出虚拟环境
deactivate
5、删除虚拟环境
rmvirtualenv 虚拟环境名称
3、WEB 与 服务器
1、WEB:表示用户可以浏览的网页(HTML,CSS,JS)
2、服务器:专门给用户提供服务的一台机器
1、硬件 与 软件
硬件范畴:一台主机
软件范畴:一个能够接收用户请求并给出响应的程序
1、APACHE
2、TOMCAT
3、IIS(Internet Information Service)
4、Nginx
2、作用:
1、存储WEB上的信息(网页,图片,音视频,css,js)
2、能够处理用户的请求(request)并给出响应(response)
3、能够执行服务器端程序:如查询数据库
3、WEB与服务器的关系
WEB需要放在服务器上才能够被用户访问
运行在服务器端的程序,可以由不同的语言来编写
Java语言-->JSP
C#语言-->ASP>NET
PHP语言-->php
Python语言-->Django
4、网站请求的全过程
1、用户:输入域名,通过域名解析(DNS)器得到IP地址
2、向服务器发送http(开80端口)/https(开440端口)请求
3、传输层TCP协议,经过网络传输和路由解析
4、WEB服务器接收HTTP请求
5、服务器处理请求内容,并进行必要的数据交换(我们需要做的事情)
6、将响应的内容发回给浏览器(响应)
7、浏览器解析HTML
8、显示解析好的内容
4、框架
1、什么是框架
框架是一个为了解决某些开放性问题而存在的一种结构。框架本身提供了最基本的功能,我们只需在这些基本功能上构建自己的操作即可。
2、框架的优点
1、快速开发 - 基本功能已经提供好了
2、可以解决大部分问题
3、bug少,稳定性较高
3、框架的分类
1、前端框架
处理前端内容(HTML,CSS,JS)
2、后端框架
处理服务器程序的
Spring -Java
3、全栈框架
包含WEB整体的解决方案,包括开发框架,运行环境
Rails(Ruby)
Django(Python)
4、Python的WEB框架
1、Django:重量级的Python Web框架
2、Tornado:异步框架
3、Flask:轻量级框架,直接引入模块即可使用
4、Webpy:轻量级框架
5、Web2py:全栈框架,webpy的加强版
1、设计模式 与 框架模式
1、设计模式
设计模式,是一套被反复使用,多数人知晓并经过分类的代码设计经验的总结,是为了解决一些通用性问题的
目的:重用代码并保证代码的可靠性
官方认证的设计模式有23中:单列模式,抽象工厂模式,观察者模式等 《大话设计模式》
2、框架模式
代码的重用,框架模式是解决如何设计程序框架的代码,在框架模式中会包含多种的设计模式
如:MVC,MTV,MVVM,ORM,...
1、MVC
M:Models,模型层,
在程序中主要处理数据,负责在数据库中对数据进行存取操作(CRUD)
V:Views,视图层
应用程序中处理显示的部分内容(HTMl,JSP)
C:Controllers,控制器层
处理用户交互的部分,通常负责从模型中取出数据,再进行业务的处理,最后将数据给视图,并将视图给客户端
2、MTV
M:Models 模型层,
模型层,负责数据库建模以及CRUD的操作
T:Templates 模板层
用于处理用户显示的部分内容,如:html
V:Views 视图层
处理用户交互部分,从模型中获取数据,再将数据给模板,在显示给用户
2、Django框架
1、什么是Django
是一个开源框架,2005年发布,采用python语言开发的。早期Django是做新闻和内容管理的网站的,提供了非常强大的后台管理系统,采用的是MTV框架模式
2、Django的优缺点
1、优点
1、开源框架,有完美的文档支持
2、解决方案比较完整,内部功能也比较多
3、提供完整的路由系统,优雅的URL解析方式
4、自助式的后台管理
2、缺点
1、耦合度偏高
3、Django的安装
1、Linux中的安装
1、查看已安装的Django
1、进入到虚拟环境中
2、进入到python的交互模式中
3、在交互模式中输入
1、import django
2、django.VERSION
2、在线安装 - 使用 pip
1、终端中输入
pip install django(安装django的最高版本)
pip install django==1.11.8
注意:在虚拟环境中不要使用sudo
2、离线安装
1、下载所需要的django包
2、在Linux中解压django
tar - xvf Django-1.11.8.tar.gz
3、进入到Django文件夹中
4、安装
python setup.py install
2、Windows中的安装
1、在线安装
控制台: pip3 install django==1.11.8
2、离线安装
1、下载django安装包
2、解压django包
3、进入到django包中
python setup.py install
4、使用Django
1、创建Django项目
直接使用django-admin去创建Django项目
1、找到项目文件夹(自定义)
2、使用django-admin 指令
django-admin startproject 项目名称
2、启动Django项目
1、进入到项目文件夹中
2、通过manage.py 启动项目
1、
python manage.py runserver
或 ./manage.py runserver
只能在本机访问
http://localhost:8000
http://127.0.0.1:8000
2、
python manage.py runserver 0.0.0.0:8000
或 ./manage.py runserver 0.0.0.0:8000
允许在局域网内访问。可以通过IP地址访问,但是需要将setting.py文件中ALLOWED_HOSTS = []修改为ALLOWED_HOSTS = ["*"]
5、Django结构介绍
1、manage.py
负责执行django中的各项操作的文件,又叫命令脚本文件
如:
1、启动服务
2、创建应用
3、创建管理员、用户
....
2、主文件夹(名称与项目名称相同)
存放项目的最基础的配置文件
1、__init__.py
项目初始化文件,每当服务器启动的时候,会自动执行,如果有自定义的初始化操作,需要放在该文件中
2、urls.py
项目的基础url(路由)配置文件
路由:去哪里找执行的程序
3、wsgi.py
配置应用服务器的文件,暂时不用
4、settings.py(重要)
项目的主设置文件:应用:模板,数据库,语言,时区....
1、BASE_DIR:项目的绝对路径
2、DEBUG:调试模式
开发过程中,推荐使用Ture,上线运行时,必须改为False
3、ALLOWED_HOSTS
设置允许访问本地项目的地址列表,如果不设置的话,只能本机访问,推荐用"*",表示任何机器都允许访问当前项目
4、INSTALLED_APPS
指定已经安装的应用,如果有自定义应用的话,需要在此注册
5、MIDDLEWARE:注册中间件
6、ROOT_URLCONF:指定项目的基础路由配置文件
7、TEMPLATES:指定模板的信息
8、DATABASES:指定数据库的信息
9、LANGUAGE_CODE:指定语言,允许修改为zh-Hans
10、TIME_ZONE = 'UTC':指定时区,建议改为Asia/Shanghai
6、settings的加载流程
1、先加载globals_settings.py
位于:/home/xdl/my_env/env3.5/lib/python3.6/site-packages/django/conf/globals_settings.py
2、再加载项目中的settings.py
注意:如果globals_settings中的内容与项目settings中的内容冲突的话,优先使用项目中的settings中的内容
7、初始 django-admin 和 mangage.py
1、在终端输入django-admin命令
check
compilemessages
createcachetable
dbshell
diffsettings
dumpdata
flush
inspectdb
loaddata
makemessages
makemigrations
migrate
runserver
sendtestemail
shell:python3 manage.py shell ,进入django的交互环境,
showmigrations
sqlflush
sqlmigrate
sqlsequencereset
squashmigrations
startapp
startproject#创建项目
test
testserver
2、进入项目主目录文件夹,输入./manage.py
[auth]
changepassword #修改密码
createsuperuser #创建超级用户
示例:
1、首先需要创建一张用于存储用户信息:./manage.py migrate
2、创建用户:./manage.py createsuperuser
[contenttypes]
remove_stale_contenttypes
[django]
check
compilemessages
createcachetable
dbshell #进入到Django数据shell交互模式
diffsettings
dumpdata
flush
inspectdb #将数据表直接导出为Models
loaddata
makemessages
makemigrations#创建数据库日志文件,记录Models的改动
migrate #将数据库日志文件同步到数据库中
sendtestemail
shell
showmigrations
sqlflush
sqlmigrate
sqlsequencereset
squashmigrations
startapp #创建应用
startproject
test
testserver
[sessions]
clearsessions
[staticfiles]
collectstatic
findstatic
runserver #启动服务
8、URL的使用
1、urls.py
默认在主文件夹中,包含所有的地址映射。
每当一个请求产生后,都会到urls.py中进行地址的匹配,匹配上后再找对应的处理程序(View视图)去处理
2、测试
1、在主文件夹中,创建views.py
作用:包含所有定义好的视图(处理程序)
内容包括:
from django.http import HttpResponse
def fun_views(request):
'''视图,处理用户的请求并给出响应
request:表示用户的请求信息
HttpResponse:响应给客户端的内容'''
return HttpResponse("Hello django")
2、在urls.py中追加
from .views import *
urlpatterns = [
url(r'^admin/',admin.site.urls),
//如果访问路径是fun/ 的话,则交给fun_views视图处理函数去处理
url(r'^fun/$',fun_views),//如果这里添加了自定义视图处理函数时,localhost:8000将会失效
//如果请求的URL在这里可以匹配多个,则只能执行第一个匹配到的
]
3、url函数
url函数的语法:
url(regex,views,kwargs=None,name=None)
1、regex:正则表达式,匹配请求的url
2、views:url处理的视图函数,通常都是自定义的
3、kwargs:字典,用来向views传参
4、name:字符串,给url()起一个别名,主要在模板中匹配{%url%}一起使用
4、url向view传参
1、使用正则表达式传参
使用正则表达式的子组传参,使用()
urlpatterns=[
//访问路径必须是fun
url(r'^fun/$',fun_views),
//访问路径必须是fun
url(r'^fun/$',fun_views),
url(r'^fun/(\d+)',fun_arg1_views),
]
注意
1、在url()中,一个子组()表示一个参数
2、在views.py中,对应的处理函数要根据url()中子组的个数,相应的定义参数,定义的参数要位于request之后
练习:
1、访问地址:localhost:8000/18/0223/15,如何获取18 0223 15
def fun_arg3_views(request,num1,num2,num3):
return HttpResponse("%s %s %s"%(num1,num2,num3));
url(r'^(\d{2})/(\d{4})/(\d{2})$',fun_arg3_views),
2、使用url()第三个参数,字典传参
urlpatterns=[
url(r'^showname/$',show_views,{'name':"zhang",'age':25}),
]
views.py:
def show_views(request,name,age):
return HttpResponse(name+':'+str(age))
注意:
1、视图处理函数中,必须声明参数
2、参数的名称 和 位置 必须要与字典中的名称和位置保持一致
3、Django中的应用
1、什么是应用
应用是网站中的一个独立的模块,包含独立的显示信息
在项目主文件夹中一般不处理其他的请求,主要就做初始化设置 以及 地址的分发
实际操作中,会将请求交给不同的应用去处理
2、创建应用
1、命令: ./manage.py startapp 应用名称
2、在settings.py中注册应用:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'index',
]
3、应用的结构组成
1、migrations 目录
存放数据库日志文件,是一个django与数据库交互的中间文件
2、__init__.py
应用的初始化操作文件
3、admin.py
应用的后台管理配置文件
4、apps.py
应用的属性设置文件,不需改动
5、modles.py
Modles模型文件
6、tests.py
测试模块,通常不用
7、views.py
定义视图的py文件
练习:
创建应用,并进行注册
在day02_exer 中创建应用
1、index - 主页面的应用
./manage.py startapp index
2、news - 新闻的应用
./manage.py startapp news
3、sports - 体育的应用
./manage.py startapp sports
4、musics - 音乐的应用
./manage.py startapp musics
在settings.py中的INSTALLED_APPS列表中添加以上应用
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'index',
'news',
'sports',
'musics',
]
from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), ] urlpatterns += [ url(r'^music/', include('music.urls')), url(r'^sport/',include('sport.urls')), url(r'^news/',include('news.urls')), #匹配空的时候一定要放在最后 url(r'^', include('index.urls')), ]
1、Django模板(Template)
1、什么是模板
就是一个网页,可以被view响应给用户
目的是为了解决复杂的显示问题
2、模板的设置
1、BACKEND:指定模板的搜索引擎,不用改动(就是指定到哪里搜索模板)
2、DIRS:指定模板所存放的目录,如果DIRS为空的话并且APP_DIRS为True,那么django会自动搜索每个应用中的templates文件作为模板管理目录
DIRS = ['index.trmp','music.temp']
推荐:
1、DIRS保持为空
2、在每个应用中,创建一个templates的文件夹
3、APP_DIRS:值为boolean类型
True:首先从DIRS中指定的文件夹中查找模板,如果没有找到指定模板的话,则再搜索templates目录
3、模板的加载方式
1、使用loader 获取模板,通过HttpResponse进行响应
from django.template import loader
def xxx(request):
#1、通过loader加载模板
t = loader.get_template('show.html')
#2、将模板渲染成字符串
html = t.render({})
#3、通过HttpResponse响应回去
return HttpResponse(html)
说明:
render({}),字典中的是数据,会传入html文档中,在HTML中通过{{字典的键}}取值,{{num1}}
render({}),字典参数,可以通过locals(),获取该函数中的局部变量的字典,进行传递
2、使用render直接加载
return render(request,'模板名称',{})
4、url()的name参数
urlpatterns = [
url(regex,views,kwargs=None,name=None)
]
name:定义当前url的别名,允许在Template中使用该别名来找到对应的url(反向解析)
反向解析:通过name 的值来匹配出对应的regex路径
在Django模板中使用name实现连接
{% url 'name值' %}
如果url中有参数需要{% url 'name值' 参数1 参数2 ...%}
在视图中实现name别名反向解析出对应的URL地址
需要引包:from django.shortcuts import reverse
语法:
1、无参数解析:reverse("别名")
2、带参数解析:reverse("别名",args = (参数1,参数2....))
from django.shortcuts import render from django.http import HttpResponse from django.urls import reverse # Create your views here. def index_views(request): return HttpResponse("news index_views") def reverse_views(rquest): #反向解析url(不带参数),/news/reverse #url = reverse("reverse") #反向解析url(带参数),/news/reverse/2018/08 url = reverse('reverse_args',args=(2018,'08')) return HttpResponse("反向解析出的URL:"+url)
5、模板的语法
1、变量
1、 作用:允许将后端的数据传递给模板(html),在模板中,会根据变量的实际值进行显示
2、在Django中允许传递给模板作为变量的数据类型
数字,字符串,列表,元组,字典,函数,对象,类。 集合不可以
3、变量语法
变量们必须要封装到字典中才能传递给模板
1、使用render加载模板
dic = {
’变量1’:‘值1’,
‘变量2’:‘值2’,
....
}
return render(request,'xx/html',dic)
2、使用loader加载模板
dic = {
’变量1’:‘值1’,
‘变量2’:‘值2’,
....
}
t = loader.get_template('x.html')
#渲染成字符串是需要传递变量字典到模板中
html = t.render(dic)
return HttpResponse(html)
4、在模板中使用变量:
{{变量名}}
如果要取列表,字典,元组中的值要通过变量名.下标 或 变量名.键
def var_views(request): #声明变量字典 l = ['金毛狮王','白眉鹰王','青'] t = ('潘林连','西门庆','武大郎') dic = { 'SHZ':"水浒传", 'xyj':"西游记", 'hlm':'红楼梦' } def fun(): return '函数' class Dog(object): name = '阿拉斯基' def eat(self): return '吃狗粮' vars = { 'num':15, 'str':'模板中的字符串变量', 'tup':t, 'list':l, 'dic':dic, 'fun':fun(),#等价于'fun':fun 'dog':Dog(),#等价于Dog } return render(request,'02_var.html',vars)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>num:{{ num }}</h3> <h3>str:{{ str }}</h3> <h3>tup:{{ tup }}</h3> <h3>tup[0]:{{ tup.0 }}</h3> <h3>list:{{ list }}</h3> <h3>list[1]:{{ list.1 }}</h3> <h3>dic:{{ dic }}</h3> <h3>dic['xyj']:{{ dic.xyj }}</h3> <h3>fun:{{ fun }}</h3> <h3>dog:{{ dog }}</h3> <h3>dog.name:{{ dog.name }}</h3> <!--调用类方法内中函数时只用对象.函数名,无需加括号--> <h3>dog.eat:{{ dog.eat }}</h3> *********************************************************** <h3>tup:{{ t }}</h3> <h3>tup[0]:{{ t.1 }}</h3> <h3>list:{{ l }}</h3> <h3>list[1]:{{ l.1 }}</h3> <h3>dic:{{ dic }}</h3> <h3>dic['xyj']:{{ dic.xyj }}</h3> <h3>fun:{{ fun }}</h3> <h3>dog:{{ Dog }}</h3> <h3>dog.name:{{ Dog.name }}</h3> <!--调用类方法内中函数时只用对象.函数名,无需加括号--> <h3>dog.eat:{{ Dog.eat }}</h3> </body> </html>
2、标签
1、什么是标签
允许嵌套一些服务器端的逻辑运算到模板中
2、语法
{% %}
3、常用标签
1、{% if 条件 %} ...{% endif %}
接受:not and or
但是 :and 和 or 不能同时出现
以下内容当成False处理:
空[]
空()
空{}
数字:0
空字符串
特殊对象:None
2、{%if 条件 %}...{%else%}...{%endif%}
3、
{%ifequal 值1 值2%}...{%endifequal%}:判断值1与值2是否相等
{%ifequal 值1 值2%}...{%else%}...{%endifequal%}
4、{% for 变量 in 列表|元组|字典%}{%endfor%}
允许使用的内置变量(免声明)
forloop
1、forloop.counter:记录循环的次数
2、forloop.counter0:同上,但从0开始
3、forloop.revcounter:记录未被遍历的数量
4、forloop.revcounter0:同上,从0开始
5、forloop.first:布尔值,标记是否为第一个项目
6、forloop.last:布尔值,表示是否为最后一个项目
{% for str in l %} <!--将第一条数据的背景色变为红色--> <h3 {% if forloop.first %} style="background:red;" {% endif %} >数据{{forloop.counter0}}:{{ str }} </h3> {% endfor %}
5、{%url%}
6、{%static%}
7、{%extends%}:用作模板继承
8、comment 标签
作用:在服务器端就被注释的内容,不会被渲染到客户端的
<!--注释内容-->>:客户端注释会被渲染到客户端,在其中的{{ 服务器代码}},回去执行解释
3、过滤器
1、作用
在显示变量之前,允许对数据进行筛选或改变
2、过滤器的语法
{{var|过滤器}}
3、常用过滤器
1、{{var|upper}}:将var的数据变为大写
2、{{var|lower}}:将var的数据变为小写
3、{{var|add}}:
4、{{var|floatformat:n}}:将var四舍五入到n为小数
5、{{value|truncatechars:n}}:将value截取保留至n位字符(包含三个点...)
自定义标签和过滤器
步骤:
1、在应用目录下创建templatetags目录
2、在templatetags创建模块文件,并导入Django内部方法
3、在模板最上方中加载自定义的模块文件,{% load 模块文件名%}
自定义过滤器
1、在templatetags目录下创建python模块,例如命名为tags.py
from django import template register = template.Library() @register.filter def value_verification(value): # value为前端传递的参数
'''最多传递两个参数''' try: int(value) return True except: return False
<!--前端模块中的代码-->
{% load app01_func %} {% if load|value_verification %} {{ num }} is a valid int number. {% else %} {{ num }} is letter. {% endif %}
自定义标签
1、simple_tag的代码方式与filter一样,不同的是在装饰器部分和前端调用的方式不同
from django import template register = template.Library() @register.simple_tag def value_verification(value): # value为前端传递的参数 '''可以传递多个参数''' try: int(value) return True except: return False
2、前端模块中调用{% value_verification num %}
filter 和 simple_tag的区别
1、filter可以用在if 条件判断中,但是最多只能有两个参数,可以将多个参数用特定字符拼接成一个字符串传递给后端,后端通过拆分获取多个参数
2、simple_tag不能用在if、for语句中,可以传递多个参数
3、模板中的调用方式不同
1、filter将我们指定的函数变成了返回值可执行的方法{{ 参数1 | value_verification:参数2 }},冒号后面不能有空格
2、simple_tag将函数功能变为标签功能{% value_verification 参数1 参数2...... as 返回结果的别名 %}
4、静态文件的处理
1、什么是静态文件
在Django中,不被解释器动态解析的文件就称为静态文件,在Django中,物理路径(磁盘中真是存在的)是无法找到静态文件的
模板中所用到的css,js,image等一些资源文件都是静态文件
2、Django中静态文件的处理
需要在settings.py中设置静态文件的访问路径 和 存储路径
1、STATIC_URL:设置静态文件的访问路径
STATIC_URL = '/static/'
2、STATICFILES_DIRS:设置静态文件的存储路径
1、STATICFILES_DIRS = (BASE_DIR,'static')
2、STATICFILES_DIRS = (os.path.join(BASE_DIR,'静态文件目录名'))
静态文件目录存放位置:
1、所有应用中创建一个同名目录
2、项目的根目录处也可以创建一个同名文件
3、访问静态资源
1、<img src="/static/images/huiyuan.jpg">
2、使用{%static%}访问静态资源
{%static%}:表示的就是静态文件资源的访问路径(就是setting.py中STATIC_URL的值,STATIC_URL = '/static/')
1、模板的最顶层增加{%load static%}
2、使用静态资源文件时
<img src="{%static 'images/huiyuan.jpg'%}"
5、模板的继承
1、什么是模板的继承
当多个模板(网页)具备大部分相同的内容时,就可以使用继承的方式,将相同的内容继承过来,在增加/修改属于自己的内容即可
2、模板继承的语法
1、在父模板中增加{%block 名称%}...{%endblock%}
说明:名称不能重复
2、在子模板中
1、在最顶层第一句话增加:
{%extends '父模板的名称'%}
2、增加block标记,编写属于自己的内容
{%block 名称%}//这里的名称要与父模板{%block 名称%}中的名称相同
属于子模板中自己的内容
//一旦引用次标记,则此处不再显示父模块中的内容
{%endblock%}
2、Django模型(Model)
1、什么是模型
模型,就是根据数据中数据表的结构而创建出来的class。
数据库中的每一张表到编程语言中就是一个class
数据库表中的每一个字段(列)可以被构建成class中的一个成员变量(属性),并且在模型中,完成对数据库的CRUD操作
C:Create
R:Retrieve(检索查找)
U:Update
D:Delete
2、创建 和 使用模型 - ORM
1、什么是ORM
ORM:Object Relational Mapping(对象关系映射)
简称:ORM, O/RM, O/R Mapping
三大特征:
1、数据表到类(class)的映射
允许将表自动生成一个类,也允许将一个类自动生成一张表
2、数据类型的映射
允许将表中字段的类型自动生成到编程语言中对应的数据类型,也允许将编程语言中的数据类型生成数据表中对应的字段类型
3、关系映射
数据库中表的关联关系:
一对一,一对多(多对一),多对多
将表中的关联关系也映射到编程语言的class中,通过创建对象的关系来完成映射
允许将类与类之间的关系自动映射成表与表之间的关系
class A(object):
name = None
class B(object):
a = A()#在表中通过外键进行关联
2、ORM的优点
1、提高了开发效率,能够自动完成实体类到数据表的映射,
2、可以省略庞大的数据访问层,即便不用SQL编码(语句),就能够完成对数据的CRUD操作
3、创建 和 配置数据库
1、创建数据库(支持中文)
create database webdb default charset=utf8
create database webdb default charset utf8 collate utf8_general_ci
2、Django中数据库的配置
settings.py中配置数据库信息
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'webdb',
'USER': 'debian-sys-maint',
'PASSWORD':'Lo0r79JmxvMFNtA2',
'HOST':'localhost',
'PORT':'3306',
}
}
1、ENGINE:引擎
django.db.backends.mysql
2、NAME:要连接到的数据库名称
3、USER:用户名称
4、PASSWORD:密码
5、HOST:连接的主机,本机的话localhost/127.0.0.1/不写
6、PORT:端口,3306
4、安装pymysql
注意:Django中要连接MySQL数据库的话要依赖于MySQLdb,通过pymysql解决问题
pip install pymysql==0.7.11
5、在主文件夹找找到__init__.py写入
import pymysql
pymysql.install_as_MySQLdb()#转换为MySQLdb
6、启动django
./manage.py runserver
4、数据库的同步操作
1、./manage.py makemigrations
作用:将每个应用下的models.py文件生成一个数据库的中间文件(映射成一个数据库日志文件),并存放在migrations目录中
2、./manage.py migrate
作用:将每个应用下的migrations目录中的中间文件(日志文件)同步到数据库中
当migrations目录中没有中间文件时,会创建Django中自带的数据表
5、编写Models(重难点)
1、注意:
1、Models中的每个class都称之为 模型类(Model)或实体类(Entry)
实体:数据表中的一行记录,就是一个实体
实体完整性:确保每张表中的数据不能有重复的,数据表中的主键,是实现实体完整型的方式之一
2、Models中的每个实体类,必须继承自models.Model
2、示例:
在models.py中
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=20)
website = models.URLField()
from django.db import models import datetime # Create your models here. #实体类:Publisher #对应到数据库中的一张,表表名为index_publisher(应用名_实体类名小写) #该类中的每个属性,会对应到数据表中的每个字段啊 class Publisher(models.Model): name = models.CharField(max_length=30,deafult='匿名') address = models.CharField(max_length=60) city = models.CharField(max_length=30) country = models.CharField(max_length=30) website = models.URLField() class Author(models.Model): name = models.CharField(max_length=30) age = models.IntegerField() email = models.EmailField(null=True) class Book(models.Model): title = models.CharField(max_length=50) publication_date = models.DateField(default=datetime.datetime.now())
6、Django中的字段类型以及字段选项
1、字段类型(Field Types):映射到数据库表中的数据类型
1、BooleanField():tinyint()
2、CharField():varchar()
3、DateField():date
4、DateTimeField():datetime(6),6位精度 2018-08-27 16:43:20.000000
5、FloatField():double()
6、FileField():varchar(100)
7、EmailField():varchar(254)
8、IntegerField():int(11)
9、ImageField(upload_to=None):varchar(100)存放文件路径
uimg=models.ImageField(upload_to='images/users/')
10、URLField():varchar(200)
11、DecimalField(max_digits=7,decimal_places=2):decimal(7,2),通常用来表示钱
12、TextField():longtext()存放大量数据
2、字段选项:对生成的字段的说明信息
1、null:是否允许为空,默认为False
name = models.CharField(max_length=30,null=True)
2、default:为该字段设置默认值
name = models.CharField(max_length==30,default="匿名")
3、db_cloumn
指定当前属性(字段)对应到数据库表的列名,如果不指定则采用属性名作为列名
3、说明:
如果在原先实体类中添加属性(字段)时,必须给这个字段设置为允许为空(null=True)或者给一个默认值default=‘值’,否则会有如下提示
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
7、数据的导入和导出(数据迁移)以及版本切换
1、版本切换
./manage.py migrate 应用名称 版本号
./mansge.py migrete index 0001 //会将原先已经映射的数据表删除
2、数据库的导出
1、mysqldump -u... -p 数据库名 >文件.sql
导出所有的表结构以及数据
2、mysqldump -u... -p -d 数据库名 >文件.sql
只导出所有的结构
3、数据库的导入
mysql -u.. -p 数据库名 < 文件.sql
4、通过数据库自动导出Models
./manage.py inspectdb >文件名.py
表名index_book变为实体类名为IndexBook
class IndexBook(models.Model):
title = models.CharField(max_length=50)
publication_date = models.DateField()
class Meta:
managed = False
db_table = 'index_book'
1、模型的数据库操作方法(CRUD)
1、通过视图向DB中增加数据
1、Entry.objects.create(属性=值,属性=值)
返回值:创建好的实体,
Author.objects.create(name='王宝强',age=33,email='wangbaoqiang@green.com')
2、创建一个实体对象,并通过save()方法完成增加
obj = Entry(属性=值,属性=值)
obj.save()
3、通过字典创建实体对象,在调用save()
dic = {
"name":"xx",
"age": ,
"email":"xx"
}
obj = Author(**dic)
obj.save()
示例:
dic = {"name":"陈羽凡","age":38,"email":"chenyufan@green.com"}
obj = Author(**dic)
obj.save()
def add_views(request): #方法1、向Author实体中增加一条记录 ret = Author.objects.create(name='老舍',age=85,email='laoshe@163.com') return HttpResponse(ret)#返回一个实体类对象,age是str,int都可以 #方法二 author = Author(name='巴金',age=75,email='bajin@163.com') ret = author.save() return HttpResponse(ret)#返回值为None #方法三 dict = { 'name':'冰心', 'age':80, 'email':'bingxin@163.com', } author = Author(**dict) ret = author.save() return HttpResponse(ret)#返回None
2、查询操作(重难点)
所有的查询都要在Entry.objects.基础上完成
1、基本查询操作
语法:all()
用法:Entry.objecsts.all()
返回:QuerySet(查询结果集,是一个封装了若干对象的列表)
<QuerySet [<Author: Author object>, <Author: Author object>, <Author: Author object>]>
<QuerySet [<Author: 老舍>, <Author: 老舍>, <Author: 巴金>, <Author: 冰心>]>
def query_views(request): #查询Author实体中所有的数据 #返回一个列表,其中封装了若干的对象 authors = Author.objects.all() for au in authors: print(au.name,au.age,au.email) return HttpResponse('query ok')
2、查询接口
1、all()
Entry.objects.all()
相当于:select * from ...
2、查询指定列的操作
语法:values("列名1",‘列名2’...)
Entry.objects.values('name')
相当于:select name from ...
作用:查询所有记录的某一列的值
返回值:QuerySet(查询结果集,是一个封装了若干字典的列表)<QuerySet [{'name': '王宝强'}, {'name': '贾乃亮'}, {'name': '陈羽凡'}]>
注意:values()可以用在QuerySet(查询结果集)后面比如:all().values()
def query_views(request): #查询Author实体中name 和 age的信息 authors = Author.objects.values('name','age') print(authors) # < QuerySet[ # {'age': 85, 'name': '老舍'}, # {'age': 85, 'name': '老舍'}, # {'age': 75, 'name': '巴金'}, # {'age': 80, 'name': '冰心'}] > for au in authors: print(au['name'],au['age']) # 老舍 85 # 老舍 85 # 巴金 75 # 冰心 80 return HttpResponse('ok')
3、values_list('列1',‘列2’)
Entry.objects.values_list("name","age")
相当于:select name,age from...
返回值:QuerySet,是一个有若干元祖所组成的列表:<QuerySet [('王宝强', 33), ('贾乃亮', 35), ('陈羽凡', 38)]>
注意:values_list()可以用在QuerySet(查询结果集)后面比如:all().values_list()
def query_views(request): #查询Author实体中name 和 age的信息 authors = Author.objects.values_list('name','age') print(authors) #< QuerySet[ # ('老舍', 85), # ('老舍', 85), # ('巴金', 75), # ('冰心', 80)] > for au in authors: print(au[0],au[1]) # 老舍 85 # 老舍 85 # 巴金 75 # 冰心 80 return HttpResponse('ok')
4、get()
只查找一条记录是使用,也只能返回一条记录,如果查询返回多条记录的话,则报错
Entry.objects.get(id=1)
相当于:select * from .... where id=1
返回值:Author object
注意:查询多于一条记录或者没有查询到结果都会抛出异常
1、get() returned more than one Author -- it returned 2!(Exception Type: MultipleObjectsReturned)
2、Author matching query does not exist(Exception Type: DoesNotExist)
5、exclude()
作用:对给定条件取反
Entry.objects.exclude(id=1)
相当于:select * from ...where not id=1
返回值:<QuerySet [<Author: Author object>, <Author: Author object>]>
Entry.objects.exclude(id=1,age=33)
相当于:slect * from ...where not(id=1 and age=3)
6、order_by()
Entry.objects.order_by('列名1',‘列名2’...)
指定按照字段进行排序,如果是多个字段,中间用,逗号隔开。默认是按照升序排列,需要降序的话,只需在列名前加”-“符号即可
返回值:QuerySet(查询结果集,是一个封装了若干对象的列表)<QuerySet [<Author: Author object>, <Author: Author object>, <Author: Author object>]>
def query_views(request): #查询Author实体中的数据按照年龄升序排列 authors = Author.objects.order_by('age') print(authors) #< QuerySet[ # < Author: 巴金 >, # < Author: 冰心 >, # < Author: 老舍 >, # < Author: 老舍 >] > for au in authors: print(au.name,au.age) #巴金 75 #冰心 80 #老舍 85 #老舍 85 return HttpResponse('ok')
7、filter()
根据自定义条件查询结果集,可以是一个,也可以是多个,多个的话,条件用,逗号隔开。
如果是多个条件的话,其内部是使用AND来进行条件连接的
返回值:QuerySet(查询结果集,是一个封装了若干对象的列表)
1、使用Entry的属性来作为filter()的条件
示例:
1、Author.objects.filter(id=1)
相当于:select * from author where id=1
2、Author.object.filter(id=1,age=33)
相当于:select * from author where id=1 and age=3
2、使用Field Lookups(查询谓词),完成复杂条件查询
查询谓词:每一个独立的查询谓词就是一个独立的查询条件,所有支持使用查询条件的位置处,都允许适应查询谓词,get(),filter(),exclude()
语法:属性__查询谓词=,双下划线
1、__exact
作用:等值判断
Author.objects.filter(id__exact=1)
select * from author where id=1
查看文档:https://docs.djangoproject.com/en/2.1/ref/models/querysets/
def query_views(request): #查询Author实体中邮箱属性包含字符a authors = Author.objects.filter(email__contains='a') return render(request,'query.html',locals())
2、子查询
inner = Author.objects.filter(name__exact="王宝强").values("age")
authors = Author.objects.filter(age__gt=inner)等价于authors = Author.objects.filter(age__gt=inner[0]['age'])
3、修改操作
1、修改单个对象
1、通过get()获取要修改的实体对象
2、通过实体对象修改属性值
3、在通过实体对象的save()函数,实现保存
auth = Author.objects.get(id=1)
auth.name='宝强.王'
auth.age = 45
auth.save()
2、批量修改(修改查询结果集的值)
调用update()函数即可
Author.objects.all().update(属性=值,....)
说明:不能批量修改id
4、删除操作
1、删除单个对象
obj = Author.objects.get(id=1)
obj.delete()
2、批量删除
Author.objects.all().delete()
5、F()操作 和 Q()操作
1、F()操作
作用:在执行中获取某列的值
语法:F(‘列名’)
from django.db.models import F
Author.objects.all().update(age=F('age')+10)
2、Q()操作
作用:在查询条件中完成或(or)的操作
语法:
from django.db.models import Q
Q(条件1)|Q(条件2)
Author.objects.filter(id=1,age=35)//查询id为1并且age为35
Author.objects.filter(Q(id_exact=1)|Q(age=35),name='王')//查询id为1或者age为35,并且那么为王的
用法二:
q = Q()
q.connector = 'or'
q.children.append(('id_exact',1))
q.children.append(('age',35))
Author.objects.filter(q)//查询id为1或者age为35
6、原生的数据库操作方法
1、查询
函数:raw()
语法:Entry.objects.raw(sql语句)
2、增删该
def sql(requset):
with connection.cursor() as cursor:
sql = 'delete from index_author;'
cursor.execute(sql)
return render(......)
7、转发 与 重定向
1、转发:
转发就是将用户的请求发给另外一个视图进行处理,并将处理结果返回给用户请求的视图,最后响应给用户
表现:地址栏不会发生改变
原因:只有一次请求,所以地址栏就是最初请求的地址
def query_views(request): authors = Author.objects.filter(isActive=True) return render(request,'query.html',locals()) def delete_views(request,id): author = Author.objects.get(id=id) author.isActive=False author.save() return query_views(request)
2、重定向:(推荐使用)
重定向就是告知并响应给用户哪个视图可以处理用户的请求,然后用户在根据响应的地址进行请求,最终得到结果
表现:地址栏会显示最后一次请求的地址
原因:重定向导致浏览器向服务器发送了两次请求
from django.http import HttpResponseRedirect
def query_views(request): authors = Author.objects.filter(isActive=True) return render(request,'query.html',locals()) def delete_views(request,id): author = Author.objects.get(id=id) author.isActive=False author.save() #重定向,参数是要重定向的地址 return HttpResponseRedirect('/02_query/')
from django.shortcuts import redirect
def query_views(request): authors = Author.objects.filter(isActive=True) return render(request,'query.html',locals()) def delete_views(request,id): author = Author.objects.get(id=id) author.isActive=False author.save() #重定向,参数是要重定向的地址 return redirect('/02_query/')
from django.shortcuts import reverse
def query_views(request): authors = Author.objects.filter(isActive=True) return render(request,'query.html',locals()) def delete_views(request,id): author = Author.objects.get(id=id) author.isActive=False author.save() #方向解析,参数是url的别名 url = reverse('query') #重定向,参数是要重定向的地址 return redirect(url)
1、使用后台管理Models
后台登录地址:http://localhost:8000/admin
1、创建后台管理员
./manage.py createsuperuser
Username:
Email Address:可以为空
Password:
Password(agin)
2、基本管理
1、在应用中的admin.py中注册要管理的数据
1、admin.py
作用:注册需要管理的Models,只有在此注册的Model才允许被管理,否则无法管理
2、注册Model
from .models import *
admin.site.register(Entry)
3、修改models.py处理显示内容
后台默认效果可读性不高
def __str__(self):
return self.name//将后台显示Author object(一条记录),修改为该对象的name属性值
在实体类中属性添加verbose_name="姓名"
name = models.CharField(max_length=30,verbose_name="姓名")//显示name字段为姓名
name = models.CharField(max_length=30,verbose_name="aa")//显示name字段为Aa
4、通过内部类Meta实现展现的属性
允许为每个model类设置内部类Meta来设置其展示形式
class Author(models.Model):
....
....
class Meta:
1、db_table:指定该实体类对应到表的名称,该操作必须先同步到数据库
2、verbose_name:定义该实体类在admin中显示的名字(复数形式),会在该属性值的后面加s
3、verbose_name_plural:效果同上,是单数形式
4、ordering:在后台显示数据时的排序规则,取值是一个列表,默认是升序,降序在字段前面加‘-’
ordering = ["uphone"]:按照电话号码升序
ordering = ["-uphone"]:按照电话号码降序
5、ImageField数据类型
在示例对象中添加该数据类型
1、pip install Pillow
2、picture = models.ImageField(
null=True,upload_to='static/upload/usrimg',verbose_name='头像')
null = True:因为数据表中原先有数据,现在添加新字段,需要允许为空
upload_to:表示上传后在项目中的保存路径
verbose_name:在后台显示的名字
2、高级管理
1、在admin.py中创建管理类,实现高级管理功能
1、定义EntryAdmin类,继承自admin.ModelAdmin
2、注册实体类
class AuthorAdmin(admin.ModelAdmin):
pass
admin.site.register(Author, AuthorAdmin)
3、允许在EntryAdmin增加的属性
1、list_display
作用:在显示实体信息的页面上,都显示哪些字段
取值:列表 或 元组
2、list_display_links
作用:定义能够链接到具体实体页面的链接们
取值:由属性名组成的元组或列表
注意:取值必须要出现在list_display中,默认为list_display的第一个字段,
3、list_editable
作用:定义在列表页面中允许被修改的字段
取值:由属性名组成的元组或列表
注意:list_editable中的值不能出现在list_display_links
4、search_fields
作用:添加允许被搜索的字段
取值:由属性组成的元组或列表
5、list_filter
作用:在列表的右侧增加过滤器,实现快速筛选
取值:由属性组成的元组或列表
6、date_hierarchy
作用:在顶部增加一个时间选择器,所以取值必须是DateField 或 DateTieField的列
7、fields
作用:在实体的详细页面中,显示哪些属性,并按照什么样的顺序显示
取值:由属性组成的元组或列表,空列表或元组无效
8、fieldsets
作用:在实体的详细页面中,对属性进行分组
注意:fieldsets 与 fields不能共存
语法:
fieldsets = (
#分组1
(‘当前分组的名称’,{'fields':(属性1,属性2...),‘classes’:(‘collapse’)}),
#分组2
(‘当前分组的名称’,{'fields':(属性1,属性2...),‘classes’:(‘collapse’)}),
......
)
‘classes’:(‘collapse’):表示可以被折叠
9、filter_horizontal(“必须是具有多对多关系的属性”)和 filter_vertical(“必须是具有多对多关系的属性”)
注意:
当两个属性与raw_id_fields共存时,效果将会失效
原图:
filter_horizontal = ('publisher',):
filter_vertical = ("publisher",)
10、raw_id_fields("必须是具有一对多或多对多关系的属性")
class BookAdmin(admin.ModelAdmin): list_display = ('title','publication_date') #book与publisher是多对一的关系, #book域author是多对多的关系 raw_id_fields = ('publisher','author') filter_horizontal = ('author',)#此处域raw_id_fields("author")共存将失效
原图:
raw_id_fields = ('publisher','author'):
2、Django连接查询(关系映射)
1、一对一映射(1:1)
1、什么是一对一
A表中的一条记录只能与B表中的一条记录匹配关联
B表中的一条记录也只能与A表中的一条记录相关联
数据库中的实现:
A表:设计主键
B表:有主键,增加一列(作为外键),并应用A表中的主键值,还得增加一个唯一约束
2、语法:
在关联的两个类的任何一个类中,增加对另外一个类的应用
属性 = models.OneToOneField(Author,null=True)
author = models.OneToOneField(Author,null=True)
+-----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(30) | NO | | NULL | |
| age | int(11) | NO | | NULL | |
| author_id | int(11) | YES | UNI | NULL | |
+-----------+-------------+------+-----+---------+----------------+
| wife | CREATE TABLE `wife` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL,
`age` int(11) NOT NULL,
`author_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `author_id` (`author_id`),
CONSTRAINT `wife_author_id_1672739f_fk_author_id` FOREIGN KEY (`author_id`) REFERENCES `author` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
#编写Wife实体了类,与Author做一对一关系映射 class Wife(models.Model): name = models.CharField(max_length=30,verbose_name="姓名") age = models.IntegerField(verbose_name='年龄') #指定一对一的关联关系,引用自Author实体 author = models.OneToOneField(Author,verbose_name='丈夫') class Meta: db_table='wife'
3、查询
class Wife(models.Model):
name = models.CharField(max_length=30,verbose_name='姓名')
age = models.IntegerField(verbose_name="年龄")
#增加一对一的关系映射
author = models.OneToOneField(Author,null=True,verbose_name='丈夫')
正向查询:通过wife 找 author
#获取id为1的wife的信息
w = Wife.objects.get(id=1)
#在获取wife关联的author
a = w.author
def oto_views(requset): #先获取i的为1的wife的信息 wife = Wife.objects.get(id=1) #再获取对应的author author = wife.author return render(requset,'03_oto.html',locals())
反向查询:通过author 找 wife
a = Author.objects.get(id=1)
w = a.wife
wife 是由Django通过OneToOneField在Author中默认增加的一个属性,在数据库中没有体现
2、一对多映射
1、什么是一对多
A表中的一条数据可以与B表中的任意多条数据匹配
B表中的一条数据只能与A表中的一条数据相关联
2、语法:
在‘多’表中增加外键,对‘一’表表中的主键进行引用
使用外键(Foreign Key)
在‘多’实体中增加:
属性 = models.ForeignKey(实体类)
pub = models.ForeignKey(Publisher,null=True)
+----+----------+------------------+--------+
| id | title | publication_date | pub_id |
+----+----------+------------------+--------+
| 1 | Python | 1990-01-20 | 1 |
| 2 | HTML/CSS | 1992-12-18 | NULL |
| 3 | Django | 2018-08-18 | 3 |
| 4 | HTML/CSS | 1992-02-18 | 2 |
| 5 | JAVA | 2018-08-19 | 3 |
+----+----------+------------------+--------+
| book | CREATE TABLE `book` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(30) NOT NULL,
`publication_date` date NOT NULL,
`publisher_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `book_publisher_id_ac4b162a_fk_publisher_id` (`publisher_id`),#普通索引
CONSTRAINT `book_publisher_id_ac4b162a_fk_publisher_id` FOREIGN KEY (`publisher_id`) REFERENCES `publisher` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 |
3、查询
Book(M)和publisher(1)
class Book(models.Model):
#增加一对多的关系
pub = models.ForeignKey(Publisher,null=True,verbose_name="出版社")
1、正向查询 —— 通过Book 查询 Publisher
book = Book.objects.get(id=1)
publisher = book.pub
def otm_views(request): #先查询id为1的book的信息 book = Book.objects.get(id=1) #在查询book关联publisher publisher=book.publisher return render(request,'04_otm.html',locals())
2、反向查询 - 通过Publisher 查询 Book
Django会通过ForeignKey()向关联的类中增加一个隐式属性:当前类_set,(当前类小写)
p = Publisher.objects.get(id=1)
bookset = p.book_set.all()//book_set是Django在Publisher实体类中添加book_set属性
3、多对多映射
1、什么是多对多
A表中的一条记录可以与B表中的任意多条记录相关联
B表中的一条记录可以与A表中的任意多条记录相关联
2、在数据库中的体现
必须创建第三张表,用于关联涉及到的两张表的数据
3、语法:
在涉及的到两个类中的任意一个类中,都可以对另外一个类的多对多的引用
entry=models.ManyToManyField(Entry)
示例:
创建书籍与作者之间的多对多的引用
可以在书籍实体类中,增加对作者的引用
可以在作者实体类中,增加对书籍的引用
class Book(models.Model):
........
author=models.ManyToManyField(Author)
+-----------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| book_id | int(11) | NO | MUL | NULL | |
| author_id | int(11) | NO | MUL | NULL | |
+-----------+---------+------+-----+---------+----------------+
| book_author | CREATE TABLE `book_author` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`book_id` int(11) NOT NULL,
`author_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `book_author_book_id_author_id_4fda6750_uniq` (`book_id`,`author_id`),#复合唯一索引book_id和author_id不能同时相同
KEY `book_author_author_id_325bf96f_fk_author_id` (`author_id`),#普通索引
CONSTRAINT `book_author_author_id_325bf96f_fk_author_id` FOREIGN KEY (`author_id`) REFERENCES `author` (`id`),
CONSTRAINT `book_author_book_id_19a45511_fk_book_id` FOREIGN KEY (`book_id`) REFERENCES `book` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
4、查询
class Book(models.Model):
........
author=models.ManyToManyField(Author)
正向查询:通过Book找到对应的所有的Author
#查询id为1的书籍的信息
book = Book.objects.get(id=1)
#查询book对应的所有的作者,通过关联属性查询对应的所有信息
authors = book.author.all()
反向查询:通过Author查询所有的Book
Django会通过ManyToManyField()在关联类中增加一个隐式属性
属性名:当前类_set,(类名小写)
#查询id为2的作者信息
author = Author.objects.get(id=2)
#再查询对应的所有的书籍
bookList = author.book_set.all()
def mtm_views(request): #正向查询 book =Book.objects.get(id=2) authors = book.author.all() #反向查询,book_set author = Author.objects.get(id=3) bookList = author.book_set.all() return render(request,'05_mtm.html',locals())
HTTP通信协议
1、什么是HTTP
HTTP:Hyper Text Transfer Protocol(超文本传输协议)
作用:规范了数据是如何打包以及传送的
2、请求消息
由请求起始行,请求消息头,请求主体
请求主题:
post和put两种提交方式会产生请求主体
3、响应消息
由响应起始行,响应消息头,响应主体
1、HttpRequest
1、HttpRequest介绍
HttpRequest,在Django中是对请求对象的封装体现,会封装请求过程中所有的信息,
在Django中,HTTPRequest被封装成了Request被自动传到了视图处理函数中
以双下划线或单下划线开头的不是HTTPRequest协议中的属性或方法,是Django自动添加的
['COOKIES', 'FILES', 'GET', 'META', 'POST', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_encoding', '_get_post', '_get_raw_host', '_get_scheme', '_initialize_handlers', '_load_post_and_files', '_mark_post_parse_error', '_messages', '_post_parse_error', '_read_started', '_set_post', '_stream', '_upload_handlers', 'body', 'build_absolute_uri', 'close', 'content_params', 'content_type', 'csrf_processing_done', 'encoding', 'environ', 'get_full_path', 'get_host', 'get_port', 'get_raw_uri', 'get_signed_cookie', 'is_ajax', 'is_secure', 'method', 'parse_file_upload', 'path', 'path_info', 'read', 'readline', 'readlines', 'resolver_match', 'scheme', 'session', 'upload_handlers', 'user', 'xreadlines']
2、HTTPRequest中的主要内容
1、request.scheme:请求协议
2、request.body:请求主题(只有post和put请求方式时才会有请求主题)
3、request.path:请求路径
4、request.get_host():请求的主机地址或域名
5、request.method:获取请求方法
6、request.GET:封装了GET请求方式提交的数据
7、request.POST:封装了POST请求方式提交的数据
说明:
GET,POST的返回值都是一个字典,字典的值是一个列表,但是通过request.GET['key']取出的一个字符串,(为什么?)
答案:Django中通过重写__getitem__方法实现的
''' QueryDict.__getitem__(key) 返回给出的 key 的值。如果key 具有多个值,__getitem__() 返回最后(最新)的值。如果 key 不存在, 则引发django.utils.datastructures.MultiValueDictKeyError。( 它是Python 标准KeyError 的一个子类,所以你仍然可以坚持捕获KeyError。) 总结:Django中通过重写__getitem__方法实现的 ''' class MyDict(): def __init__(self,iterable): self.data = iterable def __getitem__(self, item): return self.data[item][-1] dict = { 'name':['xdl','gj'], 'age':[25] } myDict = MyDict(dict) print(type(myDict))#<class '__main__.MyDict'> print(myDict['name'])#gj
8、request.COOKIES:封装了cookie的数据
9、request.META:封装了请求的元数据
request.META["HTTP_REFERER"]:封装了请求的源地址
def requset_views(request): #request,类型就是HTTPRequest #request,封装的是所有与请求相关的内容 #print(dir(request)) #请求协议(方案),http scheme = request.scheme #请求主体 body = request.body #请求资源的具体路径,根相对路径,/01_requset/ path = request.path #请求的主机地址或域名,127.0.0.1:8000 host = request.get_host() #请求方式,GET method = request.method #get方式请求的数据,得到的是一个字典,<QueryDict: {}> get = request.GET #post方式请求数据,<QueryDict: {}> post = request.POST #cookie中的数据,返回的是一个字典 # {'csrftoken': 'w1TDCKqZakTz9IKn94luPeFjefTsGdDnRqGxzXdGJ5yNOQaWfeJC5MbUw0KRPWzo', # 'sessionid': '702s33knczrluqmeh15m9rvbasptd39i'} cookies = request.COOKIES #请求元数据,返回的是一个字典 meta = request.META return render(request,'01_request.html',locals())
3、获取请求提交的数据
1、get请求方式
request.GET["名称"]
1、使用表单提交数据
<form></form>
2、通过超链接拼接查询字符串
<a href="地址?参数1&参数2..."></a>
此种方式,属于http标准,任何语言都可以使用
Django中通过URL传递参数
url(r'01_test/(\d+)',test_views)
此种方式,非http标准的,属于Django标准
2、post请求方式
request.POST["名称"]
CSRF:Cross-Site Request Forgery(伪装):跨站点伪装攻击
解决方案:
1、取消CSRF的验证
删除settings.py中MIDDLEWARE中的'CsrfViewMiddleware'中间件
2、开放验证权限,无需验证,直接进入
在视图处理函数之上增加一个装饰器@crsf_protect
需要引包:from django.views.decorators.csrf import csrf_protect
3、必须要通过验证后才可以请求
在模板中<form>下第一行增加:{% scrf_token %}
在表单里面会出现一个隐藏域,value是一个可变的字符串
<input type='hidden' name='csrfmiddlewaretoken' value='hE2u8FkzeReMYlfzj8CUHPUwEVqURdc6C3Po5S7gNCT0DtF8pi02Xnq7WGhj0W87' />
4、Django中的表单处理
表单页面的get和post请求是由同一个视图(views)处理的,通过request.method判断
def login_views(request): if request.method == 'GET': return render(request,'03_login.html') else: return HttpResponse('用户名:%s,密码:%s'%(request.POST['uname'],request.POST['upwd']))
2、使用forms模块处理表单
1、forms模块的作用
通过forms模块,允许将表单与class相结合,允许通过class生成表单
2、使用forms模块
1、创建forms.py文件(在应用中创建)
2、导入forms
form django import forms
3、创建class,必须继承自forms.Form一个class对应成一个表单
class LoginForm(forms.Form):
pass
4、在class中创建属性(不用创建提交按钮)
一个属性对应一个表单控件
# 表示评论内容的表单控件 class RemarkForm(forms.Form): # 评论标题-文本框 subject = forms.CharField(label='标题') # Email - type=‘Email’ email = forms.EmailField(label="邮箱") #评论内容-文本域 message = forms.CharField(label="内容",widget=forms.Textarea)#widget=forms.PasswordInput表示密码框 #好评,中平,差评-select topic_choices = ( (1,"好评"), (2,"中评"), (3,"差评")) topic = forms.ChoiceField(label='评价',choices=topic_choices) #是否保存 isSaved = forms.BooleanField(label='是否保存')
3、在模板中解析form对象
1、注意
1、需要自定义<form></form>
2、需要自定义按钮<input type='submit'>
2、处理方法
在视图中创建forms.Form的对象,并发送到模板中
示例:
form = RemarkForm()
return render(request,'xx.html',locals())
1、手动解析
在模板中:
{% for field in form %}
{{field.lable}}:表示控件前面显示的文本
{{field}}:表示的就是控件
{% endfor %}
2、自动解析
1、{{form.as_p}}
将form对象中的每个属性使用p标记包裹起来,再显示在网页上
2、{{form.as_ul}}
将form对象中的每个属性使用li标签包裹起来,再显示在网页上
注意:必须手动提供<ol></ol>或<ul></ul>
3、{{form.as_table}}
将form对象中的每个属性使用tr标签包裹起来,再显示在网页上
注意:必须手动提供<table></table>
4、在视图中,通过forms.Form自动获取表单数据
1、通过forms.Form的构造函数,接收post数据
form = XXXForm(requset.POST)
2、需要让form通过验证后,再取值(必须要验证)
form.is_valid()
返回True:提交的数据已经通过验证,允许接收表单提交的数据
返回False:提交的数据验证未通过,无法取值
3、获取表单中的数据
通过form.cleaned_data(字典)接收提交的数据
def register_views(request): if request.method =="GET": form = RegisterForm() return render(request,'06_register.html',locals()) else: form = RegisterForm(request.POST) if form.is_valid(): cd = form.cleaned_data try: User.objects.get(uname=cd['uname']) return HttpResponse('用户名已存在') except ObjectDoesNotExist: User.objects.create(**cd) return HttpResponse("注册成功")
1、forms模块
1、forms的高级处理
将Models和Forms结合到一起使用
将Forms中的类和Models中的类关联到一起,实现属性的共享
1、在forms.py中创建class,继承自forms.ModelForm
2、创建内部类:Meta,关联Form和Model
属性:
1、model:指定要关联的Model类
2、fields:指定从Model中取哪些字段生成控件
1、取值:"__all__",全部的属性都要生成控件
2、取值:列表或元祖,声明允许生成控件的属性名称
3、labels:指定每个属性所关联的label,取值为字典
labels={
'属性名':"label文本",
'属性名':"label文本",
.........
}
#创建class表示登录的表单,要关联Users实体类 class UserLoginForm(forms.ModelForm): class Meta: #指定关联的model model = User #指定要生成的控件字段 fields = ["uname","upwd"] #指定每个控件对应的label labels={ "uname":"用户名", "upwd":"密码", }
2、内置小部件
1、什么是小部件
小部件(widget),表示的是生成到页面中的控件的类型以及其他的html属性
2、常用的小部件
1、TextInput:type=“text”
2、NumberInput:type=“number”
3、PasswordInput:type=“password”
4、EmailInput:type=“email”
5、URLInput:type=”url“
6、HiddenInput:type=“hidden”
7、CheckboxInput:type=“checkbox”
8、Textarea:<Textarea></Textarea>
9、Select:<Select></Select>
3、小部件的使用
1、继承自forms.Form
1、基本版
只指定控件的类型
属性=forms.CharField(
lable="标签",
widget=forms.小部件的类型
)
示例:
upwd=forms.CharField(label=“密码”,widget=forms.PasswordInput)
2、高级版
指定控件类型之外还允许设置html属性
属性=forms.CharField(
label="标签",
widget=forms.小部件类型(
attrs = {
"html属性名":"属性值",
"html属性名":"属性值",
......
}
)
)
class WidgetForm(forms.Form): uname = forms.CharField( label="用户名称", widget=forms.TextInput( attrs={ 'name':'user_name', 'placeholder':"请输入用户名称", 'class':'form-control', } ) ) upwd = forms.CharField( label="用户密码", widget=forms.PasswordInput( attrs={ 'name':'user_pwd', 'placeholder':'请输入密码', 'class':'form-control', } ) )
2、继承自forms.ModelForm
class Widget2Form(forms.ModelForm):
class Meta:
model = User
fields= "__all__"
labels={
"属性1":"标签1",
"属性2":"标签2",
....
}
widgets={
"属性1":forms.小部件类型(attrs={}),
"属性2":forms.小部件类型(attrs={}),
........
}
class Widget2Form(forms.ModelForm): class Meta: model=User fields=("uname","upwd") labels={ "uname":'用户名称', "upwd":"用户密码", } widgets={ 'uname':forms.TextInput( attrs={ "placeholder":'请输入用户名' } ), 'upwd':forms.PasswordInput( attrs={ 'placeholder':"请输入密码" } ) }
2、cookies
1、什么是cookies
cookies是一种数据的存储技术,只能保存字符串
允许将一段文本保存在客户端上(浏览器)的一种技术,并可以长时间保存
2、cookies的使用场合
1、记住密码
2、保存搜索关键词
3、在Django中使用cookies
1、设置cookies的值(将数据保存客户端)
语法:
响应对象.set_cookie(key,value,[expires])
key:cookie的名字
value:cookie的值
expires:保存时间,以s为单位,如果不给该参数,则浏览器关闭,cookie失效
示例:
响应对象.set_cookie('uname','xdl',60*60*24*366)
响应对象:HttpResponse,render,HttpResponseRedirect,redirect
1、不使用模板(HttpResponse)
resp = HttpResponse("给客户端的一句话")
resp.set_cookie('key','value',expires)
return resp
2、使用模板(render)
resp = render(reuqest,'xxx.html',locals())
resp.set_cookie('key','value',expires)
return resp
3、重定向(HttpResponseRedirect/redirect)
resp = HttpResponseRedirect('/地址/')
resp.set_cookie('key','value',expires)
return resp
2、获取cookies的值(将数据从客户端中获取出来)
通过request.COOKITES(返回的是一个字典,通过键值可以取值)
获取当前访问站点下所有的cookies的信息
3、删除cookie
响应对象.delete_cookie('key')
3、session-会话
1、什么是session
session(会话),实际上就是在服务器上为每个浏览器开辟的一段空间,用于保存相关的请求信息
2、session的使用场合
session也是为了存储数据而存在的
通常会把服务器经常要用到的数据保存进去
3、Django中使用session
1、设置session的值
request.session['key']=value
request.session.set_expiry(time):
设置session的过期时间,如果设置为0的话,则表示关闭浏览器session就失效
2、获取session的值
value = request.session['key']
value = request.session.get('key')
3、删除session的值
del request.session['key']
4、在setting.py中,有关session的设置
1、SESSION_COOKIE_AGE
作用:设置sessionID在cookies中的保存时长,默认为15天
示例:
SESSION_COOKIE_AGE=60*6024
2、SESSION_EXPIRE_AT_BROWSER_CLOSE(建议使用)
作用:设置关闭浏览器时清除服务器上对象的session空间
示例:
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
cookie 存取中文
def setCookie_views(request): uname = '张三丰' #将uname转化为unicode uname = json.dumps(uname) resp = HttpResponse('set cookie ok') resp.set_cookie('name',uname) return resp def getCookie_views(requset): uname = requset.COOKIES['name'] #将unicode码转换为中文 uname = json.loads(uname) return HttpResponse(uname)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script type="text/javascript" src="/static/js/jquery-1.11.3.js"></script> <script type="text/javascript" src="/static/js/jquery.cookie.js"></script> <script> $(function(){ var uname = $.cookie('name') //将Unicode码转换为中文 uname = JSON.parse(uname) console.log(uname) }); </script> </body> </html>
上传图片
前段页面:
上传图片
<form action="" method="post" enctype="multipart/form-data"> {% csrf_token %} <input type="file" name="pic" id="pic"> <button type="submit">提交</button> </form>
访问图片:通过views函数返回这个对象集合,然后在前端循环获取图片路径.url
{% for show in p %} {% if show.pic %} <img src="{{ show.pic.url }}"> {% endif %} {% endfor %}
后端配置:
配置settings文件
MEDIA_ROOT = os.path.join(BASE_DIR,'media').replace('\\','/') MEDIA_URL = '/media/'
配置urls文件,主路由文件
from django.conf.urls import url, include from django.contrib import admin from sale import views from django.conf import settings from django.conf.urls.static import static urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^$',views.index,name='index'), url(r'^userinfo/',include('userinfo.urls')), ]+ static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
views.py视图
def salecar(request): new_a = Aid()#实体类 pic = request.FILES.get('pic') new_a.pic = pic new_a.save() return render(request,'infomessage.html')