Django学习
一 什么叫Django
Django是一个开放源代码的Web应用框架,由Python写成。采用了MVC的框架模式,即模型M,视图V和控制器C。它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是CMS(内容管理系统)软件。并于2005年7月在BSD许可证下发布。这套框架是以比利时的吉普赛爵士吉他手Django Reinhardt来命名的。
MVC框架:
二 Django的简单介绍
工作机制:
模型:M
模型是你的数据的唯一的、权威的信息源。它包含你所储存数据的必要字段和行为。通常,每个模型对应数据库中唯一的一张表。
基础:
- 每个模型都是django.db.models.Model 的一个Python 子类。
- 模型的每个属性都表示为数据库中的一个字段。
- Django 提供一套自动生成的用于数据库访问的API
三 Django文档
1 视图层
1)Request对象和Response对象
Django 使用Request 对象和Response 对象在系统间传递状态。
当请求一个页面时,Django会建立一个包含请求元数据的 HttpRequest 对象。 当Django 加载对应的视图时,HttpRequest 对象将作为视图函数的第一个参数。每个视图会返回一个HttpResponse 对象。
HttpRequest对象
属性
- HttpRequest.method
- HttpRequest.GET 类似字典的对象
- HttpRequest.POST 类似字典的对象
- HttpResponse对象
- 与由Django自动创建的HttpRequest 对象相比,HttpResponse 对象由程序员创建.你创建的每个视图负责初始化实例,填充并返回一个 HttpResponse.
- 用法
- 传递字符串
- 典型的应用是传递一个字符串作为页面的内容到HttpResponse 构造函数:
>>> from django.http import HttpResponse >>> response = HttpResponse("Here's the text of the Web page.") >>> response = HttpResponse("Text only, please.", content_type="text/plain")
- 2 render()
- help文档中描述如下:
render(request, template_name, context=None, content_type=None, status=None, using=None)
Returns a HttpResponse whose content is filled with the result of calling django.template.loader.render_to_string() with the passed arguments.
此方法的作用---结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。
通俗的讲就是把context的内容, 加载进templates中定义的文件, 并通过浏览器渲染呈现.
参数讲解:
request: 该request用于生成response
template_name: templates 中定义的文件, 要注意路径名. 比如'templates\polls\index.html', 参数就要写‘polls\index.html’
context: 要传入文件中用于渲染呈现的数据, 默认是字典格式
content_type: 生成的文档要使用的MIME 类型。默认为DEFAULT_CONTENT_TYPE 设置的值。
status: http的响应代码,默认是200.
using: 用于加载模板使用的模板引擎的名称。
示例:from django.shortcuts import render def my_view(request): # View code here... return render(request, 'myapp/index.html', { 'foo': 'bar', }, content_type='application/xhtml+xml')
3 redirect()重定向
如果验证成功要用redirect跳转,不然你实际页面是发生了变化,但是URL还是没有变!~
render()只是对当前访问模板的加载与渲染,记住!是当前!并不能跳转!
4 编写视图
一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何东西都可以。无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你的Python目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了将代码放在某处,约定是将视图放置在项目或应用程序目录中的名为views.py的文件中。
一个简单的视图
下面是一个返回当前日期和时间作为HTML文档的视图:
from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
让我们逐行阅读上面的代码:
-
首先,我们从 django.http模块导入了HttpResponse类,以及Python的datetime库。
-
接着,我们定义了current_datetime函数。它就是视图函数。每个视图函数都使用HttpRequest对象作为第一个参数,并且通常称之为request。
注意,视图函数的名称并不重要;不需要用一个统一的命名方式来命名,以便让Django识别它。我们将其命名为current_datetime,是因为这个名称能够精确地反映出它的功能。
-
这个视图会返回一个HttpResponse对象,其中包含生成的响应。每个视图函数都负责返回一个HttpResponse对象。
四 cmd相关的指令。
命令行创建Django项目
在指定的文件夹下 django-admin startproject XXX
启动Django项目
在指定文件夹下 python manage.py runserver
五 模板
模板层
模板是一个文本,用于分离文档的表现形式和内容。
使用模板来输出数据,从而实现数据与视图分离。
在 Django 模板中遍历复杂数据结构的关键是句点字符。非常灵活。列表的索引值,字典的key值,类的静态属性,类的动态属性,都可以是 . 取到。美中不足的是类的动态属性不能传参。
点号(.)用来访问变量的属性。
从技术上来说,当模版系统遇到点("."),它将以这样的顺序查询:
- 字典查询(Dictionary lookup)
- 属性或方法查询(Attribute or method lookup)
- 数字索引查询(Numeric index lookup)
如果计算结果的值是可调用的,它将被无参数的调用。调用的结果将成为模版的值。 -----官方文档(1.8.2)
模版是纯文本文件。它可以产生任何基于文本的的格式(HTML,XML,CSV等等)。
模版包括在使用时会被值替换掉的 变量,和控制模版逻辑的 标签。
模板继承
{{ block.super }}继承模板中原有的内容。
模板变量用双括号表示。
模板标签
if/else 标签
{% if condition %} ... display {% endif %}
for/empty标签
for 标签带有一个可选的{% empty %} 从句,以便在给出的组是空的或者没有被找到时,可以有所操作。
{% for person in person_list %} <p>{{ person.name }}</p> {% empty %} <p>sorry,no person here</p> {% endfor %}
csrf_token 标签
原文博客地址:http://blog.csdn.net/wjtlht928/article/details/46563809
PS :跨域
参考博客 :https://segmentfault.com/a/1190000000718840
CSRF的攻击原理
CSRF攻击原理比较简单,如图1所示。其中Web A为存在CSRF漏洞的网站,Web B为攻击者构建的恶意网站,User C为Web A网站的合法用户。
1. 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;
2.在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;
3. 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;
4. 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;
5. 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。
预防措施
1)在请求地址中添加token并验证
CSRF攻击之所以能够成功,是因为攻击者可以伪造用户的请求,该请求中所有的用户验证信息都存在于Cookie中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的Cookie来通过安全验证。由此可知,抵御CSRF攻击的关键在于:在请求中放入攻击者所不能伪造的信息,并且该信息不存在于Cookie之中。鉴于此,系统开发者可以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务器端建立一个拦截器来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。
2)在HTTP头中自定义属性并验证
自定义属性的方法也是使用token并进行验证,和前一种方法不同的是,这里并不是把token以参数的形式置于HTTP请求之中,而是把它放到HTTP头中自定义的属性里。通过XMLHttpRequest这个类,可以一次性给所有该类请求加上csrftoken这个HTTP头属性,并把token值放入其中。这样解决了前一种方法在请求中加入token的不便,同时,通过这个类请求的地址不会被记录到浏览器的地址栏,也不用担心token会通过Referer泄露到其他网站。
六 django的请求生命周期
首先我们知道HTTP请求及服务端响应中传输的所有数据都是字符串.
在Django中,当我们访问一个的url时,会通过路由匹配进入相应的html网页中.
Django的请求生命周期是指当用户在浏览器上输入url到用户看到网页的这个时间段内,Django后台所发生的事情
而Django的生命周期内到底发生了什么呢??
1. 当用户在浏览器中输入url时,浏览器会生成请求头和请求体发给服务端
请求头和请求体中会包含浏览器的动作(action),这个动作通常为get或者post,体现在url之中.
2. url经过Django中的wsgi,再经过Django的中间件,最后url到过路由映射表,在路由中一条一条进行匹配,
一旦其中一条匹配成功就执行对应的视图函数,后面的路由就不再继续匹配了.
3. 视图函数根据客户端的请求查询相应的数据.返回给Django,然后Django把客户端想要的数据做为一个字符串返回给客户端.
4. 客户端浏览器接收到返回的数据,经过渲染后显示给用户.
视图函数根据客户端的请求查询相应的数据后.如果同时有多个客户端同时发送不同的url到服务端请求数据
服务端查询到数据后,怎么知道要把哪些数据返回给哪个客户端呢??
因此客户端发到服务端的url中还必须要包含所要请求的数据信息等内容.
例如,http://www.aaa.com/index/?nid=user
这个url中,
客户端通过get请求向服务端发送的nid=user
的请求,服务端可以通过request.GET.get("nid")
的方式取得nid数据
客户端还可以通过post的方式向服务端请求数据.
当客户端以post的方式向服务端请求数据的时候,请求的数据包含在请求体里,这时服务端就使用request.POST的方式取得客户端想要取得的数据
需要注意的是,request.POST是把请求体的数据转换一个字典,请求体中的数据默认是以字符串的形式存在的.
七 django UR调度器
视图层
文档网址:http://python.usyiyi.cn/documents/django_182/topics/http/urls.html
1()位置传参
2(?P<x>)关键字传参
3 URL的反向解析
在模板中使用 url模板标签
urlpatterns=[r'login.html',view.login,name='mylogin']
模板html文件中
[form action='{% url 'mylogin'%}']
这类功能可以用Django的中间件框架来实现。
W3C介绍网址:https://www.w3cschool.cn/django/mrxdfozt.html
十 Q查询
Q 对象是 django.core.meta.Q 的实例, 用来装载一系列关键字参数. 这些关键字参数就象指定给 get() 和 filter() 函数的关键字参数一样.举例来说:
Q(question__startswith='What')
Q 对象可以使用 & 和 | 运算符进行组合. 当两个Q对象进行 & 或 | 运算时,会生成一个新的Q对象.举例来说语句:
Q(question__startswith='Who') | Q(question__startswith='What')
生成一个新的 Q 对象表示这两个 "question__startswith" 查询条件的 "OR" 关系. 等同于下面的 SQL WHERE 子句:
WHERE question LIKE 'Who%' OR question LIKE 'What%'
示例:
from django.db.models import Q,F
book_list=models.Book.objects.filter(Q(publish__id=2)|Q(price__gt=70))
十一 F查询
应用场景 :商品在原价格的基础上涨价10元
models.Book.objects.update(price=F('price')+10)
十二 中介模型
文档官方网址:http://python.usyiyi.cn/documents/django_182/topics/db/models.html
中介模型解决的是当Django帮你建好的多对多模型,并不能够满足,需要添加额外的字段。
比如Student表,Course表,属于多对多关系。在Studnet2Course中,想添加一个score字段。
怎么解决呢?通过through参数,来告诉Django我自己来建表。
class Student(models.Model): name=models.CharField(max_length=10) courese=models.ManyToManyField('Course',through='student2course') class Course(models.Model): name=models.CharField(max_length=10) class student2course(models.Model): student_id=models.ForeignKey('Student') course_id=models.ForeignKey('Course') score=models.DecimalField(max_digits=4,decimal_places=2)
中介模型有一些限制:
1 中介模型必须有且只有一个外键关联到源模型上,否则,必须通过manytomanyfield.through_fields()来显示指定Django 应该在关系中使用的外键。
示例:
Article与Tag建立多对多 中介模型
class Article(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=50, verbose_name='文章标题') desc = models.CharField(max_length=255, verbose_name='文章描述') comment_count= models.IntegerField(default=0) homeCategory = models.ForeignKey(to='HomeCategory', to_field='nid', null=True) user = models.ForeignKey(verbose_name='作者', to='UserInfo', to_field='nid') tags = models.ManyToManyField( to="Tag", through='Article2Tag', through_fields=('article', 'tag'), )
在这个中介模型中,有两个外键,怎么办呢,用through_fields参数。
class Tag(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(verbose_name='标签名称', max_length=32) blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid')
class Article2Tag(models.Model): nid = models.AutoField(primary_key=True) article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid') tag = models.ForeignKey(verbose_name='标签', to="Tag", to_field='nid') class Meta: unique_together = [ ('article', 'tag'), ]
设置联合唯一。
十三 <QuerySet>转变为生成器
只需调用.iterator()方法
def index(request): obj = models.Student.objects.all() print(obj, type(obj)) print(obj.iterator(),type(obj.iterator())) return HttpResponse('ok')
输出:
<QuerySet [<Student: Student object>, <Student: Student object>]> <class 'django.db.models.query.QuerySet'> <generator object ModelIterable.__iter__ at 0x000002538633DBA0> <class 'generator'>
十四 bulk_create 整体插入
bulk 大量
如果插入10000条数据,这样的方法是不明智的,不合适的
def create(request): for i in range(10000): User.objects.create_user('user-%s' %i) return HttpResponse('ok')
尽量少的避免数据的链接与断开
推荐这种方法
def create(request): l=[] for i in range(10000): l.append('user-%s' %i) User.objects.bulk_create(l) return HttpResponse('ok')
十五 verbose_name
自述名
应用场景:后台显示,admin?
一个字段的可读性更高的名称。如果用户没有设定冗余名称字段,Django会自动将该字段属性名中的下划线转换为空格,并用它来创建冗余名称。
除ForeignKey、ManyToManyField 和 OneToOneField 之外,每个字段类型都接受一个可选的位置参数(在第一的位置) —— 字段的自述名。如果没有给定自述名,Django 将根据字段的属性名称自动创建自述名 —— 将属性名称的下划线替换成空格。
官方文档地址:http://python.usyiyi.cn/documents/django_182/topics/db/models.html#verbose-field-names