2011-05-14 85 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)