Django进阶

一:用户信息扩展
1.可以采用用户关联的方式进行扩展
2.可以采用继承的方式进行扩展
都需要在admin中进行设定,显示需要显示的内容


Django之HttpRequest和HttpResponse


Django之HttpRequest和HttpResponse - songyalong1117 - 宋亚龙


二:自定义认证方式
只不过是自己在view当中写login函数罢了
user.check_password()
user.has_perm

三:权限的设计使用

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的前缀,格式为<app label>.<permission codename>。

无论permission赋予user还是group,has_perm()方法均适用


第一设置权限,第二注册权限


四:自定义模板库


就是blog项目当中的简化代码,抽离出一个大的base.html然后设置block
需要补充的是,block可以在base.html当中进行设置作为默认,其他的html在base.html基础上写的时候,没有设置那个block就以默认的block运行


五:自定义标签

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
  •     文本节点: ". "
  •     IfEqual节点: name.birthday和today

当你调用一个已编译模板的 render() 方法时,模板就会用给定的context来调用每个在它的节点列表上的所有节点的 render() 方法。 这些渲染的结果合并起来,形成了模板的输出。 因此,要自定义模板标签,你需要指明原始模板标签如何转换成节点(编译函数)和节点的render()方法完成的功能 。


 
这个要在templatetags里面进行定义
upper.py
//
  1. class UpperNode(template.Node): 继承template.Node类
  2. def __init__(self,nodelist):
  3. self.nodelist=nodelist
  4. def render(self, context): 调用render处理方法
  5. content = self.nodelist.render(context) 用render处理context
  6. return content.lower() 将作用与节点当中的内容,不仅仅是变量
  1. def upper(parser, token):第一个参数是模板内容,第二个参数是参数列表
  2. nodelist = parser.parse("endupper") 取节点当中的内容
  3. parse.delete_first_token() 删除第一个参数,因为第一个参数是自己的名字upper
  4. renturn UpperNode(nodelist) 传递到UpperNode当中
还需要注册一下
在html当中使用upper标签的时候要先load进来
  1. {%load upper %}
  2. {% upper %}
  3. {% endupper %}


六:自定义过滤器

过滤器还可以组合起来是用,不同的组合还会有不同的效果

直接把blog里面定义过来的filter拷贝过来看
  1. # -*- coding: utf-8 -*-
  2. from django import template
  3. register = template.Library()
  4. # 定义一个将日期中的月份转换为大写的过滤器,如8转换为八
  5. @register.filter
  6. def month_to_upper(key):
  7. return ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'][key.month-1]
  8. # 注册过滤器
  9. # register.filter('month_to_upper', month_to_upper)
跟定义标签类似,但实现的功能更为强大

七:models的定义和同步

如果在models里面定义没有定义meta就会显示object
所以在meta或者__str__中来返回一些想要显示的内容
当对models进行修改的时候可以通过
makemigrations  migrate进行同步



八:增加修改和删除操作

拿Article的models作为范例
添加信息的几种方式:
1.article = Article(user='li',tags=1) article.save()
2.article = Article.objects.get(user='li') article.user= "wei" article.save()
3.article = Article.objects.create(user='li') article.save()
更倾向于第三种,不过第一种也可以,第二种可以修改

删除操作  
article = Article.objects.get(user='li')
article.delete()

九:单表查询的常用方法
get() 得到一个对象,没有得到或者得到多个会报错
all()
filter() 得到符合条件的对象
exclude() 得到与输入条件相反的对象
order_by() 按一定顺序排序
distinct.values('name')  根据某一个字段进行去重
[0:10]  从0开始取

常用查询方式:
__exact 精确等于  例如:filter(name__exact='li')
__iexact 忽略大小写精确等于
__contains  包含有某一字段   filter(name__contains="li")
__icontains 忽略大小写包含某一字段
但对sqlite当中contains作用等于icontains
__gt 大于
__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'])


十:多表查询常用方式及方法

Commnet 为 Article的子表
comment = Comment.objects.filter(user__username='li')用这种双下划线的方式进行判断
二:comment.user.username取出外键当中的内容
主表查询子表:
artilce= Article.objects.get(pk=1)
comment = article.comment_set.content
取出的是id=1的文章的所有评论

主表可以查询出所关联的所有子表,子表可以查询出所关联主表的信息,也可以通过查询子表当中的外键到主表中去匹配,从而查询出所有的主表



十一:聚集查询相关方式及方法

这个silver好sb啊,Django 的查询就是聚合查询,查询一般是一个QuerySet的集合

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 用法


  1. def foo(*args, **kwargs):
  2. print args = ‘, args
  3. print kwargs = ‘, kwargs
  4. print ‘—————————————‘
  5. if __name__ == __main__’:
  6. foo(1,2,3,4)
  7. foo(a=1,b=2,c=3)
  8. foo(1,2,3,4, a=1,b=2,c=3)
  9. foo(‘a’, 1, None, a=1, b=’2′, c=3)
  10. 输出结果如下:args = (1, 2, 3, 4)
  11. kwargs = {}
  12. —————————————
  13. args = ()
  14. kwargs = {‘a’: 1, c’: 3, b’: 2}
  15. —————————————
  16. args = (1, 2, 3, 4)
  17. kwargs = {‘a’: 1, c’: 3, b’: 2}
  18. —————————————
  19. args = (‘a’, 1, None)
  20. kwargs = {‘a’: 1, c’: 3, b’: 2’}
  21. 可以看到,这两个是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”。
  22. 还有一个很漂亮的用法,就是创建字典:
  23. def kw_dict(**kwargs):
  24. return kwargs
  25. print kw_dict(a=1,b=2,c=3) == {‘a’:1, b’:2, c’:3}

