Django ORM处理MySQL BIT(1)字段

时间:2022-10-28 22:09:41

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