Opened 12 years ago
Last modified 12 years ago
#21413 closed Bug
select_related "row, fields misalignment" in SQLCompiler.fill_related_selections() — at Initial Version
| Reported by: | anonymous | Owned by: | nobody |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | dev |
| Severity: | Normal | Keywords: | select_related parent inheritance subclass oracle |
| Cc: | Shai Berger | Triage Stage: | Accepted |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Given this models for example:
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
When using select related to prefetch the child, the child fields are not initialized properly:
>>> Restaurant.objects.create(name='Bobs Cafe', address="Somewhere", serves_pizza=True, serves_hot_dogs=True)
<Restaurant: Restaurant object>
>>> p = Place.objects.all().select_related('restaurant')[0]
>>> vars(p.restaurant)
{'_place_ptr_cache': <Place: Place object>,
'_state': <django.db.models.base.ModelState at 0x2e791d0>,
'address': u'Somewhere',
'id': 1L,
'name': u'Bobs Cafe',
'place_ptr_id': 1L,
'serves_hot_dogs': 1,
'serves_pizza': 1}
serves_pizza and serves_hot_dogs are set to 1 instead of True!
The cause of this bug is kind of tricky. It is actually a general defect because of a "row, fields misalignment" in SQLCompiler.fill_related_selections().
https://github.com/django/django/blob/master/django/db/models/sql/compiler.py#L650:
self.query.related_select_cols returns:
[SelectInfo(col=(u't13781_restaurant', u'place_ptr_id'), field=<django.db.models.fields.AutoField: id>), SelectInfo(col=(u't13781_restaurant', 'serves_hot_dogs'), field=<django.db.models.fields.CharField: name>), SelectInfo(col=(u't13781_restaurant', 'serves_pizza'), field=<django.db.models.fields.CharField: address>)]
But it only turns up when using SQL backends that use the misaligned fields for converting the row values depending on the field type (mainly when resolve_columns() is implemented). So for example in MySQL this only happens when boolean fields on the child model are involved, because in this special case the field information is interpreted.
https://github.com/django/django/blob/master/django/db/backends/mysql/compiler.py#L10:
if (field and field.get_internal_type() in ("BooleanField", "NullBooleanField") and
value in (0, 1)):
value = bool(value)
It won't appear using SQLite but i guess it will appear using Oracle (only tested SQLite and MySQL).
patch for ticket #21413