Django之HttpRequest和HttpResponse
2.1 Permission
如上文所述,Django定义每个model后,默认都会添加该model的add, change和delete三个permission,自定义的permission可以在我们定义model时手动添加:
1
2
3
4
5
6
7
8
|
class
Task(models.Model):
...
class
Meta:
permissions
=
(
(
"view_task"
,
"Can see available tasks"
),
(
"change_task_status"
,
"Can change the status of tasks"
),
(
"close_task"
,
"Can remove a task by setting its status as closed"
),
)
|
每个permission都是django.contrib.auth.Permission类型的实例,该类型包含三个字段name,codename和content_type,其中content_type反应了permission属于哪个model,codename如上面的view_task,代码逻辑中检查权限时要用,name是permission的描述,将permission打印到屏幕或页面时默认显示的就是name
2.2 User Permission管理
User对象的user_permission字段管理用户的权限:
1
2
3
4
5
6
7
8
|
myuser.user_permissions
=
[permission_list]
myuser.user_permissions.add(permission, permission, ...)
#增加权限
myuser.user_permissions.remove(permission, permission, ...)
#删除权限
myuser.user_permissions.clear()
#清空权限
##############################################################
# 注:上面的permission为django.contrib.auth.Permission类型的实例
##############################################################
|
检查用户权限用has_perm()方法:
myuser.has_perm('myapp.fix_car')
has_perm()方法的参数,即permission的codename,但传递参数时需要加上model 所属app的前缀,格式为
无论permission赋予user还是group,has_perm()方法均适用
第一设置权限,第二注册权限
四:自定义模板库
1.建立项目,app的不说。只要在随意一个app中建立上文提到的templatetags文件夹。
这里是有点不理解的地方,在任意一个app建立的tags别的app能够使用吗?起初对此很疑惑。以为在一个app下建立的tags就这一个app能使用。为了大家都能够使用自己定义的tags,我还想把templatetags单独拿出来,跟普通app在项目当中是平级地位。这种思路搞了很久发现行不通。无奈只好打算使用copy在每一个app都复制一份templatetags。(当然这只是我起初的错误想法)但后来发现,居然一个app中有,其他的app中就可以直接使用此自定义的文件了。只需要在需要的模板当中(不管模板是在你的那个app中)调用load语句将自定义的文件load进来便可以。
随后看了看一些文档,只要templatetags所在位置是settings.py中INSTALLED_APPS中配置过的,或是在TEMPLATE_DIRS配置过的,任意一个位置便可以。
一定记得要在templatetags文件夹中包含__init__.py文件。空文件便可。
Django编译一个模板时,它将原始模板分成一个个 节点 。每个节点都是 django.template.Node 的一个实例,并且具备 render() 方法。 于是,一个已编译的模板就是 节点 对象的一个列表。 例如,看看这个模板:
1
2
3
4
5
6
7
8
|
Hello, {{ person.name }}.
{
%
ifequal name.birthday today
%
}
Happy birthday!
{
%
else
%
}
Be sure to come back on your birthday
for
a splendid surprise message.
{
%
endifequal
%
}
|
被编译的模板表现为节点列表的形式:
- 文本节点: "Hello, "
- 变量节点: person.name
- 文本节点: ".\n\n"
- IfEqual节点: name.birthday和today
当你调用一个已编译模板的 render() 方法时,模板就会用给定的context来调用每个在它的节点列表上的所有节点的 render() 方法。 这些渲染的结果合并起来,形成了模板的输出。 因此,要自定义模板标签,你需要指明原始模板标签如何转换成节点(编译函数)和节点的render()方法完成的功能 。
class UpperNode(template.Node): 继承template.Node类
def __init__(self,nodelist):
self.nodelist=nodelist
def render(self, context): 调用render处理方法
content = self.nodelist.render(context) 用render处理context
return content.lower() 将作用与节点当中的内容,不仅仅是变量
def upper(parser, token):
第一个参数是模板内容,第二个参数是参数列表nodelist = parser.parse("endupper") 取节点当中的内容
parse.delete_first_token() 删除第一个参数,因为第一个参数是自己的名字upper
renturn UpperNode(nodelist) 传递到UpperNode当中
{%load upper %}
{% upper %}
{% endupper %}
# -*- coding: utf-8 -*-
from django import template
register = template.Library()
# 定义一个将日期中的月份转换为大写的过滤器,如8转换为八
@register.filter
def month_to_upper(key):
return ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'][key.month-1]
# 注册过滤器
# register.filter('month_to_upper', month_to_upper)
__gte 大于等于
__lt 小于
__lte 小于等于
__in 存在于一个list范围内
__startswith 以…开头
__istartswith 以…开头 忽略大小写
__endswith 以…结尾
__iendswith 以…结尾,忽略大小写
__range 在…范围内
__year 日期字段的年份
__month 日期字段的月份
__day 日期字段的日
__isnull=True/False
__isnull=True 与 __exact=None的区别
filter(name__in=['li','wei'])
Q查询
django.db.models.Q
1、Q对象(django.db.models.Q)可以对关键字参数进行封装,从而更好地应用多个查询,例如:
from django.db.models import Q from login.models import New #models对象 news=New.objects.filter(Q(question__startswith='What'))
2、可以组合使用&,|操作符,当一个操作符是用于两个Q的对象,它产生一个新的Q对象。
Q(question__startswith='Who') | Q(question__startswith='What')
3、Q对象可以用~操作符放在前面表示否定,也可允许否定与不否定形式的组合
Q(question__startswith='Who') | ~Q(pub_date__year=2005)
django *args, **kwargs 用法
def foo(*args, **kwargs):
print ‘args = ‘, args
print ‘kwargs = ‘, kwargs
print ‘—————————————‘
if __name__ == ‘__main__’:
foo(1,2,3,4)
foo(a=1,b=2,c=3)
foo(1,2,3,4, a=1,b=2,c=3)
foo(‘a’, 1, None, a=1, b=’2′, c=3)
输出结果如下:args = (1, 2, 3, 4)
kwargs = {}
—————————————
args = ()
kwargs = {‘a’: 1, ‘c’: 3, ‘b’: 2}
—————————————
args = (1, 2, 3, 4)
kwargs = {‘a’: 1, ‘c’: 3, ‘b’: 2}
—————————————
args = (‘a’, 1, None)
kwargs = {‘a’: 1, ‘c’: 3, ‘b’: ‘2’}
可以看到,这两个是python中的可变参数。*args表示任何多个无名参数,它是一个tuple;**kwargs表示关键字参数,它是一个 dict。并且同时使用*args和**kwargs时,必须*args参数列要在**kwargs前,像foo(a=1, b=’2′, c=3, a’, 1, None, )这样调用的话,会提示语法错误“SyntaxError: non-keyword arg after keyword arg”。
还有一个很漂亮的用法,就是创建字典:
def kw_dict(**kwargs):
return kwargs
print kw_dict(a=1,b=2,c=3) == {‘a’:1, ‘b’:2, ‘c’:3}
kwargs['username'] = 'li'
kwargs['username'] = 'wei'
comment = Comment.objects.filter(**kwargs)
Django提供两种方式执行(performing)原始的SQL查询:
(1)、Manager.raw():执行原始查询并返回模型实例
(2)、Executing custom SQL directly:直接执行自定义SQL,这种方式可以完全避免数据模型,而是直接执行原始的SQL语句。
raw() 方法自动通过查询字段映射到 model字段,并且是通过名称来匹配,这意味着我们可以使用SQL子句(clause)
注意当输入查询字段的时候,不要漏了主键(id),否则会出错
导入 form django.db import connection,transaction
django.db.connection:代表默认的数据库连接
django.db.transaction:代表默认数据库事务(transaction)
connection.cursor(): 获得一个游标(cursor)对象
cursor.execute(sql, [params]):执行SQL
cursor.fetchone() 或者 cursor.fetchall():返回结果行
如果执行修改操作,则调用transaction.commit_unless_managed()来保证你的更改提交到数据库。
def sql(request):
"""
----------------------------------------------
Function: 执行原始的SQL
DateTime: 2013/x/xx
----------------------------------------------
"""
from django.db import connection,transaction
cursor = connection.cursor() #获得一个游标(cursor)对象
#更新操作
cursor.execute('update other_other2 set name ="李四" where id=%s',[3]) #执行sql语句
transaction.commit_unless_managed() #提交到数据库
#查询操作
cursor.execute('select * from other_other2 where id>%s' ,[1])
raw = cursor.fetchone() #返回结果行 或使用 #raw = cursor.fetchall()
#如果连接多个数据库则使用django.db.connections
from django.db import connections
_cursor = connections['other_database'].cursor()
#如果执行了更新、删除等操作
transaction.commit_unless_managed(using='other_databases')
return render_to_response('other/sql.html',{'raw':raw})
from django.db import models
class ArticleManager(models.Manager):
def distinct_date(self):
distinct_date_list = []
date_list = self.values('date_publish')
for date in date_list:
date = date['date_publish'].strftime('%Y/%m文章存档')
if date not in distinct_date_list:
distinct_date_list.append(date)
return distinct_date_list
当编写Django应用程序时,我们已经习惯通过添加方法到模型里以此达到封装业务逻辑并隐藏实现细节。这种方法看起来是非常的自然,而且实际上它也用在Django的内建应用中。 |
>>> from django.contrib.auth.models import User
>>> user = User.objects.get(pk=5)
>>> user.set_password('super-sekrit')
>>> user.save()
这里的set_password就是一个定义在django.contrib.auth.models.User模型中的方法,它隐藏了对密码进行哈希操作的具体实现。相应的代码看起来应该是这样
|
from django.contrib.auth.hashers import make_password
class User(models.Model):
# fields go here..
def set_password(self, raw_password):
self.password = make_password(raw_password)
class ArticleManager(models.Manager):
def distinct_date(self):
distinct_date_list = []
date_list = self.values('date_publish')
for date in date_list:
date = date['date_publish'].strftime('%Y/%m文章存档')
if date not in distinct_date_list:
distinct_date_list.append(date)
return distinct_date_list
class Article(models.Model):
objects = ArticleManager()
class LoginForm(forms.Form):
email = forms.CharField(label='email' max_length=100)
age = forms.IntegerField(label='age')
def clean_email(self):
email = self.clean_date.get('email')
if len(email.sqlit('@'))<2:
raise forms.ValidationError('email is not correct')
return email
每一个请求都是先通过中间件中的 process_request 函数,这个函数返回 None 或者 HttpResponse 对象,如果返回前者,继续处理其它中间件,如果返回一个 HttpResponse,就处理中止,返回到网页上。
中间件不用继承自任何类(可以继承 object ),下面一个中间件大概的样子:
1
2
3
4
5
6
|
class
CommonMiddleware(
object
):
def
process_request(
self
, request):
return
None
def
process_response(
self
, request, response):
return
response
|
class Version(object):
def process_request(self,request): 请求处理过程
agent = request.META['HTTP_USER_AGENT'] 获取浏览器版本型号
result = re.findall('MSIE [5678]', agent) 匹配字符串
if len(result)>0:
renturn
render(request, 'warning.html') 可以用render方法渲染到另一个页面
使用Django时,默认是开启对多时区的支持的,在获取时间的时候会是如下形式:
datetime.datetime(2014, 4, 18, 15, 37, 7, tzinfo=
我们可以利用django.utils.timezone中提供的localtime方法来将该时间转换为本地时间:
1
2
3
4
|
>>> dt
datetime.datetime(
2014
,
4
,
18
,
15
,
37
,
7
, tzinfo
=
>>> localtime(dt)
datetime.datetime(
2014
,
4
,
18
,
23
,
37
,
7
, tzinfo
=
|
有时候,我们需要将该时间与当前时间做比较,例如计算差值,你可能会想到直接这么做:
1
2
3
|
>>>
import
datetime
>>> now
=
datetime.datetime.now()
>>> now
-
dt
|
不过这是不对的,并告知如下错误:
1
2
3
|
Traceback (most recent call last):
File
"
, line
1
,
in
TypeError: can't subtract offset
-
naive
and
offset
-
aware datetimes
|
问题就出在利用datetime.datetime.now()得到的当前时间是offset-naive的,而另外一个却是offset-aware的,因此我们需要将这里的dt转成与now一样的形式,可以这么做:
1
2
3
4
5
|
>>> dt
=
dt.replace(tzinfo
=
None
)
>>> dt
datetime.datetime(
2014
,
4
,
18
,
15
,
37
,
7
)
>>> now
-
dt
datetime.timedelta(
0
,
34108
,
443000
)
来源:
|