跳转到主要内容

Django的ReverseUnique字段实现

项目描述

Build Status Coverage Status

Django的ReverseUnique模型字段实现

ReverseUnique字段可以用于从ForeignKey的反向访问单个模型实例。本质上,ReverseUnique可以用于在正常ForeignKey的反向方向上生成OneToOneField的行为。想法是在遍历外键的反向方向时添加一个唯一的过滤条件。

要使用反向唯一,您需要一个反向边的唯一约束,或者知道反向边只有一个实例可以匹配。

示例

看到实际的用例总是很好的。在这个例子中,我们将用具有时间依赖性的薪水来模拟员工。这个用例可以建模为

class Employee(models.Model):
    name = models.TextField()

class EmployeeSalary(models.Model):
    employee = models.ForeignKey(Employee, related_name='employee_salaries')
    salary = models.IntegerField()
    valid_from = models.DateField()
    valid_until = models.DateField(null=True)

可以保存像“Anssi从2000-1-1到2009-12-31有10€的薪水,从2010-1-1到无穷大(在模型中建模为None)的薪水11€”这样的数据。

不幸的是,当使用这些模型时,直接获取员工及其薪水以显示给用户并不简单。可以通过遍历员工的全部薪水并检查哪个EmployeeSalaries当前有效来实现这一点。然而,这种方法有几个缺点

  • 在列表视图中表现不佳

  • 最重要的是,执行涉及员工当前工资的查询是不可能的。例如,获取前10位最高薪员工或员工的平均工资,在单次查询中是无法实现的。

Django-reverse-unique拯救了我们!让我们将Employee模型改为

from datetime import datetime
class Employee(models.Model):
    name = models.TextField()
    current_salary = models.ReverseUnique(
        "EmployeeSalary",
        filter=Q(valid_from__gte=datetime.now) &
               (Q(valid_until__isnull=True) | Q(valid_until__lte=datetime.now))
    )

现在我们可以简单地发出如下查询

Employee.objects.order_by('current_salary__salary')[0:10]

或者

Employee.objects.aggregate(avg_salary=Avg('current_salary__salary'))

那里发生了什么?我们添加了一个ReverseUnique字段。该字段是EmployeeSalary.employee外键的反向,并附加了一个限制,即关系必须在执行查询的当前时刻有效。第一个“EmployeeSalary”参数指的是EmployeeSalary模型(我们必须使用字符串,因为EmployeeSalary模型是在Employee模型定义之后定义的)。filter参数是一个Q对象,可以引用远程模型的字段。

Django应用程序的另一个常见问题是如何存储模型翻译。存储问题可以使用django-reverse-unique来解决。以下是一个针对该用例的完整示例。

from django.db import models
from reverse_unique import ReverseUnique
from django.utils.translation import get_language, activate

class Article(models.Model):
    active_translation = ReverseUnique("ArticleTranslation",
                                       filters=Q(lang=get_language))

class ArticleTranslation(models.Model):
    article = models.ForeignKey(Article)
    lang = models.CharField(max_length=2)
    title = models.CharField(max_length=100)
    body = models.TextField()

    class Meta:
        unique_together = ('article', 'lang')

activate("fi")
objs = Article.objects.filter(
    active_translation__title__icontains="foo"
).select_related('active_translation')
# Generated query is
#    select article.*, article_translation.*
#      from article
#      join article_translation on article_translation.article_id = article.id
#                               and article_translation.lang = 'fi'
# If you activate "en" instead, the lang is changed.
# Now you can access objs[0].active_translation without generating more
# queries.

同样,可以获取酒店房间等的当前有效预订等。

安装

ReverseUnique的要求是Django 1.6+。您需要将reverse_unique目录放置在Python路径中,然后就像在上面的示例中那样使用它。测试(reverse_unique/tests.py)包含一些额外的示例。安装的最简单方法是

pip install -e git://github.com/akaariai/django-reverse-unique.git#egg=reverse_unique

测试

您需要安装支持的Django版本。转到testproject目录并运行

python manage.py test reverse_unique

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。

源分布

django-reverse-unique-charettes-1.1.tar.gz (9.4 kB 查看哈希值)

上传时间

构建分布

django_reverse_unique_charettes-1.1-py2.py3-none-any.whl (11.3 kB 查看哈希值)

上传时间 Python 2 Python 3

支持者

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面