一个普通例子:

todos = Todo.objects.filter(owner=request.user).filter(is_done=False).filter(priority=1)

弊端:

首先,代码冗长,正式的项目中,将会更加复杂。

其次,泄露实现细节。比如代码中的is_done是BooleanField,如果改变了他的类型,代码就不能用了。

或者就是,意图不清晰,很难理解。

最后,使用中会有重复。

Django 有两个关系密切的与表级别操作相关的构图:managers 和 querysets

manager(django.db.models.manager.Manager的一个实例)被描述成 “通过查询数据库提供给Django的插件”。Manager是表级别功能的通往ORM大门。每一个model都有一个默认的manager,叫做objects。

Quesyset (django.db.models.query.QuerySet) 是“数据库中objects的集合”。本质上是一个SELECT查询,也可以使用过滤,排序等(filtered,ordered),来限制或者修改查询到的数据。用来 创建或操纵 django.db.models.sql.query.Query实例,然后通过数据库后端在真正的SQL中查询。

Manager接口就是个谎言。

QuerySet方法是可链接的。每一次调用QuerySet的方法(如:filter)都会返回一个复制的queryset等待下一次的调用。这也是Django ORM 流畅之美的一部分。

但是当Model.objects 是一个 Manager时,就出现问题了。我们需要调用objects作为开始,然后链接到结果的QuerySet上去。

那么Django又是如何解决呢?

接口的谎言由此暴露,所有的QuerySet 方法基于Manager。

更多:http://www.oschina.net/translate/higher-level-query-api-django-orm

models.py:

from model_utils.managers import PassThroughManager

class NewsQuerySet(models.query.QuerySet):
    def display(self):
        return self.filter(status=1).order_by('-create_time')

def exece(self, question_id):
        return self.exclude(pk=question_id).display()

class News(models.Model):
    STATUS = (
        (0, u'不展示'),
        (1, u'展示'),
    )
    title = models.CharField(max_length=20)
    author = models.CharField(max_length=20)
    img = models.ImageField(upload_to='upload/news/%Y/%m/%d', blank=True, null=True)
    content = models.TextField(blank=True, null=True)
    create_time = models.DateTimeField(auto_now_add=True)
    source = models.CharField(max_length=20)
    status = models.IntegerField(default=1, null=True, blank=True, choices=STATUS)

objects = PassThroughManager.for_queryset_class(NewsQuerySet)()

views.py:

原先:

q = News.objects.all().exclude(id=news_id).filter(status=1).order_by('-create_time')
现在:

q = News.objects.exece(news_id)

在视图和其他高级应用中使用源生的ORM查询代码不是很好的主意。而是用django-model-utils中的PassThroughManager将我们新加的自定义QuerySet API加进你的模型中,这能给你以下好处:

啰嗦代码少,并且更健壮。
    增加DRY,增强抽象级别。

  将所属的业务逻辑推送至对应的域模型层。


2015.1.6

StatusField

from model_utils.fields import StatusField
from model_utils import Choices class Article(models.Model):
STATUS = Choices('draft', 'published')
# ...
status = StatusField() from model_utils.fields import StatusField
from model_utils import Choices class Article(models.Model):
ANOTHER_CHOICES = Choices('draft', 'published')
# ...
another_field = StatusField(choices_name='ANOTHER_CHOICES')

MonitorField

from model_utils.fields import MonitorField, StatusField

class Article(models.Model):
STATUS = Choices('draft', 'published') status = StatusField()
status_changed = MonitorField(monitor='status') from model_utils.fields import MonitorField, StatusField class Article(models.Model):
STATUS = Choices('draft', 'published') status = StatusField()
published_at = MonitorField(monitor='status', when=['published'])

SplitField

from django.db import models
from model_utils.fields import SplitField class Article(models.Model):
title = models.CharField(max_length=100)
body = SplitField() content:
The full field contents.
excerpt:
The excerpt of content (read-only).
has_more:
True if the excerpt and content are different, False otherwise. >>> a = Article.objects.all()[0]
>>> a.body.content
u'some text\n\n<!-- split -->\n\nmore text'
>>> a.body.excerpt
u'some text\n'
>>> unicode(a.body)
u'some text\n\n<!-- split -->\n\nmore text' By default, SplitField looks for the marker <!-- split --> alone on a line and takes everything before that marker as the excerpt. This marker can be customized by setting the SPLIT_MARKER setting. If no marker is found in the content, the first two paragraphs (where paragraphs are blocks of text separated by a blank line) are taken to be the excerpt. This number can be customized by setting the SPLIT_DEFAULT_PARAGRAPHS setting.

 Choices

from model_utils import Choices

GENERIC_CHOICES = Choices((0, 'draft', _('draft')), (1, 'published', _('published')))

class Article(models.Model):
STATUS = GENERIC_CHOICES + [(2, 'featured', _('featured'))]
status = models.IntegerField(choices=STATUS, default=STATUS.draft)

 Field Tracker

