Opened 12 years ago

Closed 9 years ago

#18480 closed Bug (duplicate)

Inherited model fails to handle blank field properly

Reported by: Yuval Adam Owned by:
Component: Database layer (models, ORM) Version: 1.4
Severity: Normal Keywords:
Cc: navi7 Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I just opened a stack overflow question about this, but after digging a bit this is starting to look like a bug.

Take two simple models with inheritance:

class A(models.Model):
    a = models.IntegerField(blank=True)

class B(A):
    b = models.IntegerField(blank=True)

And then in runtime:

>>> A()
<A: A object>
>>> B()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "django/db/models/base.py", line 357, in __init__
    setattr(self, field.attname, val)
  File "django/db/models/fields/related.py", line 271, in __set__
    (instance._meta.object_name, self.related.get_accessor_name()))
ValueError: Cannot assign None: "B.b" does not allow null values.

There should be absolutely no reason why A() is properly created, while B() should fail.

Change History (8)

comment:1 by Yuval Adam, 12 years ago

The issue here is a conflicting field name. This is totally irrelevant to the field being blank.

I would argue, though, that the error must be much more descriptive. And I still don't quite understand why this isn't an issue with the parent model.

comment:2 by Aymeric Augustin, 12 years ago

Triage Stage: UnreviewedAccepted

blank=True is irrelevant here; blank is validation-related and the example doesn't involve forms.

I reproduced the inconsistency and I agree that it's a bug.

I don't understand the comment above. yuval_a, are you sure you haven't misread the model definition?

comment:3 by anonymous, 12 years ago

Well, what's the bug here, in your opinion?

As far as I can tell I've made the error of having field names which are the same as model names in both examples.

It's odd that the error only reproduces on the sub-model. And the error should definitely be more descriptive.

comment:4 by anonymous, 11 years ago

Seems all related accessor name are not validated against existing fields.

class A(models.Model):

a = models.IntegerField()
br = models.IntegerField()

class B(models.Model):

a = models.ForeignKey(A, related_name='br')

raises an error.

Should fixing this wait till the validation changes hit?

comment:5 by navi7, 10 years ago

Owner: changed from nobody to navi7
Status: newassigned

comment:6 by navi7, 10 years ago

This is a kind of red herring.

The actual problem stems from the model coming up with the same field name as name of the derived class itself so it can have the reference to the base class. Model building then just overwrites our field. The simplest test is this:

class FruitFly(models.Model):
    pass

class CroatianFruitFly(FruitFly):
    croatianfruitfly = models.IntegerField()


fly2 = CroatianFruitFly()  #  this throws wrong exception

The error thrown is:

ValueError: Cannot assign None: "CroatianFruitFly.croatianfruitfly" does not allow null values.

And that's totally misleading.

As I'm totally new to Django, I don't know a way out of it. It seems that using the same field name as the class can be explicitly forbidden by throwing meaningful errors when the model is built. Then again, that could potentially be a breaking change.

Or, the name of the reference could be mangled somehow to not use that exact name.

Anyways, I need someone who knows the internals a bit more to look at this.

comment:7 by navi7, 10 years ago

Cc: navi7 added
Owner: navi7 removed
Status: assignednew

comment:8 by Tim Graham, 9 years ago

Resolution: duplicate
Status: newclosed

The clashing field/model names is a duplicate of #14217.

Note: See TracTickets for help on using tickets.
Back to Top