Django ORM处理MySQL BIT(1)字段

时间:2010-04-24 20:39:34

标签: mysql django orm

在Django应用程序中,我正在尝试访问使用Hibernate(Java ORM)创建的现有MySQL数据库。我使用以下方法反向设计模型:

$ manage.py inspectdb > models.py

这从数据库创建了一个很好的模型文件,很多东西都很好。但我找不到如何正确访问布尔字段,这些字段由Hibernate映射为BIT(1)类型的列。

默认情况下,inspectdb脚本在模型中将这些字段创建为TextField,并添加注释,表示无法可靠地获取字段类型。我将这些更改为BooleanField但是使用admin打开了我的模型对象,但它不起作用(模型对象总是为这些字段获取值true)。使用IntegerField也不会起作用(例如在管理员这些字段中显示奇怪的非ascii字符)。

在不更改数据库的情况下执行此操作的任何提示? (我需要现有的Hibernate映射和Java应用程序仍然可以使用数据库)。


更多信息:我将这些字段保留为BooleanField,并使用交互式shell查看获取的值。它们返回为'\ x00'(当Java / Hibernate值为false时)和'\ x01'(当为true时),而不是Python布尔值“True”和“False”。

>>> u = AppUser.objects.all()[0]
>>> u.account_expired
'\x00'
>>> u.account_enabled
'\x01'

模型包括:

class AppUser(models.Model):
    account_expired = models.BooleanField()
    account_enabled = models.BooleanField(blank=True)
    # etc...

6 个答案:

答案 0 :(得分:10)

这是德米特里建议的详细解决方案:

我的派生字段类:

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'

我的模型中的字段:

account_enabled = MySQLBooleanField()
account_expired = MySQLBooleanField()

答案 1 :(得分:2)

我想唯一的方法是子类化,比如说BooleanField,并覆盖to_python / get_prep_value函数,因此该字段可以与django无缝地工作 你的数据库。

答案 2 :(得分:2)

我不得不处理同样的问题,但是我没有对字段进行子类化,而是扩展了MySQL后端以理解Hibernate方式。它只有几行代码,并且具有可以使DB内省正常工作的优势。

查看 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',
})

答案 3 :(得分:1)

django-mysql 包提供了一个名为Bit1BooleanField BooleanField 子类,解决了这个问题:

from django.db import Model
from django_mysql.models import Bit1BooleanField

class AppUser(Model):
    bit1bool = Bit1BooleanField()

比滚动自己更容易,并在几个Django和Python版本上进行测试。

答案 4 :(得分:0)

为了让它能够在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

答案 5 :(得分:0)

在Python中,布尔类型是整数的子类,而在Java中,布尔类型是Bit。 因此,在DB for Python中,布尔字段数据类型应为Tinyint而不是BIT类型。

由于上述原因,应用程序意外返回了\x00\x01值。

如果我们在Django模型中添加一个布尔字段并运行迁移然后再迁移,它将添加Tinyint类型的列而不是bit。

因此将列类型更新为Tinyint应该可以解决此问题。