настройка функциональности поиска полей для пользовательских полей модели Django - PullRequest
3 голосов
/ 14 мая 2011

У меня есть поле пользовательской модели YearWithSurenessField, которое представлено в python пользовательским типом данных YearWithSureness.Конструктор для YearWithSureness равен YearWithSureness(year='', is_certain=False), где year равен либо '', либо четырехзначному году (в виде строки), а is_certain является логическим значением, представляющим, уверен ли я, что данноегод правильный.Поля модели этого типа хранятся в моей базе данных в форме year / is_termin , например, "2008 / True", "2011 / False", "/ False" и т. Д.

КакНапример, в модели Member у меня есть поле grad_year = YearWithSurenessField(...), в котором хранится год выпуска участника, а также то, знаю ли я точно, что год, который я сохранил, правильный.

Что бы яЯ хотел бы иметь возможность использовать что-то вроде

Member.objects.filter(grad_year__year=2011)

, чтобы получить QuerySet всех Участников, чей grad_year равен либо «2011 / True», либо «2011 / False».Точно так же я хотел бы иметь возможность использовать что-то вроде

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

, чтобы получить QuerySet всех Участников, чей grad_year находится в диапазоне от 2000 до 2011 года, независимо от того, является ли 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):
        # ...

Ответы [ 3 ]

3 голосов
/ 15 декабря 2012

Вот что мне показалось полезным: Создание пользовательских полевых поисков в Django

Более гибкий способ сделать это - написать собственный QuerySet, а также собственный менеджер.Работа с кодом Озана:

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)
3 голосов
/ 14 мая 2011

Я не могу понять, зачем вам нужно такое настраиваемое поле. Насколько я вижу, «год» и «is_termin» идеально подходят для хранения в 2 отдельных поля. Таким образом, во-первых, поиск по диапазону года или года становится проще. Во-вторых, поиск также будет значительно более эффективным, особенно при наличии большого количества данных. И последнее, но не менее важное: вам больше не нужно беспокоиться о том, как правильно реализовать настраиваемое поле.

Поэтому я предлагаю вам объяснить фундаментальную причину, по которой вам нужно хранить эти два естественно разнородных типа данных в одном столбце таблицы базы данных. И, возможно, мы можем указать на более простой способ достижения ваших реальных целей.

0 голосов
/ 14 мая 2011

Вы пытались изменить поведение get_prep_lookup, чтобы оно возвращало только значение года, когда lookup_type == 'year'? Вы можете вернуть int (value.split ('/') [0])

Я не уверен, что реализация такого настраиваемого поля является лучшим вариантом, есть ли действительно веская причина, чтобы не разбивать значения на два отдельных поля?

...