-
Привет всем!
Иметь TsvectorField на вооружении очевидно удобно.
Для наследников мы, теоретически, получаем правильный SQL JOIN.
Застрял на реализации метода get_db_prep_lookup.
Заготовка для поля, аккумулирующего лексемы объекта, выглядит так:
Результирующий SQL должен содержать примерно следующее:from django.db.models import Field
class TsvectorField(Field):
"""
PostgreSQL tsvector field.
"""
def __init__(self, *args, **kwargs):
kwargs['editable'] = False
kwargs['null'] = True
super(TsvectorField, self).__init__(*args, **kwargs)
def db_type(self):
from django.conf import settings
if settings.DATABASE_ENGINE in ('postgresql_psycopg2', 'postgresql'):
return 'tsvector'
return None
def get_db_prep_lookup(self, lookup_type, value):
"""
Returns field's value prepared for database lookup.
"""
if lookup_type == 'tsquery':
return ['@@ plainto_tsquery(%s)' % value]
raise TypeError('Dude, TsvectorField has invalid lookup: %s' % lookup_type)
где 'firewall' – пример запроса, plainto_tsquery – встроенная функция postgres, @@ – оператор.... WHERE tsv @@ plainto_tsquery('firewall') ;
Метод get_db_prep_lookup в заготовке не работает:
FieldError: Join on field 'tsv' not permitted.
Соответственно django-код запроса выглядит как-то так:
Уважаемые коллеги, где копать-то?Trap.objects.filter(tsv__tsquery='firewall')
TrapClean.objects.filter(tsv__tsquery='switch')
django 1.0.x branch:
http://code.djangoproject.com/svn/django/branches/releases/1.0.X/
Код моделей на всякий случай:
Материал по теме:from django.db import models
from string import printable
from fields import TsvectorField
class TrapCommon(models.Model):
"""
Common SNMPTT data.
See http://www.snmptt.org/docs/snmptt.shtml#LoggingDatabase
"""
trapoid = models.CharField(max_length=255, blank=True, db_index=True)
enterprise = models.CharField(max_length=255, blank=True, db_index=True)
community = models.CharField(max_length=60, blank=True, db_index=True)
hostname = models.CharField(max_length=255, blank=True, db_index=True)
agentip = models.CharField(max_length=48, blank=True, db_index=True)
uptime = models.CharField(max_length=60, blank=True)
traptime = models.DateTimeField(db_index=True)
formatline = models.TextField(blank=True)
tsv = TsvectorField()
class Meta:
abstract = True
ordering = ('-traptime',)
get_latest_by = 'traptime'
def __unicode__(self):
fmt = ''.join([c for c in self.formatline if c in printable])
return '%s - %s - %s' % (self.traptime, self.hostname.split('.')[0], fmt)
class Trap(TrapCommon):
"""
Traps caught by SNMP Trap Translator.
"""
eventname = models.CharField(max_length=150, blank=True, db_index=True)
eventid = models.CharField(max_length=150, blank=True, db_index=True)
category = models.CharField(max_length=60, blank=True, db_index=True)
severity = models.CharField(max_length=60, blank=True, db_index=True)
class Meta(TrapCommon.Meta):
db_table = u'snmptt'
class TrapClean(Trap):
"""
Traps caught by SNMP Trap Translator and passed spam filter validation.
"""
class Meta(Trap.Meta):
verbose_name = u'SNMP Trap'
verbose_name_plural = u'SNMP Traps'
Введение в полнотекстовый поиск в PostgreSQL:
http://www.sai.msu.su/~megera/postgres/talks/fts_pgsql_intro.html
Заранее всем спасибо! -
Это нерешенный пока вопрос. Дело в том, что у Джанги захардкожено то, какие lookup-типы она может принимать, и какие SQL-операторы из них делать. И одного
get_db_prep_lookupтут совсем недостаточно. По сути он только умеет форматировать значения, участвующие в запросах, но не позволяет определять новый lookup-тип.Я как-то решил грубой силой с monkey-патчингом эту задачку на работе, чтобы можно было писать
.filter(time__period='today_future'). Пришлось написать свой менеджер, свой QuerySet, свой Query и свой WhereNode. Код, к сожалению, не под рукой сейчас... -
Найдено временное решение!
fields.py:
———————————-8<———————————-
———————————-8<———————————-from django.db.models import Field
class TsvectorField(Field):
"""
PostgreSQL tsvector field.
"""
def __init__(self, *args, **kwargs):
kwargs['editable'] = False
kwargs['null'] = True
super(TsvectorField, self).__init__(*args, **kwargs)
def db_type(self):
from django.conf import settings
if settings.DATABASE_ENGINE.startswith('postgres'):
return 'tsvector'
return None
В файле __init__.py (в той же директории):
———————————-8<———————————-
———————————-8<———————————-def fulltext_search_sql(self, field_name):
return ('%s @@ plainto_tsquery(%%s)' % field_name)
def fts_patch():
"""
Enables Full Text Searching in PostgreSQL 8.3+.
"""
from django.db.backends.postgresql_psycopg2.base import DatabaseOperations
DatabaseOperations.fulltext_search_sql = fulltext_search_sql
fts_patch() # apply patch
Соответственно работает так:
Подсмотрено здесь:qs = queryset.filter(tsv__search=terms)
http://www.djangosnippets.org/snippets/685/
Иван, спасибо: успокоил по поводу отсутствия правильного решения проблемы прямо сейчас. -
А! Вам повезло, что операция "search" в Джанге таки есть :-)

