I'm looking to do this:
class Place(models.Model):
name = models.CharField(max_length=20)
rating = models.DecimalField()
class LongNamedRestaurant(Place): # Subclassing `Place`.
name = models.CharField(max_length=255) # Notice, I'm overriding `Place.name` to give it a longer length.
food_type = models.CharField(max_length=25)
This is the version I would like to use (although I'm open to any suggestion): http://docs.djangoproject.com/en/dev/topics/db/models/#id7
Is this supported in Django? If not, is there a way to achieve similar results?
No, it is not:
See https://stackoverflow.com/a/6379556/15690:
This supercool piece of code allows you to 'override' fields in abstract parent classes.
When the fields have been removed from the abstract parent class you are free to redefine them as you need.
This is not my own work. Original code from here: https://gist.github.com/specialunderwear/9d917ddacf3547b646ba
Updated answer: as people noted in comments, the original answer wasn't properly answering the question. Indeed, only the
LongNamedRestaurant
model was created in database,Place
was not.A solution is to create an abstract model representing a "Place", eg.
AbstractPlace
, and inherit from it:Please also read @Mark answer, he gives a great explanation why you can't change attributes inherited from a non-abstract class.
(Note this is only possible since Django 1.10: before Django 1.10, modifying an attribute inherited from an abstract class wasn't possible.)
Pasted your code into a fresh app, added app to INSTALLED_APPS and ran syncdb:
Looks like Django does not support that.
That is not possible unless abstract, and here is why:
LongNamedRestaurant
is also aPlace
, not only as a class but also in the database. The place-table contains an entry for every purePlace
and for everyLongNamedRestaurant
.LongNamedRestaurant
just creates an extra table with thefood_type
and a reference to the place table.If you do
Place.objects.all()
, you also get every place that is aLongNamedRestaurant
, and it will be an instance ofPlace
(without thefood_type
). SoPlace.name
andLongNamedRestaurant.name
share the same database column, and must therefore be of the same type.I think this makes sense for normal models: every restaurant is a place, and should have at least everything that place has. Maybe this consistency is also why it was not possible for abstract models before 1.10, although it would not give database problems there. As @lampslave remarks, it was made possible in 1.10. I would personally recommend care: if Sub.x overrides Super.x, make sure Sub.x is a subclass of Super.x, otherwise Sub cannot be used in place of Super.
Workarounds: You can create a custom user model (
AUTH_USER_MODEL
) which involves quite a bit of code duplication if you only need to change the email field. Alternatively you can leave email as it is and make sure it's required in all forms. This doesn't guarantee database integrity if other applications use it, and doesn't work the other way around (if you want to make username not required).