还可以这样查询
  1. kwargs['username'] = 'li'
  2. kwargs['username'] = 'wei'
  3. comment = Comment.objects.filter(**kwargs)


十二:在Django中使用sql

关键字:
connection     connections       transaction
insert/create/update/delete/select/drop

如果在models没有定义数据表名,将以app名加下划线加上定义的表名(自动转化为小写)

查询时可以直接使用raws函数进行sql查询

comment = Comment.objects.raw(select * from blog_comment)

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()来保证你的更改提交到数据库。


 
  1. def sql(request):
  2. """
  3. ----------------------------------------------
  4. Function: 执行原始的SQL
  5. DateTime: 2013/x/xx
  6. ----------------------------------------------
  7. """
  8. from django.db import connection,transaction
  9. cursor = connection.cursor() #获得一个游标(cursor)对象
  10. #更新操作
  11. cursor.execute('update other_other2 set name ="李四" where id=%s',[3]) #执行sql语句
  12. transaction.commit_unless_managed() #提交到数据库
  13. #查询操作
  14. cursor.execute('select * from other_other2 where id>%s' ,[1])
  15. raw = cursor.fetchone() #返回结果行 或使用 #raw = cursor.fetchall()
  16. #如果连接多个数据库则使用django.db.connections
  17. from django.db import connections
  18. _cursor = connections['other_database'].cursor()
  19. #如果执行了更新、删除等操作
  20. transaction.commit_unless_managed(using='other_databases')
  21. return render_to_response('other/sql.html',{'raw':raw})


十三:自定义QuerySet及惰性机制

comment = Comment.objects.filter(user__username='li')
这样查询之后还可以接着查询comment.exclude(user__username='wei')
返回为一个QuerySet查询集,但不会真正去查询,直到使用到它的时候才去数据库里面进行查询,然后上面两句查询语句会合成一大句sql查询语句

自定义QuerySet其实就是写的查询语句

十四:自定义manager

在models当中定义类方法进行使用
  1. from django.db import models
  2. class ArticleManager(models.Manager):
  3. def distinct_date(self):
  4. distinct_date_list = []
  5. date_list = self.values('date_publish')
  6. for date in date_list:
  7. date = date['date_publish'].strftime('%Y/%m文章存档')
  8. if date not in distinct_date_list:
  9. distinct_date_list.append(date)
  10. return distinct_date_list


当编写Django应用程序时,我们已经习惯通过添加方法到模型里以此达到封装业务逻辑并隐藏实现细节。这种方法看起来是非常的自然,而且实际上它也用在Django的内建应用中


  1. >>> from django.contrib.auth.models import User
  2. >>> user = User.objects.get(pk=5)
  3. >>> user.set_password('super-sekrit')
  4. >>> user.save()
这里的set_password就是一个定义在django.contrib.auth.models.User模型中的方法,它隐藏了对密码进行哈希操作的具体实现。相应的代码看起来应该是这样

  1. from django.contrib.auth.hashers import make_password
  2. class User(models.Model):
  3. # fields go here..
  4. def set_password(self, raw_password):
  5. 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()
http://www.oschina.net/translate/higher-level-query-api-django-orm 
 

十五:form的定义与验证的使用
终于知道为什么要写forms了,可以省掉一堆html代码,直接交给Django去处理,由Django去生成html代码,还可以对输入的数据进行判断,非常方便,
直接在后端写python代码,不用在前端在进行修改
forms可以在view当中写,也可以新建一个文件来写
Django对输入的字段进行验证,不符合要求会进行提醒
  1. class LoginForm(forms.Form):
  2. email = forms.CharField(label='email' max_length=100)
  3. age = forms.IntegerField(label='age')
  4. def clean_email(self):
  5. email = self.clean_date.get('email')
  6. if len(email.sqlit('@'))<2:
  7. raise forms.ValidationError('email is not correct')
  8. return email


python中间件

每一个请求都是先通过中间件中的 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
我觉得就是

这张图当中当网页的request请求进行处理的时候,设计一个函数对request进行处理叫做中间件


现在settings里面的MIDDLEWARE_CLASSES 配置路径,app名,加模块名,加类名'todolist.middleware.Version',
然后再在定义的模块里面进行定义
  1. class Version(object):
  2. def process_request(self,request): 请求处理过程
  3. agent = request.META['HTTP_USER_AGENT'] 获取浏览器版本型号
  4. result = re.findall('MSIE [5678]', agent) 匹配字符串
  5. if len(result)>0:
  6. renturn  render(request, 'warning.html') 可以用render方法渲染到另一个页面
还可以写成跳转的形式,跳转到warning.html,这里需要判断,需要些url和views


Django获取Datetime中offset-naive与offset-aware时间的计算

使用Django时,默认是开启对多时区的支持的,在获取时间的时候会是如下形式:

datetime.datetime(2014, 4, 18, 15, 37, 7, tzinfo=<UTC>)

我们可以利用django.utils.timezone中提供的localtime方法来将该时间转换为本地时间:

1
2
3
4
>>> dt
datetime.datetime(201441815377, tzinfo=<UTC>)
>>> localtime(dt)
datetime.datetime(201441823377, tzinfo=<LocalTimezone>)

有时候,我们需要将该时间与当前时间做比较,例如计算差值,你可能会想到直接这么做:

1
2
3
>>> import datetime
>>> now = datetime.datetime.now()
>>> now - dt

不过这是不对的,并告知如下错误:

1
2
3
Traceback (most recent call last):
  File "<console>", line 1in <module>
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(201441815377)
>>> now - dt
datetime.timedelta(034108443000)

 

做这个项目真是有点日 了狗了
卧槽我居然把存储的时间弄错了,而没发现错在哪里    










原文地址:https://www.cnblogs.com/wuqingzangyue/p/5749617.html