I have a model that inherit from 2 abstract models with attributes in their meta-classes.
How can I make it inherit the metas from both parent classes? It seems like it only inherit the meta of the class written first.
Normal rules for Python's multiple inheritance apply when using it in Django. That means that if multiple parents have the Meta class, only the Meta of the first parent will be used. Others will be ignored.
See this URL for more info
https://docs.djangoproject.com/en/dev/topics/db/models/#multiple-inheritance
Related
Say I have this class in an app:
class Something(models.Model):
pass
But I don't want this class to inherit from models.Model, I want it to inherit from my own custom class, let's call this 'BetterModel'.
Multiple inheritence doesn't work in this situation so I can't do:
import Something
class newClass(Something, BetterModel):
pass
Are there any other options other fork the app?
You can just directly import your parent "BetterModel". As long as better model implements models.Model you should be good.
Additionally, Django does support multiple inheritance of models so you should be able to extend two different classes as long as they extend models.Model.
Additional Resources:
https://docs.djangoproject.com/en/dev/topics/db/models/#model-inheritance
https://docs.djangoproject.com/en/dev/topics/db/models/#multiple-inheritance
I am trying to design a framework to help implement complex web flows. The framework would provide with abstract classes which could inherited and implemented by the sub-apps. Now, as you can see my abstract class Action has a Foreign Key with Stage. Since, it has a foreignkey it could not be made abstract due to which it would have its own table. So, If I have 2 implementing application then my first application can see all the Stages for itself as well as for the other application. I could make some tweaks in the queries to avoid this. But I want to know if there is solution so, that my implementing Action class could directly point to the Inheriting Stage class.
parent_app/models.py
class Stage(models.Model):
name = models.CharField(max_length=255)
class Action(models.Model):
stage = models.ForeignKey(Stage)
class Meta:
abstract = True
sub_app1/models.py
class StageImpl1(Stage):
pass
class ActionImpl1(Action):
...
sub_app2/models.py
class StageImpl2(Stage):
pass
class ActionImpl2(Action):
...
Update:
The current situation is:
ActionImpl1 has a foreignkey to Stage
What I would to have is:
ActionImpl1 to have a foreignkey with StageImpl1
An abstract class is a class that doesn't exist. It is used as a basis for other classes. It is never never ever initialized.
Something that does not exist cannot have a foreign key pointing at it!
Something to look at, if you want to have a way to point at several different kinds of classes: generic relations. This is Django's build-in way to have something that looks like a foreign key point at a number of different objects.
It is imposible.
Think what would happen to all the classes with a foreign key pointing A if A is abtract and several classes inherit from A.
I dont know your requirements but I maybe you should consider using multitable inheritance, and point the FK to the parent table.
From the Django documentation:
Multi-table inheritance
https://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance
The second type of model inheritance supported by Django is when each
model in the hierarchy is a model all by itself. Each model
corresponds to its own database table and can be queried and created
individually. The inheritance relationship introduces links between
the child model and each of its parents (via an automatically-created
OneToOneField). For example:
Suppose you have to model several classes that should have composite properties like dimensions (width and height) or phone number (prefix, number and extension).
In Java (using JPA 2) I'd create a Dimensions class and annotate it with #Embeddable. This causes Dimension's fields (e.g. width and height) to be embedded into every class that declares a property of type Dimensions.
How do you model these with Django while avoiding code duplication? It doesn't make sense to create a separate Dimensions model and reference it with a ForeignKey field. And the classes do not have enough in common to justify model inheritance.
I think you might be over-thinking inheritance. Inheritance is and is actually the recommended method to composite models. The following is an example of how properly use model inheritance in Django:
class PhoneModelBase(model.Model):
phone = models.CharField(max_length=16)
...
class Meta:
abstract = True
class PhoneModel(PhoneModelBase):
# phone is here without typing it
# the only restriction is that you cannot redefine phone here
# its a Django restriction, not Python restriction
# phone = models.CharField(max_length=12) # <= This will raise exception
pass
So what this does is it creates a model PhoneModelBase, however the key here is that it uses class Meta with abstract=True.
Here is more of behind the scenes of what is going on and some explanation of some of the Python concepts. I assume that you are not aware of them since you mentioned Java in the question. These Python concepts are actually rather confusing concepts so my explanation is probably not full, or even confusing, so if you will not follow, don't mind. All you have to know is to use abstact = True. Here is the official doc: https://docs.djangoproject.com/en/dev/topics/db/models/#abstract-base-classes.
Meta attribute within PhoneModelBase is just that, an attribute. It is the same as any other attribute within the class, except its a class instance (remember that in Python classes and functions are first order members). In addition, Python has this thing called __metaclass__ which you can add to you classes. __metaclass__ defines a way of how an instance of a class is build. More about that here. Django uses these in how it creates model class instances.
So to create the PhoneModelBase class, the following is a rough outline:
When an instance of the PhoneModelBase class (the class itself, not instance of class - PhoneModelBase()) is being created, the __metaclass__ which comes from model.Model due to inheritance takes over the creation process
Within the __metaclass__, Python calls the function which creates the actual class instance and passes to it all of the fields from the class you are trying to create - PhoneModelBase. That will include phone, Meta and any other fields you define
It sees the Meta attribute and then it starts analyzing its attributes. According to the values of these attributes, Django will change the behavior of the model
It sees the abstract attribute and then changes the logic of the class its trying to create - PhoneModelBase by not storing it in db
So then the PhoneModelBase, even though its definition looks very similar to a regular model, its not a regular model. It is just an abstract class which is meant to be used as composite in other models.
When other models inherit from PhoneModelBase, their __metaclass__ will copy the attributes from the base model as if you manually typed those attributes. It will not be a foreign key on anything like that. All of the inherited attributes are going to be a part of the model and will be in the same table.
Hopefully all of this makes some sense. If not, all you have to remember is just to use Meta class with abstract = True.
EDIT
As suggested in the comment, you can also inherit from multiple base classes. So you can have PhoneModelBase, DimensionsModelBase, and then you can inherit from both of these (or more), and all of the attributes from all base classes will be present in your model.
I'm attempting to have inherited class templates, so that all my models have certain default fields, and all have default overrides for a few functions like save_model()
If I do it like this, I get the overrides, but then have to go and manually set meta data like db_table...
class ModelExtension(models.Model):
altered_by = models.CharField(max_length=64)
class SomeModel(ModelExtension):
class Meta:
db_table = 'app_somemodel'
fields = models.CharField()
...
Is there a way to get this kind of inheritance working right? So far I either have to do extra work to compensate for the drawbacks of this approach, or I'm plagued by MRO errors.2
What's an MRO error? Have you read the django docs on model inheritance? You can either have Abstract Base Classes, Multi-table inheritance, or proxy models.
http://docs.djangoproject.com/en/stable/topics/db/models/#abstract-base-classes
What you've done there is a multi-table inheritance - there's a hidden OneToOneField connecting your two models. I don't know why you think you need the db_table specified - it shouldn't be.
If you are never going to have objects of bare class ModelExtension then you want abstract base classes. In this case you put abstract=True in the Meta section, and then all the fields from the base class are added to the table for the child class. The docs explain it better than I can here.
I often find myself starting to do it one way and then flipping back and forth several times as I think more about my database structure....
If you just want to add new functionality to a model without changing its fields, use a proxy model!
This is a question about Python Mixins that might be useful in general. I'm just using Django models as that is the use-case I'm most familiar with.
Should a mixin inherit from the class it is designed to mix-in with or from 'object'?
Examples by code, what is more correct or better, or better depending on what you want to achieve?
This
class TaggingMixin(models.Model):
tag = models.ForeignKey(Tag)
class Meta:
abstract = True
class MyModel(models.Model, TaggingMixin):
title = models.CharField(max_length=100)
Or this:
class TaggingMixin(object):
tag = models.ForeignKey(Tag)
class Meta:
abstract = True
class MyModel(models.Model, TaggingMixin):
title = models.CharField(max_length=100)
I think inheriting from object is the right way. But I'm seeing examples of the first case all over the net...
EDIT: I've moved my follow up question to a separate question: Django Abstract Models vs simple Python mixins vs Python ABCs
Django does a lot of meta magic when it comes to its model classes, so unfortunately the usual approach to mixins as suggested in Daniel Roseman's answer -- where they inherit from object -- does not work well in the Django universe.
The correct way to structure your mixins, using the example provided, would be:
class TaggingMixin(models.Model):
tag = models.ForeignKey(Tag)
class Meta:
abstract = True
class MyModel(TaggingMixin):
title = models.CharField(max_length=100)
Important points here being:
Mixins inherit from model.Model but are configured as an abstract class.
Because mixins inherit from model.Model, your actual model should not inherit from it. If you do, this might trigger a consistent method resolution order exception.
I would recommend that it inherits from object. That way you can ensure that it only provides those methods and attributes you actually define explicitly.
Also, you should always ensure that you put the mixin class first when defining your concrete class. Python's resolution rules mean that the superclasses are searched in order of their definition in the class declaration, and resolution stops when a matching attribute is found. So if your mixin defines a method that is also defined by the main superclass, your mixin method won't be found.
This looks like a job for an abstract model.
EDIT:
Those are not mixins per se. Or rather, they do not need to be. You can derive from an abstract model directly.
When you inherits from plain Python object South doesn't create a migration so you can't use this approach