orangle / blog

博客--自我学习监督
http://orangleliu.info
3 stars 0 forks source link

Django 开发积累 #4

Open orangle opened 8 years ago

orangle commented 8 years ago

记录下那些简单,又容易忘掉,并且有用的技巧等。

user 和 threading.local()

threading.local() 用来保存当前线程级别的变量,给人的感觉是就当前线程的全局变量,每个线程维持自己的拷贝。如果我想在django的一个请求处理中,任何位置获取user或者是request对象,如果采用一般的方式,就需要传递 request对象,或者解析出request中的内容,在传递。 如果使用 threading.local() 做一个middlewire,在请求进来的时候把request和user对象放到local中,那么在这个请求的处理函数中,直接就可以从local中得到这两个对象,不需要直接把他们传参到函数中。

说的有点绕人,看看代码比较容易明白,下面是几个开源项目用到的这个技巧

每次当你需要当前用户的时候 current_request() 就能轻松的得到了,而不需要通过参数来传递

# coding: utf-8

"""
    :copyleft: 2009-2011 by the django-tools team, see AUTHORS for more details.
    :license: GNU GPL v3 or above, see LICENSE for more details.
"""

from __future__ import absolute_import, division, print_function

try:
    from threading import local
except ImportError:
    from django.utils._threading_local import local

_thread_locals = local()

def get_current_request():
    """ returns the request object for this thread """
    return getattr(_thread_locals, "request", None)

def get_current_user():
    """ returns the current user, if exist, otherwise returns None """
    request = get_current_request()
    if request:
        return getattr(request, "user", None)

class ThreadLocalMiddleware(object):
    """ Simple middleware that adds the request object in thread local storage."""
    def process_request(self, request):
        _thread_locals.request = request

    def process_response(self, request, response):
        if hasattr(_thread_locals, 'request'):
            del _thread_locals.request
        return response
orangle commented 8 years ago

数据库 migrate

对于某些app已经存在表和数据了,但是没有初始化 migrate, 会报错 django.db.utils.OperationalError: (1050, "Table 'device' already exists")

解决方案

python manage.py migrate --fake msc
orangle commented 8 years ago

Model设计Tips

price = models.DecimalField(max_digits=16, decimal_places=2, default=0)
在sql中保证原子性,还有精度转化的问题

经验参考 django-mysql 中的金钱计算事务处理

orangle commented 8 years ago

QuerySet

.iterator()

查询结果的遍历,一般会这样(方法一)

for i in User.objects.all():
    do something

也可能这样

for i in User.objects.all().iterator():
    do somethings

Evaluates the QuerySet (by performing the query) and returns an iterator (see PEP 234) over the results. A QuerySet typically caches its results internally so that repeated evaluations do not result in additional queries. In contrast, iterator() will read results directly, without doing any caching at the QuerySet level (internally, the default iterator calls iterator() and caches the return value). For a QuerySet which returns a large number of objects that you only need to access once, this can results in better performance and a significant reduction in memory.

.iterator() ,每次会直接查询DB,不会做cache,对于有大量记录要查询,并且只用一次的情形比较适用。

QuerySet 的 cache机制

orangle commented 8 years ago

Admin site 使用

在model的 Meta Class中添加设置

class Student(models.Model):
    ....

    class Meta:
        verbose_name = "学生"   
        verbose_name_plural = "学生"  #复数形式,如果只定义上面一项,那么objects 的地方会显示成 学生s
class TaskTemplateAdmin(admin.ModelAdmin):
    list_display = ("name", "tanent_type", 'alias')

    def tanent_type(self, obj):
        return "%s-%s" % (obj.tenant_id, 
                          u"公共模板" if obj.tenant_id == 0 else u"私有模板")

    tanent_type.short_description = u"模板属性"
from django import forms

class TaskPluginForm(forms.ModelForm):
    functiondesc = forms.CharField(widget=forms.Textarea, label=u"功能说明") 
    paramsdesc = forms.CharField(widget=forms.Textarea, label=u"参数说明")

    class Meta:
        model = TaskPlugin
        fields = '__all__'

class TaskPluginAdmin(admin.ModelAdmin):
    form = TaskPluginForm

admin.site.register(TaskPlugin, TaskPluginAdmin)
orangle commented 8 years ago

Test 测试相关

  1. django1.7 以后把south整合到django里面,如果使用mysql来做为test的数据库,就会自动migrate,这样比较讨厌,怎么禁止 test时候migrate呢

参考 disable-migrations-when-running-unit-tests-in-django-1-7

个人觉得下面这个方法挺实用的, test 的settings里面加上

MIGRATION_MODULES = {
    app[app.rfind('.') + 1:]: 'my_app.migrations_not_used_in_tests'
    for app in INSTALLED_APPS
}
orangle commented 7 years ago

Template 模版

{% if forloop.counter0|divisibleby:"2" %}
         <div class="row">
{% endif %}