M全拼为Model,主要封装对数据库层的访问,对数据库中的数据进行增、删、改、查操作
V全拼为View,用于封装结果,生成页面展示的html内容
C全拼为Controller,用于接收请求,处理业务逻辑,与Model和View交互,返回结果
M全拼为Model,与MVC中的M功能相同,负责和数据库交互,进行数据处理
V全拼为View,与MVC中的C功能相同,接收请求,进行业务处理,返回应答
T全拼为Template,与MVC中的V功能相同,负责封装构造要返回的html
为什么要使用虚拟环境?
如果在一台机器上,想开发不同的项目,这些项目依赖的同一个包的版本不同,其他项目就无法正常运行了,所有我们要用到虚拟环境,虚拟环境就是对真实Python环境的复制,通过建立多个虚拟环境,在不同的虚拟环境中开发项目就实现了项目之间的间隔
创建虚拟环境
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
创建第一个项目
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>
<h2>{{title}}</h2>
{%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("<h2>设置Cookie,请查看响应报文头</h2>")
response.set_cookie('h2', '你好')
return response
读取Cookie
def cookie_get(request):
response = HttpResponse("读取Cookie,数据如下:<br>")
if 'h2' in request.COOKIES:
response.write('<h2>' + request.COOKIES['h2'] + '</h2>')
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)
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。