一个普通例子:

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. 关于地址的理解 C++

    #include <iostream> using namespace std; int main(){ ; int* ptr; ptr=&a; cout<<& ...

  2. QT实现TCP通信服务器端和客户端(支持多个客户端)精简版

    上星期接了个私活,工期两星期,报酬3000,写一个小软件,采集定向网络上的数据,并进行双向通信,捣鼓了两天,终于把QT中tcp通信这块调通了,找过N多例子,绝大部分都是基本的一个服务端一个客户端通信的 ...

  3. 基于Visual C++2013拆解世界五百强面试题--题11-查找数字出现次数

    在排序数组中,找出给定数字出现的次数比如{ 1, 2, 2, 2, 3}中2的出现次数是3次 我们可使用二分查找发,分别查找出2最先出现的位置和最后出现的位置相减即可. 下面是上代码: #includ ...

  4. Baby Step Gaint Step

    给定同余式,求它在内的所有解,其中总是素数. 分析:解本同余式的步骤如下 (1)求模的一个原根 (2)利用Baby Step Giant Step求出一个,使得,因为为素数,所以有唯一解. (3)设, ...

  5. [置顶] 基于.NET的快速信息化系统开发框架 — RDIFramework.NET — 系统目录

    基于.NET的快速信息化系统开发整合框架 —RDIFramework.NET—系统目录 框架简单介绍 .NET快速开发整合框架(RDIFramework.NET),基于.NET的快速信息化系统开发.整 ...

  6. http协议与http代理

    TCP/IP协议族 TCP/IP(Transmission Control Protocol/InternetProtocol.传输控制协议/网际协议)是用于计算机通信的一个协议族. TCP/IP协议 ...

  7. LKD3

    第三章 进程1. Unix操作系统的抽象:进程和文件2. 进程包括两个因素:可运行代码,和资源(打开的文件,挂起的信号,内核内部数据,处理器状态,地址空间)3. 线程是进程中活动的对象.4. 线程有独 ...

  8. 记一次排查log4net 不输出日志的解决过程

    最近发现log4net 不输出日志了,重点排查几个地方,发现都没有问题. 1.[assembly: log4net.Config.XmlConfigurator(ConfigFile = " ...

  9. python中的迭代

    #迭代Python的for循环不仅可以用在list或tuple上,还可以作用在其他可迭代对象上. #list这种数据类型虽然有下标,但很多其他数据类型是没有下标的,但是,只要是可迭代对象,无论有无下标 ...

  10. C++中(int&)和(int)的区别

    在说这个问题之前,先说两个需要知道的背景知识: (1)语言的类型的强制转换不会修改原来的数据,会另外的开辟一个临时的或者程序中指定的空间来存储强制转换后的值. (2)C++引用的实现是在符号表中动了手 ...