Как найти настраиваемое поле IP-адреса, хранящееся как целое число в Django-admin? - PullRequest
3 голосов
/ 12 февраля 2009

В моей модели 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 более мощный, чем он.

1 Ответ

2 голосов
/ 17 февраля 2009

Вы можете указать ORM добавить дополнительное поле к вашим запросам SQL, например:

IPAddressModel.objects.extra(select={'ip': "inet_ntoa(ip_address)"})

Это добавляет SELECT inet_ntoa(ip_address) as ip к запросу и поле ip к вашим объектам. Вы можете использовать новое синтезированное поле в предложении WHERE.

Вы уверены, что действительно не хотите что-то вроде WHERE (ip_address & 0xffff0000) = inet_aton('192.168.0.0')? Или вы действительно хотите найти в своем журнале все ip-адреса, содержащие где-то число 119?

Если suffix - это / 24 из нотации CIDR:

mask = 0xffffffff ^ 0xffffffff >> suffix

Добавить к предложению WHERE:

(ip_address & mask) = (inet_aton(prefix) & mask)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...