In my Django model I've created custom MyIPAddressField which is stored as integer in mysql backend. To do that I've implemented to_python, get_db_prep_value, get_iternal_type (returns PositiveIntegerField) and formfield methods (uses stock IPAddressField as form_class).
在我的Django模型中,我创建了自定义MyIPAddressField,它在mysql后端存储为整数。为此,我实现了to_python,get_db_prep_value,get_iternal_type(返回PositiveIntegerField)和formfield方法(使用stock IPAddressField作为form_class)。
The only problem is field lookup in cases like builtin search in ModelAdmin. So, the question is how to implement get_db_prep_lookup to perform string-based lookup types like 'contains', 'regex', 'startswith', 'endswith'?
唯一的问题是在ModelAdmin中内置搜索的情况下进行字段查找。那么,问题是如何实现get_db_prep_lookup来执行基于字符串的查找类型,如'contains','regex','startswith','endswith'?
Mysql has special function inet_ntoa() but I don't know how to instruct ORM to use it in admin search queries. For example: SELECT inet_ntoa(ip_address) as ip FROM table WHERE ip LIKE '%search_term%'. Why custom fields perform type casting on python side but not on database side?
Mysql有特殊功能inet_ntoa()但我不知道如何指示ORM在管理搜索查询中使用它。例如:SELECT inet_ntoa(ip_address)as ip FROM table WHERE ip LIKE'%search_term%'。为什么自定义字段在python端执行类型转换而不在数据库端执行?
EDIT1: probably there is another way to solve search problem - don't transform integer column to string, but instead split search argument into subnet/mask and perform some binary math to compare them against integer IP value.
EDIT1:可能有另一种解决搜索问题的方法 - 不要将整数列转换为字符串,而是将搜索参数拆分为子网/掩码并执行一些二进制数学运算以将它们与整数IP值进行比较。
EDIT2: this is my code so far:
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)
But when I use admin changelist search box, I get error "Can not resolve keyword 'fakeip' into field. Choices are: ip, id". Is it possible to fool Django and make it think that fakeip is a real field?
但是当我使用管理员更改列表搜索框时,我收到错误“无法解析关键字'fakeip'到字段中。选项是:ip,id”。是否有可能欺骗Django并让它认为fakeip是一个真实的领域?
Using standard IPAddressField (string based) is not appropriate for my needs, as well as switching to Postgres where it stored in proper format.
使用标准IPAddressField(基于字符串)不适合我的需要,也不适合切换到以适当格式存储的Postgres。
Also I've looked to Django admin internals (options.py and views/main.py), and I see no easy way to customize ChangeList class or search mechanics without massive copy/pasting. I thought that Django admin is more powerful than it is.
另外我看过Django admin internals(options.py和views / main.py),我认为没有简单的方法可以自定义ChangeList类或搜索机制而无需大量复制/粘贴。我认为Django管理员比它更强大。
1 个解决方案
#1
You could instruct the ORM to add an extra field to your SQL queries, like so:
您可以指示ORM向SQL查询添加额外的字段,如下所示:
IPAddressModel.objects.extra(select={'ip': "inet_ntoa(ip_address)"})
This adds SELECT inet_ntoa(ip_address) as ip
to the query and a field ip
to your objects. You can use the new synthesized field in your WHERE clause.
这会将SELECT inet_ntoa(ip_address)作为ip添加到查询中,并将字段ip添加到对象中。您可以在WHERE子句中使用新的合成字段。
Are you sure you don't really want something like WHERE (ip_address & 0xffff0000) = inet_aton('192.168.0.0')
? Or do you really want to find all ip addresses in your log that contain the number 119
somewhere?
你确定你真的不想要像WHERE(ip_address&0xffff0000)= inet_aton('192.168.0.0')这样的东西吗?或者你真的想在日志中找到包含号码119的所有IP地址吗?
If suffix
is the /24 from CIDR notation:
如果后缀是来自CIDR表示法的/ 24:
mask = 0xffffffff ^ 0xffffffff >> suffix
Add to the WHERE clause:
添加到WHERE子句:
(ip_address & mask) = (inet_aton(prefix) & mask)
#1
You could instruct the ORM to add an extra field to your SQL queries, like so:
您可以指示ORM向SQL查询添加额外的字段,如下所示:
IPAddressModel.objects.extra(select={'ip': "inet_ntoa(ip_address)"})
This adds SELECT inet_ntoa(ip_address) as ip
to the query and a field ip
to your objects. You can use the new synthesized field in your WHERE clause.
这会将SELECT inet_ntoa(ip_address)作为ip添加到查询中,并将字段ip添加到对象中。您可以在WHERE子句中使用新的合成字段。
Are you sure you don't really want something like WHERE (ip_address & 0xffff0000) = inet_aton('192.168.0.0')
? Or do you really want to find all ip addresses in your log that contain the number 119
somewhere?
你确定你真的不想要像WHERE(ip_address&0xffff0000)= inet_aton('192.168.0.0')这样的东西吗?或者你真的想在日志中找到包含号码119的所有IP地址吗?
If suffix
is the /24 from CIDR notation:
如果后缀是来自CIDR表示法的/ 24:
mask = 0xffffffff ^ 0xffffffff >> suffix
Add to the WHERE clause:
添加到WHERE子句:
(ip_address & mask) = (inet_aton(prefix) & mask)