In a Django application, I'm trying to access an existing MySQL database created with Hibernate (a Java ORM). I reverse engineered the model using:
在Django应用程序中,我正在尝试访问使用Hibernate(Java ORM)创建的现有MySQL数据库。我使用以下方法反向设计模型:
$ manage.py inspectdb > models.py
This created a nice models file from the Database and many things were quite fine. But I can't find how to properly access boolean fields, which were mapped by Hibernate as columns of type BIT(1).
这从数据库创建了一个很好的模型文件,很多东西都很好。但我找不到如何正确访问布尔字段,这些字段由Hibernate映射为BIT(1)类型的列。
The inspectdb script by default creates these fields in the model as TextField and adds a comment saying that it couldn't reliably obtain the field type. I changed these to BooleanField but and opened my model objects using the admin, but it doesn't work (the model objects always fetch a value of true for these fields). Using IntegerField won't work as well (e.g. in the admin these fields show strange non-ascii characters).
默认情况下,inspectdb脚本在模型中将这些字段创建为TextField,并添加注释,表示无法可靠地获取字段类型。我将这些更改为BooleanField但是使用admin打开了我的模型对象,但它不起作用(模型对象总是为这些字段获取值true)。使用IntegerField也不会起作用(例如在管理员这些字段中显示奇怪的非ascii字符)。
Any hints of doing this without changing the database? (I need the existing Hibernate mappings and Java application to still work with the database).
在不更改数据库的情况下执行此操作的任何提示? (我需要现有的Hibernate映射和Java应用程序仍然可以使用数据库)。
Further info: I left these fields as BooleanField and used the interactive shell to look at the fetched values. They are returned as '\x00' (when Java/Hibernate value is false) and '\x01' (when true), instead of Python boolean values "True" and "False".
更多信息:我将这些字段保留为BooleanField,并使用交互式shell查看获取的值。它们返回为'\ x00'(当Java / Hibernate值为false时)和'\ x01'(当为true时),而不是Python布尔值“True”和“False”。
>>> u = AppUser.objects.all()[0]
>>> u.account_expired
'\x00'
>>> u.account_enabled
'\x01'
Where the model includes:
模型包括:
class AppUser(models.Model):
account_expired = models.BooleanField()
account_enabled = models.BooleanField(blank=True)
# etc...
5 个解决方案
#1
2
I guess that only way is to subclass, say, BooleanField, and override to_python/get_prep_value functions, so the field works seamlessly with django and your db.
我想唯一的方法是子类,比如BooleanField,并覆盖to_python / get_prep_value函数,因此该字段可以与django和你的数据库无缝协作。
#2
10
This is the detailed solution from Dmitry's suggestion:
这是德米特里建议的详细解决方案:
My derived field class:
我派生的字段类:
class MySQLBooleanField(models.BooleanField):
__metaclass__ = models.SubfieldBase
def to_python(self, value):
if isinstance(value, bool):
return value
return bytearray(value)[0]
def get_db_prep_value(self, value):
return '\x01' if value else '\x00'
Fields in my model:
我的模型中的字段:
account_enabled = MySQLBooleanField()
account_expired = MySQLBooleanField()
#3
2
I had to deal the same problem, but rather than subclassing the field, I extended the MySQL backend to understand the Hibernate way. It's only a few lines of code and has the advantage that the DB introspection can be made to work correctly, as well.
我不得不处理同样的问题,但是我没有对字段进行子类化,而是扩展了MySQL后端以了解Hibernate的方式。它只有几行代码,并且具有可以使DB内省正常工作的优点。
See it here.
在这里看到它。
hibernateboolsbackend / backends / mysql / base.py
# We want to import everything since we are basically subclassing the module.
from django.db.backends.mysql.base import *
django_conversions.update({
FIELD_TYPE.BIT: lambda x: x != '\x00',
})
DatabaseIntrospection.data_types_reverse.update({
FIELD_TYPE.BIT: 'BooleanField',
})
#4
1
The django-mysql package provides a BooleanField subclass called Bit1BooleanField that solves this:
django-mysql包提供了一个名为Bit1BooleanField的BooleanField子类,它解决了这个问题:
from django.db import Model
from django_mysql.models import Bit1BooleanField
class AppUser(Model):
bit1bool = Bit1BooleanField()
Easier than rolling your own, and tested on several Django and Python versions.
比滚动自己更容易,并在几个Django和Python版本上进行测试。
#5
0
To make it work on django 1.7.1 i've to change the "to_python" function because it was not working to read correctly the data from the db:
为了使它能在django 1.7.1上工作,我要更改“to_python”函数,因为它无法正确读取数据库中的数据:
def to_python(self, value):
if value in (True, False): return value
if value in ('t', 'True', '1', '\x01'): return True
if value in ('f', 'False', '0', '\x00'): return False
#1
2
I guess that only way is to subclass, say, BooleanField, and override to_python/get_prep_value functions, so the field works seamlessly with django and your db.
我想唯一的方法是子类,比如BooleanField,并覆盖to_python / get_prep_value函数,因此该字段可以与django和你的数据库无缝协作。
#2
10
This is the detailed solution from Dmitry's suggestion:
这是德米特里建议的详细解决方案:
My derived field class:
我派生的字段类:
class MySQLBooleanField(models.BooleanField):
__metaclass__ = models.SubfieldBase
def to_python(self, value):
if isinstance(value, bool):
return value
return bytearray(value)[0]
def get_db_prep_value(self, value):
return '\x01' if value else '\x00'
Fields in my model:
我的模型中的字段:
account_enabled = MySQLBooleanField()
account_expired = MySQLBooleanField()
#3
2
I had to deal the same problem, but rather than subclassing the field, I extended the MySQL backend to understand the Hibernate way. It's only a few lines of code and has the advantage that the DB introspection can be made to work correctly, as well.
我不得不处理同样的问题,但是我没有对字段进行子类化,而是扩展了MySQL后端以了解Hibernate的方式。它只有几行代码,并且具有可以使DB内省正常工作的优点。
See it here.
在这里看到它。
hibernateboolsbackend / backends / mysql / base.py
# We want to import everything since we are basically subclassing the module.
from django.db.backends.mysql.base import *
django_conversions.update({
FIELD_TYPE.BIT: lambda x: x != '\x00',
})
DatabaseIntrospection.data_types_reverse.update({
FIELD_TYPE.BIT: 'BooleanField',
})
#4
1
The django-mysql package provides a BooleanField subclass called Bit1BooleanField that solves this:
django-mysql包提供了一个名为Bit1BooleanField的BooleanField子类,它解决了这个问题:
from django.db import Model
from django_mysql.models import Bit1BooleanField
class AppUser(Model):
bit1bool = Bit1BooleanField()
Easier than rolling your own, and tested on several Django and Python versions.
比滚动自己更容易,并在几个Django和Python版本上进行测试。
#5
0
To make it work on django 1.7.1 i've to change the "to_python" function because it was not working to read correctly the data from the db:
为了使它能在django 1.7.1上工作,我要更改“to_python”函数,因为它无法正确读取数据库中的数据:
def to_python(self, value):
if value in (True, False): return value
if value in ('t', 'True', '1', '\x01'): return True
if value in ('f', 'False', '0', '\x00'): return False