Object Permission in Django

django

django 自己提供的 permission 系統是 "model permission"
那些 add, change, delete 的權限是認 model(也就是該 model 下的所有 objects)
因為這個 permission 系統是用在 admin 裡面的

如果要用 "object permission"
可以用 django-guardian
針對每個 object 設定不同的權限

ref:
https://docs.djangoproject.com/en/dev/topics/auth/default/#permissions-and-authorization
http://www.cnblogs.com/esperyong/archive/2012/12/20/2826690.html

django-guardian

如果是 superuser
對所有 permission 的 has_perm() 都會是 True

class Label(models.Model):
    """
    廠牌
    """

    user = models.ForeignKey(User, related_name='labels')
    name = models.CharField(_(u'name'), max_length=100)

    class Meta:
        verbose_name = pgettext_lazy(u'DPS model name', u'label')
        verbose_name_plural = pgettext_lazy(u'DPS model name', u'labels')
        permissions = (
            ('view_label', 'View label'),
        )

django 默認會幫每個 model 建立三種 permission(所謂的 codename)

  • add_modelname
  • change_modelname
  • delete_modelname
# permission format: app_label.codename
user.has_perm('sites.change_site')  # by django
user.has_perm('sites.change_site', site)  # by django-guadian

每個 model object 被建立之後是沒有 object permission 的

要手動建立
通常會透過 signal 的方式去做

from django.db.models.signals import post_save
from django.dispatch import receiver

from guardian.shortcuts import assign_perm

@receiver(post_save, sender=Label)
def create_label_permission(instance, **kwargs):
    if not kwargs['created']:
        return

    label = instance

    assign_perm('view_label', label.user, label)
    assign_perm('change_label', label.user, label)

get objects by permission

from guardian.shortcuts import get_objects_for_user

labels = get_objects_for_user(request.user, 'dps.view_label')

ref:
https://github.com/lukaszb/django-guardian
http://django-guardian.readthedocs.org/

coverage.py: Python code coverage

coveralls.io 跑 python project 的覆蓋率就是用 coverage.py
nose 也是用 coverage.py
基本上 python 社群幾乎都是用這個

ref:
http://nedbatchelder.com/code/coverage/
http://www.cnblogs.com/coderzh/archive/2009/12/01/1614874.html

Install

$ pip install coverage

Configuration

in .coveragerc

[run] 底下的 include 和 omit 是用來指定 filename pattern
而 source 是用來指定 package 或目錄

omit 是「忽略」的意思

ref:
http://nedbatchelder.com/code/coverage/config.html

Usage

# 默認會一併測試所有包含第三方 lib 在內的 Python 程式碼
$ coverage run test.py

# 你可以用 --source 指定只測試某個 packages 或目錄
$ coverage run --source=haul setup.py test
$ coverage run --source=haul tests/test.py

# show report in terminal
$ coverage report

# generate html report in the same dir
$ coverage html

ref:
http://nedbatchelder.com/code/coverage/cmd.html
http://nedbatchelder.com/code/coverage/source.html

Usage with nose

$ pip install nose nose-cov

# output terminal
$ nosetests --with-cov --cov haul tests/

# output html
$ nosetests --with-cov --cov-report html --cov haul tests/ 

Templates cache in Django

in settings.py

TEMPLATE_LOADERS = (
    ('django.template.loaders.cached.Loader', (
        'django.template.loaders.filesystem.Loader',
        'django.template.loaders.app_directories.Loader',
    )),
)

ref:
https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.loaders.cached.Loader

template fragment caching
https://docs.djangoproject.com/en/dev/topics/cache/#template-fragment-caching

cache template tag 會 cache 整個 block 的「內容」
第二個參數以後是 cache key 字串

{% load cache %}
{% cache 300 repost-card repost.id LANGUAGE_CODE %}

你可以用多個 context 變數來組合出 key
repost-card 相當於是 prefix 字串