2011-05-14 55 views
3

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

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

我想什么,能够做的是使用像

Member.objects.filter(grad_year__year=2011) 

收获的人,其grad_year要么是“2011 /真”或“2011 /假”所有成员的QuerySet。同样,我希望能够使用像

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

收获的人,其grad_year是在2000年的范围内通2011不论是否grad_year.is_certain是真还是假所有成员的QuerySet

这可能吗?我知道我可以使用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): 
     # ... 
+0

您应该只使用接受ranges参数的自定义管理器。 – 2011-05-14 01:11:15

回答

3

我不明白为什么你需要有这样的自定义字段。据我所知,'year'和'is_certain'非常适合存储在2个分隔的字段中。通过这样做,首先,按年份或年份范围搜索更容易。其次,搜索也将更有效率,特别是当数据量很大时。最后但并非最不重要的一点是,您不必费心如何正确实施定制领域了。

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

0

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

我不知道实现这样的自定义字段是最好的选择,是否有一个很好的理由,以避免将值分成两个分隔字段?

3

这里的东西,我发现有用: Creating custom Field Lookups in Django

更灵活的方式来做到这一点是写一个自定义查询集以及自定义的经理。从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)