I've got some models:
class Place(models.Model):
name = models.CharField(unique=True)
class Bar(Place):
drinks = models.ManyToManyField('Drink')
class Restaurant(Place):
meals = models.ManyToManyField('Meals')
That's a multi-table inherited structure where each bar serves drinks only, and each restaurant serves meals only. I, though, need a name of each place to be unique across all the places - hence the parent Place model.
Now, multi-table inheritance presumes a parent and a child are separate entities. That means when I want to create a new Bar, I should go like this:
>> parent = Place(name='Myplace')
>> parent.save()
>> child = Bar(place=parent, drinks=mydrinklist)
>> child.save()
But in my case, Place is not a separate entity: it should not exists by itself. It's just a shared storage with some restrictions. I'd like to have something like this:
>> child = Bar(name='Myplace', drinks=mydrinklist)
>> child.save()
Where name attribute is automatically passed to the underlying parent model and a Place model is silently created when save() is called. SQLAlchemy can do that via its multi-table inheritance. Is there a way to achieve the same in Django?
Django's abstract base classes solve the problem of sharing common fields between models:
class Place(models.Model):
name = models.CharField(unique=True)
class Meta:
abstract = True
Edit: Having said that, as Daniel mentioned in the comments, the solution you propose should work just fine. Here's more on Django's multi-table inheritance
Related
I want to create 73 different django models, those models will be very similar, so in theory I would inherit from a base model class and just change the name of the Model/table.
I am aware this is not the best database structure, however I believe this unconventional structure may improve other aspects of my application. The initial point is to test this hypothesis.
How can I have django create the models, without me having to define all 73 of them?
class BaseModel(models.Model):
some_field = models.CharField(max_length=255)
some_other_field = models.CharField(max_length=255)
class Model_NR_01(BaseModel):
pass
...
class Model_NR_73(BaseModel):
pass
Also, in the sample above, I believe the BaseModel would also be created. How could I prevent that, having at the end of the migration only the 73 models mentioned? (If possible, of course).
PS.: I did searched several similar questions, couldn't find an actual answer, only warnings of how bad design it is. I am aware.
The three argument form of type can be used to create classes dynamically. The only thing you need to pass in the attributes dictionary is __module__ as using type this way to create a class will not automatically populate this attribute which is required by Django
class BaseModel(models.Model):
some_field = models.CharField(max_length=255)
some_other_field = models.CharField(max_length=255)
class Meta:
abstract = True
for i in range(1, 74):
model_name = f'Model_NR_{i:02}'
globals()[model_name] = type(model_name, (BaseModel, ), {'__module__': BaseModel.__module__})
I am trying to set-up some model inheritance in Django. I have three classes:
class Parent(Model):
name = TextField()
class Child1(Parent):
foo = FloatField()
class Child2(Parent):
bar = BoolField()
class RandomClass(Model):
myLink = ForignKey(Parent)
The problem is in my other models like RandomClass I can get instances of Parent but I cant access the variables specific to the child classes.
I could, of course, just have multiple nullable foreign keys in RandomClass then write a property 'wrapper' which works out which ForeignKey is non-null and returns that...but that's not very nice.
Is there a better way to do this?
Cheers,
Jack
I have a Django model that already exists that I'd like to duplicate, and I can't figure out an easy way how because of related-name conflicts across ForeignKeys and ManyToManys.
As an example, let's call the model I currently have Dog:
class Dog(models.Model):
name = models.CharField()
owner = models.ForeignKey('myapp.Owner')
breeds = models.ManyToMany('myapp.Breed', help_text="Remember, animals can be mixed of multiple breeds.")
I'd like to make an exact duplicate of this model for use elsewhere, with a different database table and name. I tried using an abstract base class:
class AnimalAbstract(models.Model):
name = models.CharField()
owner = models.ForeignKey('myapp.Owner')
breeds = models.ManyToMany('myapp.Breed', help_text="Remember, animals can be mixed of multiple breeds.")
class Meta:
abstract = True
class Dog(AnimalAbstract):
pass
class Cat(AnimalAbstract):
pass
This fails because of related_name conflicts.
Is there any way to automatically copy a model like this without explicitly redefining every ForeignKey and ManyToMany?
To preemptively answer questions: yes, I know about multi-table inheritance, and I don't want to use it. I also know that I could simply store this all in the same table and use proxy models with custom managers to automatically filter out the wrong type of animal, but I don't want that either—I want them on separate database tables.
https://docs.djangoproject.com/en/1.8/topics/db/models/#abstract-related-name
To work around this problem, when you are using related_name in an abstract base class (only), part of the name should contain %(app_label)s and %(class)s.
%(class)s is replaced by the lower-cased name of the child class that the field is used in.
%(app_label)s is replaced by the lower-cased name of the app the child class is contained within. Each installed application name must be unique and the model class names within each app must also be unique, therefore the resulting name will end up being different.
Ex:
class Dog(models.Model):
name = models.CharField()
owner = models.ForeignKey(
'myapp.Owner',
related_name="%(app_label)s_%(class)s_dogs")
breeds = models.ManyToMany(
'myapp.Breed',
help_text="Remember, animals can be mixed of multiple breeds.",
related_name="%(app_label)s_%(class)s_dogs")
I have a supplied database schema for which I want to create a Django application. Many of the tables in the schema share a common set of columns, such as name and date_created. That prompted me to create an abstract Standard_model class containing those columns, and subclass the relevant models from it.
Unfortunately, some of the tables have a name column with a different max_length. I'm trying to come up with a way for the subclassed model to pass the max_length value to the abstract base class, but I'm drawing a blank.
Any ideas?
class Standard_model(models.Model):
name = models.CharField(max_length=50)
date_created = models.DateTimeField()
class Meta:
abstract = True
class MyModel(Standard_model):
name = models.CharField(max_length=80) # Can't do this.
No, you cannot override the name field definition:
In normal Python class inheritance, it is permissible for a child
class to override any attribute from the parent class. In Django, this
is not permitted for attributes that are Field instances (at least,
not at the moment). If a base class has a field called author, you
cannot create another model field called author in any class that
inherits from that base class.
See also:
In Django - Model Inheritance - Does it allow you to override a parent model's attribute?
And, FYI, according to the model naming convention, it should be called StandardModel.
I am attempting model inheritance on my Django powered site in order to adhere to DRY. My goal is to use an abstract base class called BasicCompany to supply the common info for three child classes: Butcher, Baker, CandlestickMaker (they are located in their own apps under their respective names).
Each of the child classes has a need for a variable number of things like email addresses, phone numbers, URLs, etc, ranging in number from 0 and up. So I want a many-to-one/ForeignKey relationship between these classes and the company they refer to. Here is roughly what I imagine BasicCompany/models.py looking like:
from django.contrib.auth.models import User
from django.db import models
class BasicCompany(models.Models)
owner = models.ForeignKey(User)
name = models.CharField()
street_address = models.CharField()
#etc...
class Meta:
abstract = True
class EmailAddress(models.model)
email = models.EmailField()
basiccompany = models.ForeignKey(BasicCompany, related_name="email_addresses")
#etc for URLs, PhoneNumbers, PaymentTypes.
What I don't know how to do is inherit EmailAddress, URLs, PhoneNumbers (etc) into the child classes. Can it be done, and if so, how? If not, I would appreciate your advice on workarounds.
I suspect you'll be better off with generic relations for the links, rather than trying to tie everything to a base class. Generic relations allow you to link a model such as EmailAddress to any other class, which would seem to be a good fit with your use case.