Django ORM работает с полем MySQL BIT (1) - PullRequest
7 голосов
/ 25 апреля 2010

В приложении Django я пытаюсь получить доступ к существующей базе данных MySQL, созданной с помощью Hibernate (Java ORM).Я реверс-инжиниринг модели, используя:

$ manage.py inspectdb > models.py

Это создало хороший файл моделей из базы данных, и многие вещи были довольно хорошо.Но я не могу найти, как правильно получить доступ к логическим полям, которые были отображены в Hibernate как столбцы типа BIT (1).

Сценарий inspectdb по умолчанию создает эти поля в модели как TextField и добавляет комментарийговоря, что он не может надежно получить тип поля.Я изменил их на BooleanField и открыл свои объекты модели с помощью администратора, но это не работает (объекты модели всегда получают значение true для этих полей).Использование IntegerField также не будет работать (например, в админке в этих полях отображаются странные символы, отличные от ascii).

Есть ли намеки на это без изменения базы данных?(Мне нужны существующие отображения Hibernate и Java-приложение для работы с базой данных).


Дополнительная информация: я оставил эти поля как BooleanField и использовал интерактивную оболочку для просмотра извлеченных значений.Они возвращаются как '\ 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 ]

10 голосов
/ 25 апреля 2010

Это подробное решение по предложению Дмитрия:

Мой производный класс поля:

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()
2 голосов
/ 22 февраля 2012

Мне пришлось столкнуться с той же проблемой, но вместо того, чтобы разбивать поле на подклассы, я расширил бэкэнд MySQL, чтобы понять способ Hibernate. Это всего лишь несколько строк кода, и его преимущество заключается в том, что самоанализ БД также может работать корректно.

Смотри здесь.

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',
})
2 голосов
/ 25 апреля 2010

Полагаю, что единственный способ состоит в том, чтобы создать подкласс, скажем, BooleanField, и переопределить функции to_python / get_prep_value, поэтому поле работает без проблем с django и ваш дб.

1 голос
/ 30 августа 2015

Пакет django-mysql предоставляет подкласс BooleanField с именем Bit1BooleanField , который решает это:

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

class AppUser(Model):
    bit1bool = Bit1BooleanField()

Проще, чем собственный, и протестировано на нескольких версиях Django и Python.

0 голосов
/ 22 ноября 2018

В Python логический тип является подклассом целого числа, тогда как Java имеет тип Bit. Таким образом, в БД для Python тип данных логического поля должен быть Tinyint, а не BIT.

Из-за вышеуказанной причины приложение ведет себя неожиданно, возвращая значения \x00 и \x01.

Если мы добавим логическое поле в модель Django и запустим миграцию, а затем выполним миграцию, вместо бит добавится столбец типа Tinyint.

Таким образом, обновление типа столбца до Tinyint должно решить проблему.

0 голосов
/ 09 декабря 2014

Чтобы заставить его работать на 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...