M全拼为Model,主要封装对数据库层的访问,对数据库中的数据进行增、删、改、查操做javascript
V全拼为View,用于封装结果,生成页面展现的html内容css
C全拼为Controller,用于接收请求,处理业务逻辑,与Model和View交互,返回结果html
M全拼为Model,与MVC中的M功能相同,负责和数据库交互,进行数据处理java
V全拼为View,与MVC中的C功能相同,接收请求,进行业务处理,返回应答python
T全拼为Template,与MVC中的V功能相同,负责封装构造要返回的htmlmysql
为何要使用虚拟环境?jquery
若是在一台机器上,想开发不一样的项目,这些项目依赖的同一个包的版本不一样,其余项目就没法正常运行了,全部咱们要用到虚拟环境,虚拟环境就是对真实Python环境的复制,经过创建多个虚拟环境,在不一样的虚拟环境中开发项目就实现了项目之间的间隔git
建立虚拟环境正则表达式
pip3 install virtualenv # 安装虚拟环境 pip3 install virtualenvwrapper-win # 安装虚拟环境扩展包 mkvirtualenv 虚拟环境名称 # 建立虚拟环境 deactivate # 退出虚拟环境 workon # 直接输入workon查看已建立的虚拟环境,后面接虚拟环境名称进入该虚拟环境 rmvirtualenv 虚拟环境名称 # 删除虚拟环境 pip list # 查看该虚拟环境中安装的包 pip install # 虚拟环境包管理 pip install django==1.11.11 # 安装django1.11.11
建立第一个项目sql
django-admin startproject mysite;
项目默认目录
manage.py # 项目管理文件,经过它管理项目 与项目同名的目录,此处为mysite _init_.py # 一个空文件,做用是这个目录test能够被看成包使用 settings.py # 项目的总体配置文件 urls.py # 项目的URL配置文件 wsgi.py # 项目与WSGI兼容的Web服务器入口
建立应用
python manage.py startapp app01;
应用目录结构
__init__.py # 一个空文件,表示当前目录能够看成一个python包使用 tests.py # 开发测试用例,在实际开发中会有专门的测试人员 models.py # 数据库操做相关 views.py # 接收浏览器请求,进行处理,返回页面相关 admin.py # 站点管理 migrations:
安装应用
# mysite/setting.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', ]
开发服务器
python manage.py runserver ip:端口
定义模型类
# app01/models.py from django.db import models class BookInfo(models.Model): """图书表""" btitle = models.CharField(max_length=20) bpub_date = models.DateField() class HeroInfo(models.Model): """英雄表""" hname = models.CharField(max_length=20) hgender = models.BooleanField() hcomment = models.CharField(max_length=100) hbook = models.ForeignKey(BookInfo)
迁移
python manage makemigration # 生成迁移文件 python manage migrate # 执行迁移
数据操做
# 进入项目并引入模块 python manage.py shell from datetime import date from booktest.models import BookInfo,HeroInfo # 增删改查 BookInfo.objects.create(title="射雕英雄传",bpub_date=date(2018,10,4)) BookInfo.objects.filter(id=1).delete() BookInfo.objects.filter(id=1).update(title='神雕侠侣') BookInfo.objects.filter.all() # 对象关联操做 HeroInfo.objects.create(hname='a1',hgender=False,hcomment='he is a boy',hbook=BookInfo.objects.get(id=1)) # 得到关联集合 BookInfo.objects.get(id=1).heroinfo_set.all()
管理页面本地化
# mysite/setting.py LANGUAGE_CODE = 'zh-hans' #使用中国语言 TIME_ZONE = 'Asia/Shanghai' #使用中国上海时间
建立管理员
python manage.py createsuperuser
注册模型类
# app01/admin.py from django.contrib import admin from app01.models import BookInfo,HeroInfo admin.site.register(BookInfo) admin.site.register(HeroInfo)
自定义管理界面
# app01/admin.py,list_display表示要显示的字段 from django.contrib import admin from booktest.models import BookInfo,HeroInfo class BookInfoAdmin(admin.ModelAdmin): list_display = ['id', 'btitle', 'bpub_date'] class HeroInfoAdmin(admin.ModelAdmin): list_display = ['id', 'hname','hgender','hcomment'] admin.site.register(BookInfo,BookInfoAdmin) admin.site.register(HeroInfo,HeroInfoAdmin)
定义视图
# app01/views.py from django.http import HttpResponse def index(request): return HttpResponse("index")
配置URLconf
请求者在浏览器中输入url,请求到网站后,获取url信息,而后在URL.conf逐条匹配,若是匹配成功返回相应的视图函数,若是全部URLconf都没有匹配成功,返回404错误 # app01/views.py from django.conf.urls import include, url from django.contrib import admin urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^', include('app01.urls')), ] # mysite/urls.py from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^$', views.index), ]
建立模板
# mysite/setting.py 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', ], }, }, ]
定义模板
# templtes/app01/index.html <html> <head> <title>图书列表</title> </head> <body> <h1>{{title}}</h1> {%for i in list%} {{i}}<br> {%endfor%} </body> </html>
视图调用模板
# app01/views.py from django.shortcuts import render def index(request): context={'title':'图书列表','list':range(10)} return render(request,'app01/index.html',context)
负责和数据库交互,进行数据处理
什么是orm?
对象关系映射,是随着面向对象思想发展而产生的,是一种程序技术,用于实现面向对象编程语言里不一样类型系统的数据之间的转换,面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的,两套理论存在显著的区别,为了解决这个不匹配的现象,对象关系映射技术应运而生
使用MySQL
# mysite/setting.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'python', #数据库名字, 'USER': 'root', #数据库登陆用户名 'PASSWORD': '123456', #数据库登陆密码 'HOST': 'localhost', #数据库所在主机 'PORT': '3306', #数据库端口 } } # mysite/__init__.py import pymysql pymysql.install_as_MySQLdb()
字段类型
字段约束
查询
exact 表示判等 list = BookInfo.objects.filter(id__exact=1) list = BookInfo.objects.filter(id=1)
模糊查询
contains 是否包含 list = BookInfo.objects.filter(btitle__contains='传') list = BookInfo.objects.filter(btitle__icontains='传') # 不区分大小写
startswith 以指定字符开头 list = BookInfo.objects.filter(btitle__startswith='神') list = BookInfo.objects.filter(btitle__istartswith='神') # 不区分大小写
endswithch 以指定字符结尾 list = BookInfo.objects.filter(btitle__endswitch='侣') list = BookInfo.objects.filter(btitle__iendswitch='侣') # 不区分大小写
空查询
isnull 是否为空 list = BookInfo.objects.filter(btitle__isnull=False)
范围查询
in 是否包含在范围内 list = BookInfo.objects.filter(id__in=[1, 3, 5])
比较查询
gt: 大于 gte: 大于等于 lt: 小于 lte:小于等于 list = BookInfo.objects.filter(id__gt=3)
不等于查询
exclude() 不等于运算符 list = BookInfo.objects.exclude(id=3)
日期查询
year、month、day、week_day、hour、minute、second list = BookInfo.objects.filter(bpub_date__year=1980)
F对象
比较一个对象中的两个属性 list = BookInfo.objects.filter(bread__gt=F('bcomment') * 2)
Q对象
多个过滤器逐个调用表示逻辑与关系,同sql语句中where部分的and关键字 list=BookInfo.objects.filter(bread__gt=20).filter(id__lt=3) 若是想实现逻辑或的功能,就要使用到Q对象查询,Q对象可使用&、|链接,&表示逻辑与,|表示逻辑或,~表示not list = BookInfo.objects.filter(Q(bread__gt=20) | Q(pk__lt=3))
聚合查询
使用aggregate()过滤器调用聚合函数,聚合函数包括:Avg,Count,Max,Min,Sum list = BookInfo.objects.count()
查询集表示从数据库中查询到的对象集合
返回查询集的过滤器
返回单个值的过滤器
判断一个查询集中是否有数据
两个特性
限制结果集
能够对结果集进行切片操做,等同于数据库中的分页操做,可是不支持负数 list = BookInfo.objects.all()[0:2]
一对多
一本图书中能够对应多个英雄,因此图书和英雄是一对多的关系 class BookInfo(models.Model): btitle = models.CharField(max_length=20) bpub_date = models.DateField() bread = models.IntegerField(default=0) bcomment = models.IntegerField(default=0) isDelete = models.BooleanField(default=False) class HeroInfo(models.Model): hname = models.CharField(max_length=20) hgender = models.BooleanField(default=True) isDelete = models.BooleanField(default=False) hcomment = models.CharField(max_length=200) hbook = models.ForeignKey('BookInfo')
多对多
一个类别中多条新闻,一条新闻也能够分为不一样的类别,因此新闻是多对多关系 class TypeInfo(models.Model): tname = models.CharField(max_length=20) class NewsInfo(models.Model): ntitle = models.CharField(max_length=60) ncontent = models.TextField() npub_date = models.DateTimeField(auto_now_add=True) ntype = models.ManyToManyField('TypeInfo')
一端的对象.多端的类名_set b = BookInfo.objects.get(id=1) b.HeroInfo_set.all()
多端的模型对象.多端模型类的类关系字段 h = HeroInfo.objects.get(id=1) h.hbook
多对应的模型类对象.关联类属性_id h = HeroInfo.objects.get(id=1) h.book_id
语法: 关联模型类名小写__属性名__条件运算符=值 list = BookInfo.objects.filter(heroinfo__hcontent__contains='八')
语法: 一模型类关联属性名__一模型类属性名__条件运算符=值 list = HeroInfo.objects.filter(hbook__btitle='天龙八部')
视图负责接受Web请求HttpRequest,进行逻辑处理,返回Web响应HttpResponse给请求者
位置参数
url(r'^delete(\d+)/$',views.show_arg),
关键字参数
url(r'^delete(?P<id1>\d+)/$',views.show_arg),
内置错误视图,若是想看到错误视图而不是调试信息的话,须要修改setting文件的DEBUG选项
# mysite/setting.py DEBUG = False ALLOWED_HOSTS = ['*', ]
属性
方法
set_cookie:设置Cookie信息
某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据,Cookie是由服务器端生成,发送给User-Agent(通常是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器,Cookie名称和值能够由服务器端开发本身定义,这样服务器能够知道该用户是不是合法用户以及是否须要从新登陆等,服务器能够利用Cookies包含信息的任意性来筛选并常常性维护这些信息,以判断在HTTP传输中的状态
Cookie特色
设置Cookie
def cookie_set(request): response = HttpResponse("<h1>设置Cookie,请查看响应报文头</h1>") response.set_cookie('h1', '你好') return response
读取Cookie
def cookie_get(request): response = HttpResponse("读取Cookie,数据以下:<br>") if 'h1' in request.COOKIES: response.write('<h1>' + request.COOKIES['h1'] + '</h1>') return response
对于敏感、重要的信息,建议要储在服务器端,不能存储在浏览器中,如用户名、余额、等级、验证码等信息
禁用Session中间件
存储方式
存储在数据库中,以下设置能够写,也能够不写,这是默认存储方式 SESSION_ENGINE='django.contrib.sessions.backends.db' 存储在缓存中:存储在本机内存中,若是丢失则不能找回,比数据库的方式读写更快 SESSION_ENGINE='django.contrib.sessions.backends.cache' 混合存储:优先从本机内存中存取,若是没有则从数据库中存取 SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
依赖于Cookie
在使用Session后,会在Cookie中存储一个sessionid的数据,每次请求时浏览器都会将这个数据发给服务器,服务器在接收到sessionid后,会根据这个值找出这个请求者的Session
对象及方法
以键值对的格式写session request.session['键']=值 根据键读取值 request.session.get('键',默认值) 清除全部session,在存储中删除值部分 request.session.clear() 清除session数据,在存储中删除session的整条数据 request.session.flush() 删除session中的指定键及值,在存储中只删除某个键及对应的值 del request.session['键'] 设置会话的超时时间,若是没有指定过时时间则两个星期后过时 request.session.set_expiry(value) 若是value是一个整数,会话将在value秒没有活动后过时,若是value为0,那么用户会话的Cookie将在用户的浏览器关闭时过时,若是value为None,那么会话永不过时
负责封装构造要返回的html
语法:{{变量}}
解析顺序:
for
{% for item in book_list %} 循环逻辑 {{forloop.counter}}表示当前是第几回循环,从1开始 {%empty%}列表为空执行此逻辑 {% end for %}
if
{%if ...%} 逻辑1 {%elif ...%} 逻辑2 {%else%} 逻辑3 {%endif%}
语法:变量|过滤器:参数
data|default:'默认值'
在应用中建立templatetags目录
在该目录下建立filters.py文件
#导入Library类 from django.template import Library #建立一个Library类对象 register=Library() #使用装饰器进行注册 @register.filter #定义求余函数mod,将value对2求余 def mod(value): return value%2 == 0
使用load标签引入模块
{%load filters%}
若是发如今多个模板中某些内容相同,那就应该把这段内容定义到父模板中
标签block:用于在父模板中预留区域,留给子模板填充差别性的内容,名字不能相同
{%block 名称%} 预留区域,能够编写默认内容,也能够没有默认内容 {%endblock 名称%}
标签extends:继承,写在子模板文件的第一行
{% extends "父模板路径"%} {%block 名称%} 实际填充内容 {{block.super}}用于获取父模板中block的内容 {%endblock 名称%}
跨站请求伪造,CSRF指***者盗用了你的身份,以你的名义发送恶意请求
CSRF可以作的事情:以你名义发送邮件,发消息,盗取你的帐号,甚至于购买商品,虚拟货币转帐......
形成的问题:我的隐私泄露以及财产安全
若是想防止CSRF,首先是重要的信息传递都采用POST方式而不是GET方式
防止CSRF
保护原理
加入csrf_token这个标签后,会想客户端浏览器写入一条cookie,还会在表单中加入一个隐藏域,里面存放有一个value值,而后提交数据的时候,会将这两个值提交到服务器进行校验,若是value值cookie值相同,正常执行业务逻辑,不然,返回403错误
新用户注册,为了防止请求过多,能够加入验证码功能,若是验证码错误,不须要执行后续操做,减轻服务器的压力
pip3 install Pillow
from PIL import Image, ImageDraw, ImageFont from django.utils.six import BytesIO ... def verify_code(request): #引入随机函数模块 import random #定义变量,用于画面的背景色、宽、高 bgcolor = (random.randrange(20, 100), random.randrange( 20, 100), 255) width = 100 height = 25 #建立画面对象 im = Image.new('RGB', (width, height), bgcolor) #建立画笔对象 draw = ImageDraw.Draw(im) #调用画笔的point()函数绘制噪点 for i in range(0, 100): xy = (random.randrange(0, width), random.randrange(0, height)) fill = (random.randrange(0, 255), 255, random.randrange(0, 255)) draw.point(xy, fill=fill) #定义验证码的备选值 str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0' #随机选取4个值做为验证码 rand_str = '' for i in range(0, 4): rand_str += str1[random.randrange(0, len(str1))] #构造字体对象,ubuntu的字体路径为“/usr/share/fonts/truetype/freefont” font = ImageFont.truetype('FreeMono.ttf', 23) #构造字体颜色 fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255)) #绘制4个字 draw.text((5, 2), rand_str[0], font=font, fill=fontcolor) draw.text((25, 2), rand_str[1], font=font, fill=fontcolor) draw.text((50, 2), rand_str[2], font=font, fill=fontcolor) draw.text((75, 2), rand_str[3], font=font, fill=fontcolor) #释放画笔 del draw #存入session,用于作进一步验证 request.session['verifycode'] = rand_str #内存文件操做 buf = BytesIO() #将图片保存在内存中,文件类型为png im.save(buf, 'png') #将内存中的图片数据返回给客户端,MIME类型为图片png return HttpResponse(buf.getvalue(), 'image/png')
url(r'^verify_code/$', views.verify_code),
def verify_show(request): return render(request,'app01/verify_show.html')
url(r'^verify_show/$', views.verify_show),
<html> <head> <title>验证码</title> </head> <body> <form method="post" action="/verify_yz/"> {%csrf_token%} <input type="text" name="yzm"> <img id="yzm" src="/verify_code/"/> <span id="change">看不清,换一个</span> <br> <input type="submit" value="提交"> </form> </body> </html>
def verify_yz(request): yzm=request.POST.get('yzm') verifycode=request.session['verifycode'] response=HttpResponse('no') if yzm==verifycode: response=HttpResponse('ok') return response
url(r'^verify_yz/$', views.verify_yz),
<script type="text/javascript" src="/static/jquery-1.12.4.min.js"></script> <script type="text/javascript"> $(function(){ $('#change').css('cursor','pointer').click(function() { $('#yzm').attr('src',$('#yzm').attr('src')+1) }); }); </script> ... <img id="yzm" src="/verify_code/?1"/> <span id="change">看不清,换一个</span>
url(r'^',include('app01.urls',namespace='app01')),
url(r'^fan2/$', views.fan2,name='fan2'),
<html> <head> <title>反向解析</title> </head> <body> 普通连接:<a href="/fan2/">fan2</a> <hr> 反向解析:<a href="{%url 'booktest:fan2'%}">fan2</a> </body> </html>
url(r'^fan_show/$', views.fan2,name='fan2'),
from django.shortcuts import redirect from django.core.urlresolvers import reverse return redirect(reverse('app01:fan2'))
总结:在定义url时,须要为include定义namespace属性,为url定义name属性,使用时,在模板中使用url标签,在视图中使用reverse函数,根据正则表达式动态生成地址,减轻后期维护成本
内容发布的部分由网站的管理员负责查看、添加、修改、删除数据,开发这些重复的功能是一件单调乏味、缺少创造力的工做,为此,Django可以根据定义的模型类自动地生成管理模块
页大小,每页显示多少条数据
list_per_page=100
操做选项的位置
actions_on_top=True 顶部显示的属性,True为显示,默认为True,False即为不显示 actions_on_bottom=True 同上,只不过是底部显示的属性
字段排序
admin_order_field=[字段1,字段2]
列标题
short_description='列标题'
侧边栏过滤器
list_filter=[]
搜索框
search_fields=[]
中文标题
在模型类的字段为其指定verbose_name
分组显示
fieldset=( ('组1标题',{'fields':('字段1','字段2')}), ('组2标题',{'fields':('字段3','字段4')}), )
将模型的类型定义成ImageField字段
class Pic(models.Model): pic = models.ImageField(upload_to='app01/')
迁移
python managee.py makemigrations python manage.py migrate
设置图片保存位置
MEDIA_ROOT=os.path.join(BASE_DIR,"static/media") 而且在static建立media目录,在meida目录下建立应用名称的目录,此为app01
在admin中注册该模型类
admin.site.register(Pic)