【问题标题】:customizing functionality of field lookups for custom Django model fields自定义 Django 模型字段的字段查找的自定义功能
【发布时间】:2011-05-14 00:40:13
【问题描述】:

我有一个自定义模型字段 YearWithSurenessField,它在 python 中由自定义数据类型 YearWithSureness 表示。 YearWithSureness 的构造函数是 YearWithSureness(year='', is_certain=False),其中 year'' 或四位数年份(作为字符串),is_certain 是一个布尔值,表示我是否确定给定的年份是正确的。这种类型的模型字段以 year/is_certain 的形式存储在我的数据库中,例如“2008/True”、“2011/False”、“/False”等

例如,在 Member 模型中,我有一个字段 grad_year = YearWithSurenessField(...) 存储成员的毕业年份以及我是否确定我存储的年份是正确的。

我想做的是使用类似的东西

Member.objects.filter(grad_year__year=2011)

获取所有 grad_year 为“2011/True”或“2011/False”的成员的QuerySet。同样,我希望能够使用类似的东西

Member.objects.filter(grad_year__range=(2000, 2011))

获取所有 grad_year 在 2000 到 2011 范围内的成员的 QuerySet,无论 grad_year.is_certain 是真还是假。

这可能吗?我知道我可以使用 Member.objects.filter(grad_year__contains="2011") 来获得第一个结果,但我希望能够使用 __year。

这里是相关的类,去掉了多余的代码:

class YearWithSureness(object):
    def __init__(self, year='', is_certain=False):
        # ...

    def __str__(self):
        return "{year}/{is_certain}".format(year=self.year,
                                            is_certain=self.is_certain)

class YearWithSurenessField(models.Field):
    __metaclass__ = models.SubfieldBase

    def __init__(self, *args, **kwargs):
        # ...

    def to_python(self, value):
        # ...

    def get_prep_value(self, value):
        # ...

    def get_prep_lookup(self, lookup_type, value):
        if lookup_type in ('month', 'day'):
            raise TypeError('Lookup type {0} not supported.'.format(lookup_type))
        else:
            return super(YearWithSurenessField, self).get_prep_lookup(lookup_type, value)

    def value_to_string(self, obj):
        # ...

【问题讨论】:

  • 您应该只使用接受范围参数的自定义管理器。

标签: python django django-models django-queryset


【解决方案1】:

以下是我发现有用的内容: Creating custom Field Lookups in Django

更灵活的方法是编写自定义 QuerySet 以及自定义管理器。使用 ozan 的代码:

class PersonQuerySet(models.query.QuerySet):
    def in_age_range(self, min, max):
        return self.filter(age__gte=min, age__lt=max)

class PersonManager(models.Manager):
    def get_query_set(self):
         return PersonQuerySet(self.model)

    def __getattr__(self, name):
        return getattr(self.get_query_set(), name)

class Person(models.Model):
    age = #...
    objects = PersonManager()

这允许您链接自定义查询。所以这两个查询都是有效的:

Person.objects.in_age_range(20,30)
Person.objects.exclude(somefield = some_value).in_age_range(20, 30)

【讨论】:

    【解决方案2】:

    我不明白你为什么需要这样一个自定义字段。据我所知,'year' 和 'is_certain' 非常适合存储在 2 个单独的字段中。通过这样做,首先,按年份或年份范围进行搜索更容易。其次,搜索也将显着提高效率,尤其是在有大量数据的情况下。最后但同样重要的是,您无需再为如何正确实现自定义字段而烦恼。

    因此,我建议您解释为什么需要将这两种自然不同类型的数据存储到数据库表中的单个列中的根本原因。也许我们可以指出一种更简单的方法来实现您的真正目标。

    【讨论】:

      【解决方案3】:

      您是否尝试过更改 get_prep_lookup 的行为以在 lookup_type == 'year' 时仅返回年份值?你可以返回 int(value.split('/')[0])

      我不确定实现这样的自定义字段是否是最佳选择,是否有充分的理由避免将值拆分为两个单独的字段?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-12-11
        • 2015-04-16
        • 2022-01-24
        • 1970-01-01
        • 2021-04-15
        • 1970-01-01
        • 2021-10-19
        相关资源
        最近更新 更多