В моей модели Django я создал пользовательский MyIPAddressField, который хранится как целое число в бэкэнде mysql. Для этого я реализовал методы to_python, get_db_prep_value, get_iternal_type (возвращает PositiveIntegerField) и методы fieldfield (в качестве form_class используется фондовый IPAddressField).
Единственная проблема - поиск полей в случаях, таких как встроенный поиск в ModelAdmin. Итак, вопрос заключается в том, как реализовать get_db_prep_lookup для выполнения типов поиска на основе строк, таких как «contains», «regex», «setswith», «заканчивается с»?
Mysql имеет специальную функцию inet_ntoa (), но я не знаю, как указать ORM, чтобы использовать ее в поисковых запросах администратора. Например: ВЫБЕРИТЕ inet_ntoa (ip_address) как ip ИЗ таблицы, ГДЕ ip НРАВИТСЯ "% search_term%". Почему настраиваемые поля выполняют приведение типов на стороне Python, а не на стороне базы данных?
EDIT1: возможно, существует другой способ решения проблемы поиска - не преобразуйте столбец целых чисел в строку, а вместо этого разбейте аргумент поиска на подсеть / маску и выполните некоторые двоичные вычисления, чтобы сравнить их с целочисленным значением IP.
EDIT2: это мой код до сих пор:
models.py:
class MyIPField(models.Field):
empty_strings_allowed = False
__metaclass__ = models.SubfieldBase
def get_db_prep_value(self, value):
if value is None: return None
return unpack('!L', inet_aton(value))[0]
def get_internal_type(self):
return "PositiveIntegerField"
def to_python(self, value):
if type(value).__name__ in ('NoneType', 'unicode'): return value
return inet_ntoa(pack('!L', value))
def formfield(self, **kwargs):
defaults = {'form_class': IPAddressField}
defaults.update(kwargs)
return super(MyIPField, self).formfield(**defaults)
class MyManager(models.Manager):
def get_query_set(self):
return super(MyManager, self).get_query_set().extra(select={'fakeip': "inet_ntoa(ip)"})
class Address(models.Model):
# ... other fields are skipped (Note: there was several foreign keys)
ip = MyIPField(u"IP address", unique=True)
objects = AddressManager()
def __unicode__(self):
return self.ip
admin.py:
class AddressAdmin(admin.ModelAdmin):
list_display = ('address',) # ... some fields are skipped from this example
list_display_links = ('address',)
search_fields = ('fakeip', )
admin.site.register(Address, AddressAdmin)
Но когда я использую окно поиска по списку изменений администратора, я получаю сообщение об ошибке «Не удается разрешить ключевое слово« fakeip »в поле. Варианты: ip, id». Можно ли обмануть Джанго и заставить его думать, что fakeip - это настоящее поле?
Использование стандартного IPAddressField (на основе строк) не подходит для моих нужд, а также переключение на Postgres, где он хранится в правильном формате.
Также я посмотрел на внутренние компоненты администратора Django (options.py и views / main.py) и не вижу простого способа настроить класс ChangeList или механизм поиска без массового копирования / вставки. Я думал, что админ Django более мощный, чем он.