from django.db import models
from model_utils import FieldTracker class Post(models.Model):
title = models.CharField(max_length=100)
body = models.TextField() tracker = FieldTracker() >>> a = Post.objects.create(title='First Post')
>>> a.title = 'Welcome'
>>> a.tracker.previous('title') >>> a = Post.objects.create(title='First Post')
>>> a.title = 'Welcome'
>>> a.tracker.has_changed('title')
True
>>> a.tracker.has_changed('body')
False >>> a = Post.objects.create(title='First Post')
>>> a.title = 'Welcome'
>>> a.body = 'First post!'
>>> a.tracker.changed()
{'title': 'First Post', 'body': ''}
from django.db import models
from model_utils import FieldTracker class Post(models.Model):
title = models.CharField(max_length=100)
body = models.TextField() title_tracker = FieldTracker(fields=['title']) >>> a = Post.objects.create(title='First Post')
>>> a.body = 'First post!'
>>> a.title_tracker.changed()
{'title': None}

https://django-model-utils.readthedocs.org/en/latest/models.html

django-model-utils的更多相关文章

  1. django.db.utils.ProgrammingError: (1146, "Table 'db_gold.user_ip_info' doesn't exist") RuntimeError: Model class scanhosts.models.HostLoginInfo doesn't declare an explicit app_label and isn't in an a

    Error Msg 创建了一个apps的目录将所有app放入apps文件中, 将apps路径加入sys.path中:sys.insert(0, os.path.join(BASE_DIR, " ...

  2. 【AMAD】django-model-utils -- Django model使用的mixin和utils

    动机 简介 个人评分 动机 为django model系统提供一些可重用的mixin和utils. 简介 django-model-utils1为Django Model提供了下嘛几种分类的utils ...

  3. 【转】Django Model field reference学习总结

    Django Model field reference学习总结(一) 本文档包含所有字段选项(field options)的内部细节和Django已经提供的field types. Field 选项 ...

  4. django.db.utils.ProgrammingError: 1146 的解决办法

    在models中设置完数据库相关的东西后执行命令 python manage.py makemigrations 此处无错误 再次执行 python manage.py migrate 发生报错 错误 ...

  5. Django Model field reference

    ===================== Model field reference ===================== .. module:: django.db.models.field ...

  6. Django Model Form

    ModelForm ModelForm结合了Form和Model,将models的field类型映射成forms的field类型,复用了Model和Model验证, 写更少的代码,并且还实现了存储数据 ...

  7. django.db.utils.OperationalError: (1071, 'Specified key was too long; max key length is 767 bytes')

    环境介绍 Django (2.1)  Python 3.5.5 mysqlclient (1.4.2.post1) Mysql 5.6.28 RHEL 7.3 在migrate时候报错 model代码 ...

  8. 在执行migrate的时候出现问题(错误见末尾): django.db.utils.OperationalError: (1045, "Access denied for user ‘ODBC‘@‘localho st‘ (using password: YES)")

    Python框架之Django的数据库 在执行migrate的时候出现问题(错误见末尾) django.db.utils.OperationalError: (1045, "Access d ...

  9. Django model总结(上)

    Django model是django框架中处于比较核心的一个部位,准备分三个博客从不同的方面分别进行阐述,本文为<上篇>,主要对[a]Model的基本流程,比如它的创建,迁移等:默认行为 ...

  10. Django model字段类型清单

    转载:<Django model字段类型清单> Django 通过 models 实现数据库的创建.修改.删除等操作,本文为模型中一般常用的类型的清单,便于查询和使用: AutoField ...

随机推荐

  1. python初探-copy

    python中,数据的拷贝有以下三种形式:赋值.浅copy和深copy.根据类型的不同,可以把数据分成以下两类:字符串和数字为一类,其他(包括列表.元祖.字典...)为一类. 在python中有池的概 ...

  2. Browserify: 使nodejs模块可以在浏览器下使用

    Browserify:浏览器加载Node.js模块--------------------------------------------------随着JavaScript程序逐渐模块化,在ECMA ...

  3. TreeView控件例子

    XmL文件代码: <?xml version="1.0" encoding="utf-8" ?> <Area> <Province ...

  4. 使用回调接口实现ActiveX控件和它的容器程序的通讯

    本文阅读基础:有一定的C++基础知识(了解继承.回调函数),对MFC的消息机制有一定了解,对COM的基础知识有一定了解,对ActiveX控件有一定了解. 一. 前言 ActiveX控件和它的容器程序如 ...

  5. HDU 2178 猜数字

    题解:设猜到的最大的数是h,在1到h间,你最多只要猜log2(h)+1(取整)次,所以易知==>h=2^m-1.即猜m次,能猜到的最大的数为2^m-1. #include <cstdio& ...

  6. 关于Unix时间戳

    如何在不同编程语言中获取现在的Unix时间戳(Unix timestamp)? Java time JavaScript Math.round(new Date().getTime()/1000)ge ...

  7. JavaBean讲解 规范

    一:JavaBean定义 JavaBean是一种可重复使用.跨平台的软件组件.JavaBean可分为两种:一种是有用户界面(UI,User Interface)的JavaBean,例如NetBean中 ...

  8. SGU 202 The Towers of Hanoi Revisited (DP+递归)

    转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove 题意 :n个圆盘,m个柱子的汉诺塔输出步骤. ht ...

  9. Oracle包Package调用Package

    Package左侧文件: create or replace package CALL_DETAILS is strdatarange varchar2(1) := '1'; numrow_num n ...

  10. php的迭代器

    接口Iterator 主要需要实现的方法: abstract public mixed current ( void ) abstract public scalar key ( void ) abs ...