MVC框架的核心思想是:解耦,让不一样的代码块之间下降耦合,加强代码的可扩展性和可移植性,实现向后兼容javascript
在ORM框架中,它帮咱们把类和数据表进行了一个映射,可让咱们经过类和类对象就能操做它所对应的表格中的数据。ORM框架还有一个功能,它能够根据咱们设计的类自动帮咱们生成数据库中的表格,省去了咱们本身建表的过程css
说明:不须要定义主键列,在生成时会自动添加,而且值为自动增加html
数据表的默认名称为:<app_name>_<model_name>前端
一对多的关系(ForeignKey)应定义在多的那个类中java
登陆后台管理后,默认没有咱们建立的应用中定义的模型类,须要在本身应用中的admin.py文件中注册,才能够在后台管理中看到,并进行增删改查操做python
Django提供了自定义管理页面的功能,好比列表页要显示哪些值mysql
1 from django.contrib import admin 2 from booktest.models import BookInfo,HeroInfo 3 4 class BookInfoAdmin(admin.ModelAdmin): 5 list_display = ['id', 'btitle', 'bpub_date'] 6 class HeroInfoAdmin(admin.ModelAdmin): 7 list_display = ['id', 'hname','hgender','hcomment'] 8 9 admin.site.register(BookInfo,BookInfoAdmin) 10 admin.site.register(HeroInfo,HeroInfoAdmin)
/settings.py文件,找到DATABASES项,默认使用SQLite3数据库jquery
修改成使用MySQL数据库,代码以下: 将引擎改成mysql,提供链接的主机HOST、端口PORT、数据库名NAME、用户名USER、密码PASSWORD。
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'test2', #数据库名字, 'USER': 'root', #数据库登陆用户名 'PASSWORD': 'mysql', #数据库登陆密码 'HOST': 'localhost', #数据库所在主机 'PORT': '3306', #数据库端口 } }
注意:数据库test2 Django框架不会自动生成,须要咱们本身进入mysql数据库去建立git
使用时须要引入django.db.models包,字段类型以下:正则表达式
AutoField:自动增加的IntegerField,一般不用指定,不指定时Django会自动建立属性名为id的自动增加属性。 BooleanField:布尔字段,值为True或False。 NullBooleanField:支持Null、True、False三种值。 CharField(max_length=字符长度):字符串。 参数max_length表示最大字符个数。 TextField:大文本字段,通常超过4000个字符时使用。 IntegerField:整数。 DecimalField(max_digits=None, decimal_places=None):十进制浮点数。 参数max_digits表示总位数。 参数decimal_places表示小数位数。 FloatField:浮点数。 DateField[auto_now=False, auto_now_add=False]):日期。 参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它老是使用当前日期,默认为false。 参数auto_now_add表示当对象第一次被建立时自动设置当前时间,用于建立的时间戳,它老是使用当前日期,默认为false。 参数auto_now_add和auto_now是相互排斥的,组合将会发生错误。 TimeField:时间,参数同DateField。 DateTimeField:日期时间,参数同DateField。 FileField:上传文件字段。 ImageField:继承于FileField,对上传的内容进行校验,确保是有效的图片。
经过选项实现对字段的约束,选项以下:
null:若是为True,表示容许为空,默认值是False。 blank:若是为True,则该字段容许为空白,默认值是False。 对比:null是数据库范畴的概念,blank是表单验证范畴的。 db_column:字段的名称,若是未指定,则使用属性的名称。 db_index:若值为True, 则在表中会为此字段建立索引,默认值是False。 default:默认值。 primary_key:若为True,则该字段会成为模型的主键字段,默认值是False,通常做为AutoField的选项使用。 unique:若是为True, 这个字段在表中必须有惟一值,默认值是False。
1 list=BookInfo.objects.filter(id__exact=1) 2 可简写为: 3 list=BookInfo.objects.filter(id=1)
说明:若是要包含%无需转义,直接写便可
list = BookInfo.objects.filter(btitle__contains='传')
1 list = BookInfo.objects.filter(btitle__endswith='部')
以上运算符都区分大小写,在这些运算符前加上i表示不区分大小写,如iexact、icontains、istartswith、iendswith
list = BookInfo.objects.filter(btitle__isnull=False)
1 list = BookInfo.objects.filter(id__in=[1, 3, 5])
list = BookInfo.objects.filter(id__gt=3)
1 list = BookInfo.objects.exclude(id=3)
list = BookInfo.objects.filter(bpub_date__year=1980)
list = BookInfo.objects.filter(bpub_date__gt=date(1990, 1, 1))
两个属性比较使用F对象
1 list = BookInfo.objects.filter(bread__gte=F('bcomment')) 2 list = BookInfo.objects.filter(bread__gt=F('bcomment') * 2)
多个过滤器逐个调用表示逻辑与关系,同sql语句中where部分的and关键字
1 list=BookInfo.objects.filter(bread__gt=20,id__lt=3) 2 或 3 list=BookInfo.objects.filter(bread__gt=20).filter(id__lt=3) 4 5 list = BookInfo.objects.filter(Q(bread__gt=20) | Q(pk__lt=3)) 6 7 Q对象前可使用~操做符,表示非not 8 list = BookInfo.objects.filter(~Q(pk=3))
使用aggregate()过滤器调用聚合函数。聚合函数包括:Avg,Count,Max,Min,Sum,被定义在django.db.models中
list = BookInfo.objects.aggregate(Sum('bread'))
注意aggregate的返回值是一个字典类型,格式以下:
{'聚合类小写__属性名':值} 如:{'sum__bread':3}
使用count时通常不使用aggregate()过滤器,count函数的返回值是一个数字
list = BookInfo.objects.count()
all():返回全部数据。 filter():返回知足条件的数据。 exclude():返回知足条件以外的数据,至关于sql语句中where部分的not关键字。 order_by():对结果进行排序
get():返回单个知足条件的对象 若是未找到会引起"模型类.DoesNotExist"异常。 若是多条被返回,会引起"模型类.MultipleObjectsReturned"异常。 count():返回当前查询结果的总条数。 aggregate():聚合,返回一个字典。
exists():判断查询集中是否有数据,若是有则返回True,没有则返回False
惰性执行:建立查询集不会访问数据库,直到调用数据时,才会访问数据库,调用数据的状况包括迭代、序列化、与if合用。 缓存:使用同一个查询集,第一次使用时会发生数据库的查询,而后把结果缓存下来,再次使用这个查询集时会使用缓存的数据
每一个查询集都包含一个缓存来最小化对数据库的访问。 在新建的查询集中,缓存为空,首次对查询集求值时,会发生数据库查询,django会将查询的结果存在查询集的缓存中,并返回请求的结果,接下来对查询集求值将重用缓存中的结果。
能够对查询集进行取下标或切片操做,等同于sql中的limit和offset子句。 注意:不支持负数索引。 对查询集进行切片后返回一个新的查询集,不会当即执行查询。 若是获取一个对象,直接使用[0],等同于[0:1].get(),可是若是没有数据,[0]引起IndexError异常,[0:1].get()若是没有数据引起DoesNotExist异常。 示例:获取第一、2项,运行查看。 list=BookInfo.objects.all()[0:2]
#定义图书模型类BookInfo class BookInfo(models.Model): ... #定义元选项 class Meta: db_table='bookinfo' #指定BookInfo生成的数据表名为bookinfo
1 url(r'^delete(\d+)/$',views.show_arg) 2 def show_arg(request,id): 3 return HttpResponse('show arg %s'%id)
1 url(r'^delete(?P<id1>\d+)/$',views.show_arg) 2 def show_arg(request,id1): 3 return HttpResponse('show %s'%id1)
下面除非特别说明,属性都是只读的
path:一个字符串,表示请求的页面的完整路径,不包含域名和参数部分。 method:一个字符串,表示请求使用的HTTP方法,经常使用值包括:'GET'、'POST'。 在浏览器中给出地址发出请求采用get方式,如超连接。 在浏览器中点击表单的提交按钮发起请求,若是表单的method设置为post则为post请求。 encoding:一个字符串,表示提交的数据的编码方式。 若是为None则表示使用浏览器的默认设置,通常为utf-8。 这个属性是可写的,能够经过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值。 GET:QueryDict类型对象,相似于字典,包含get请求方式的全部参数。 POST:QueryDict类型对象,相似于字典,包含post请求方式的全部参数。 FILES:一个相似于字典的对象,包含全部的上传文件。 COOKIES:一个标准的Python字典,包含全部的cookie,键和值都为字符串。 session:一个既可读又可写的相似于字典的对象,表示当前的会话,只有当Django 启用会话的支持时才可用,详细内容见"状态保持"。
content:表示返回的内容。 charset:表示response采用的编码字符集,默认为utf-8。 status_code:返回的HTTP响应状态码。 content-type:指定返回数据的的MIME类型,默认为'text/html'。
_init_:建立HttpResponse对象后完成返回内容的初始化。 set_cookie:设置Cookie信息。 set_cookie(key, value='', max_age=None, expires=None) cookie是网站以键值对格式存储在浏览器中的一段纯文本信息,用于实现用户跟踪。 max_age是一个整数,表示在指定秒数后过时。 expires是一个datetime或timedelta对象,会话将在这个指定的日期/时间过时。 max_age与expires二选一。 若是不指定过时时间,在关闭浏览器时cookie会过时。 delete_cookie(key):删除指定的key的Cookie,若是key不存在则什么也不发生。 write:向响应体中写数据。
有时须要保存下来用户浏览的状态,好比用户是否登陆过,浏览过哪些商品等。 实现状态保持主要有两种方式
response.set_cookie('h1', '你好')
response.write('<h1>' + request.COOKIES['h1'] + '</h1>')
在服务器端进行状态保持的方案就是Session
Django项目默认启用Session
/settings.py文件,设置SESSION_ENGINE项指定Session数据存储的方式,能够存储在数据库、缓存、Redis等
SESSION_ENGINE='django.contrib.sessions.backends.db'
SESSION_ENGINE='django.contrib.sessions.backends.cache'
SESSION_ENGINE='django.contrib.sessions.backends.cached_db'
全部请求者的Session都会存储在服务器中,服务器如何区分请求者和Session数据的对应关系呢?
在使用Session后,会在Cookie中存储一个sessionid的数据,每次请求时浏览器都会将这个数据发给服务器,服务器在接收到sessionid后,会根据这个值找出这个请求者的Session
结果:若是想使用Session,浏览器必须支持Cookie,不然就没法使用Session了
存储Session时,键与Cookie中的sessionid相同,值是开发人员设置的键值对信息,进行了base64编码,过时时间由开发人员设置
经过HttpRequest对象的session属性进行会话的读写操做
request.session['键']=值
request.session.get('键',默认值)
request.session.clear()
request.session.flush()
del request.session['键']
设置会话的超时时间,若是没有指定过时时间则两个星期后过时
会话还支持文件、纯cookie、Memcached、Redis等方式存储
pip install django-redis-sessions==0.5.6
SESSION_ENGINE = 'redis_sessions.session' SESSION_REDIS_HOST = 'localhost' SESSION_REDIS_PORT = 6379 SESSION_REDIS_DB = 2 SESSION_REDIS_PASSWORD = '' SESSION_REDIS_PREFIX = 'session'
for标签语法以下: {%for item in 列表%} 循环逻辑 {{forloop.counter}}表示当前是第几回循环,从1开始 {%empty%} 列表为空或不存在时执行此逻辑 {%endfor%} if标签语法以下: {%if ...%} 逻辑1 {%elif ...%} 逻辑2 {%else%} 逻辑3 {%endif%}
变量|过滤器:参数
data|default:'默认值'
日期date,用于对日期类型的值进行字符串格式化,经常使用的格式化字符以下:
Y表示年,格式为4位,y表示两位的年。 m表示月,格式为01,02,12等。 d表示日, 格式为01,02等。 j表示日,格式为1,2等。 H表示时,24进制,h表示12进制的时。 i表示分,为0-59。 s表示秒,为0-59。 value|date:"Y年m月j日 H时i分s秒"
过滤器escape能够实现对变量的html转义,默认模板就会转义,通常省略
{{t1|escape}}
过滤器safe:禁用转义,告诉模板这个变量是安全的,能够解释执行
{{data|safe}}
标签autoescape:设置一段代码都禁用转义,接受on、off参数
{%autoescape off%} ... {%endautoescape%}
CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造。CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求
1 from PIL import Image, ImageDraw, ImageFont 2 from django.utils.six import BytesIO 3 ... 4 def verify_code(request): 5 #引入随机函数模块 6 import random 7 #定义变量,用于画面的背景色、宽、高 8 bgcolor = (random.randrange(20, 100), random.randrange( 9 20, 100), 255) 10 width = 100 11 height = 25 12 #建立画面对象 13 im = Image.new('RGB', (width, height), bgcolor) 14 #建立画笔对象 15 draw = ImageDraw.Draw(im) 16 #调用画笔的point()函数绘制噪点 17 for i in range(0, 100): 18 xy = (random.randrange(0, width), random.randrange(0, height)) 19 fill = (random.randrange(0, 255), 255, random.randrange(0, 255)) 20 draw.point(xy, fill=fill) 21 #定义验证码的备选值 22 str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0' 23 #随机选取4个值做为验证码 24 rand_str = '' 25 for i in range(0, 4): 26 rand_str += str1[random.randrange(0, len(str1))] 27 #构造字体对象,ubuntu的字体路径为“/usr/share/fonts/truetype/freefont” 28 font = ImageFont.truetype('FreeMono.ttf', 23) 29 #构造字体颜色 30 fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255)) 31 #绘制4个字 32 draw.text((5, 2), rand_str[0], font=font, fill=fontcolor) 33 draw.text((25, 2), rand_str[1], font=font, fill=fontcolor) 34 draw.text((50, 2), rand_str[2], font=font, fill=fontcolor) 35 draw.text((75, 2), rand_str[3], font=font, fill=fontcolor) 36 #释放画笔 37 del draw 38 #存入session,用于作进一步验证 39 request.session['verifycode'] = rand_str 40 #内存文件操做 41 buf = BytesIO() 42 #将图片保存在内存中,文件类型为png 43 im.save(buf, 'png') 44 #将内存中的图片数据返回给客户端,MIME类型为图片png 45 return HttpResponse(buf.getvalue(), 'image/png')
1 def verify_yz(request): 2 yzm=request.POST.get('yzm') 3 verifycode=request.session['verifycode'] 4 response=HttpResponse('no') 5 if yzm==verifycode: 6 response=HttpResponse('ok') 7 return response
<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时,须要为include定义namespace属性,为url定义name属性,使用时,在模板中使用url标签,在视图中使用reverse函数,根据正则表达式动态生成地址,减轻后期维护成本
url(r'^',include('booktest.urls',namespace='booktest')) url(r'^fan2/$', views.fan2,name='fan2') 反向解析:<a href="{%url 'booktest:fan2'%}">fan2</a> return redirect(reverse('booktest:fan2'))
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ]
方法_init_(列表,int):返回分页对象,第一个参数为列表数据,第二个参数为每页数据的条数。 属性count:返回对象总数。 属性num_pages:返回页面总数。 属性page_range:返回页码列表,从1开始,例如[1, 2, 3, 4]。 方法page(m):返回Page类实例对象,表示第m页的数据,下标以1开始
调用Paginator对象的page()方法返回Page对象,不须要手动构造。 属性object_list:返回当前页对象的列表。 属性number:返回当前是第几页,从1开始。 属性paginator:当前页对应的Paginator对象。 方法has_next():若是有下一页返回True。 方法has_previous():若是有上一页返回True。 方法len():返回当前页面对象的个数。
1 from django.core.paginator import Paginator 2 from booktest.models import AreaInfo 3 ... 4 #参数pIndex表示:当前要显示的页码 5 def page_test(request,pIndex): 6 #查询全部的地区信息 7 list1 = AreaInfo.objects.filter(aParent__isnull=True) 8 #将地区信息按一页10条进行分页 9 p = Paginator(list1, 10) 10 #若是当前没有传递页码信息,则认为是第一页,这样写是为了请求第一页时能够不写页码 11 if pIndex == '': 12 pIndex = '1' 13 #经过url匹配的参数都是字符串类型,转换成int类型 14 pIndex = int(pIndex) 15 #获取第pIndex页的数据 16 list2 = p.page(pIndex) 17 #获取全部的页码信息 18 plist = p.page_range 19 #将当前页码、当前页的数据、页码信息传递到模板中 20 return render(request, 'booktest/page_test.html', {'list': list2, 'plist': plist, 'pIndex': pIndex})
url(r'^page(?P<pIndex>[0-9]*)/$', views.page_test)
<html> <head> <title>分页</title> </head> <body> 显示当前页的地区信息:<br> <ul> {%for area in list%} <li>{{area.id}}--{{area.atitle}}</li> {%endfor%} </ul> <hr> 显示页码信息:当前页码没有连接,其它页码有连接<br> {%for pindex in plist%} {%if pIndex == pindex%} {{pindex}} {%else%} <a href="/page{{pindex}}/">{{pindex}}</a> {%endif%} {%endfor%} </body> </html>
1 <html> 2 <head> 3 <title>省市区列表</title> 4 <script type="text/javascript" src="/static/js/jquery-1.12.4.min.js"></script> 5 <script type="text/javascript"> 6 $(function(){ 7 //页面加载完成后获取省信息,并添加到省select 8 $.get('/area2/',function(dic) { 9 pro=$('#pro') 10 $.each(dic.data,function(index,item){ 11 pro.append('<option value='+item[0]+'>'+item[1]+'</option>'); 12 }) 13 }); 14 //为省select绑定change事件,获取市信息,并添加到市select 15 $('#pro').change(function(){ 16 $.get('/area3_'+$(this).val()+'/',function(dic){ 17 city=$('#city'); 18 city.empty().append('<option value="">请选择市</option>'); 19 dis=$('#dis'); 20 dis.empty().append('<option value="">请选择区县</option>'); 21 $.each(dic.data,function(index,item){ 22 city.append('<option value='+item[0]+'>'+item[1]+'</option>'); 23 }) 24 }); 25 }); 26 //为市select绑定change事件,获取区县信息,并添加到区县select 27 $('#city').change(function(){ 28 $.get('/area3_'+$(this).val()+'/',function(dic){ 29 dis=$('#dis'); 30 dis.empty().append('<option value="">请选择区县</option>'); 31 $.each(dic.data,function(index,item){ 32 dis.append('<option value='+item[0]+'>'+item[1]+'</option>'); 33 }) 34 }) 35 }); 36 37 }); 38 </script> 39 </head> 40 <body> 41 <select id="pro"> 42 <option value="">请选择省</option> 43 </select> 44 <select id="city"> 45 <option value="">请选择市</option> 46 </select> 47 <select id="dis"> 48 <option value="">请选择区县</option> 49 </select> 50 </body> 51 </html
情景:用户发起request,并等待response返回。在本些views中,可能须要执行一段耗时的程序,那么用户就会等待很长时间,形成很差的用户体验,好比发送邮件、手机验证码等
INSTALLED_APPS = ( ... 'djcelery', }
import djcelery djcelery.setup_loader() BROKER_URL = 'redis://127.0.0.1:6379/2'
1 import time 2 from celery import task 3 4 @task 5 def sayhello(): 6 print('hello ...') 7 time.sleep(2) 8 print('world ...')
1 from booktest import tasks 2 ... 3 def sayhello(request): 4 # print('hello ...') 5 # time.sleep(2) 6 # print('world ...') 7 tasks.sayhello.delay() 8 return HttpResponse("hello world")
python manage.py migrate
sudo service redis start
python manage.py celery worker --loglevel=info
1 from django.conf import settings 2 from django.core.mail import send_mail 3 from celery import task 4 5 @task 6 def sayhello(): 7 msg='<a href="http://www.itcast.cn/subject/pythonzly/index.shtml" target="_blank">点击激活</a>' 8 send_mail('注册激活','',settings.EMAIL_FROM, 9 ['itcast88@163.com'], 10 html_message=msg)
请使用手机"扫一扫"x