Django ORM working with MySQL BIT field (1)

In a Django application, I am trying to access an existing MySQL database created using Hibernate (Java ORM). I redid the model with:

$ manage.py inspectdb > models.py 

This created a good model file from the database, and many things were fine. But I can’t find how to correctly access the logical fields that were displayed by Hibernate as columns of type BIT (1).

The script inspector creates these fields in the model as TextField by default and adds a comment saying that it cannot reliably get the field type. I changed them to BooleanField, but I opened my model objects with the administrator, but it doesn’t work (model objects always get true for these fields). Using IntegerField will also not work (for example, in admin these fields display strange characters other than ascii).

Any hints on this without changing the database? (I need the existing Hibernate mappings and the Java application to continue to work with the database).


Additional information: I left these fields as a BooleanField and used an interactive shell to view the values ​​obtained. They are returned as "\ x00" (when the Java / Hibernate value is false) and "\ x01" (when true), instead of the Boolean Python values ​​"True" and "False".

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

If the model includes:

 class AppUser(models.Model): account_expired = models.BooleanField() account_enabled = models.BooleanField(blank=True) # etc... 
+6
django mysql orm
source share
5 answers

I assume that only the path to a subclass of, say, BooleanField, and override the functions to_python / get_prep_value, so the field works without problems with django and your db.

+2
source share

This is a detailed solution from Dmitry’s proposal:

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() 
+10
source share

I had to solve the same problem, but instead of subclassing the field, I expanded the MySQL backend to understand the Hibernate path. These are just a few lines of code and have the advantage that the self-analysis of the database can be made to work correctly.

See 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', }) 
+2
source share

The django-mysql package provides a subclass of BooleanField called Bit1BooleanField that solves this problem

 from django.db import Model from django_mysql.models import Bit1BooleanField class AppUser(Model): bit1bool = Bit1BooleanField() 

Easier than folding your own and checking out multiple versions of Django and Python.

+1
source share

In order for it to work on django 1.7.1, I have to change the "to_python" function because it did not work in order to read data from db correctly:

 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 
0
source share

All Articles