Been using Django Polymorphic to help me with complex inheritance patterns in my Django model.
I'm having an issue where I need to have a concrete base model (because it needs to have a ForeignKey to itself), and then have multiple models inherit from it, with eventually some model inheriting from multiple of those. The issue is that I'm getting a E005 error:
app.NamedWeightedModel: (models.E005) The field 'basemodel_ptr' from
parent model 'app.namedmodel' clashes with the field 'basemodel_ptr'
from parent model 'app.massmodel'.
The simple example that triggers this is shown below:
from django.db import models
from polymorphic.models import PolymorphicModel
class BaseModel(PolymorphicModel):
parent = models.ForeignKey('self')
class NamedModel(BaseModel):
name = models.CharField(max_length=32)
class MassModel(BaseModel):
weight = models.FloatField()
class NamedWeightedModel(NamedModel, MassModel):
pass
Is there a better way to handle this? Or a standard approach?
My real model is much more complex (an implementation of the UML spec), and I would like to be able to use multiple inheritance (ideally through Polymorphic) to make things easier.
I've considered making any multiple inheritance models be single inheritance with all additional inherited models mapped as OneToOneFields, but this negates some of the nice things that polymorphic does.
Any help you can provide would be greatly appreciated.
Related
Can we say that Django models are considered dataclasses? I don't see #dataclass annotation on them or on their base class model.Models. However, we do treat them like dataclasses because they don't have constructors and we can create new objects by naming their arguments, for example MyDjangoModel(arg1= ..., arg2=...).
On the other hand, Django models also don't have init methods (constructors) or inherit from NamedTuple class.
What happens under the hood that I create new Django model objects?
A lot of the magic that happens with models, if not nearly all of it, is from its base meta class.
This can be found in django.db.models.ModelBase specifically in the __new__ function.
Regardless of an __init__ method being defined or not (which actually, it is as per Abdul's comment), doesn't mean it can or should be considered a dataclass.
As described very eloquently in this SO post by someone else;
What are data classes and how are they different from common classes?
Despite django models quite clearly and apparently seeming to have some kind of data stored in them, the models are more like an easy to use (and reuse) set of functions which leverage a database backend, which is where the real state of an object is stored, the model just gives access to it.
It's also worth noting that models don't store data, but simply retrieves it.
Take for example this simple model:
class Person(models.Model):
name = models.CharField()
And then we did something like this in a shell:
person = Person.objects.get(...)
print(person.name)
When we access the attribute, django is actually asking the database for the information and this generates a query to get the value.
The value isn't ACTUALLY stored on the model object itself.
With that in mind, inherently, django models ARE NOT dataclasses. They are plain old regular classes.
Django does not work with data classes. You can define a custom model field. But likely this will take some development work.
I'm working on a django application, and I want to create a mixin that will always be applied to model definitions. The functionality added by the mixin isn't important for the question.
However, I need to be able to retrieve a list of all the class definitions that inherit from this mixin. These classes can be in different apps within the django project.
Possible answers I've found so far are:
How to find all the subclasses of a class given its name?
How to auto register a class when it's defined
I'm mostly wondering what the best method would be to accomplish this goal.
Typically the way you would get a list of all the classes that inherit a particular class would be by registering the classes with a meta-class (as is explained in one of the questions you have linked). Django models however use their own meta class to achieve a lot of what they do automatically. I wouldn't recommend adding another meta-class into the mix - things could go wrong here!!
Fortunately however, django has something called the content-types framework which is essentially a registry of all of your models in a particular project.
To get a list of all of your models you can do this:
from django.contrib.contenttypes.models import ContentType
content_types = ContentType.objects.all()
This won't get the actual models, but rather a queryset of ContentType instances. To then get the model classes from this you can do
models = [x.model_class() for x in content_types]
So we now have a list of models. Then we can just filter the list down to those models which inherit your mixin:
models_with_mixin = [x for x in models if issubclass(x, MyMixin)]
We can simplify all of the above into the following:
from django.contrib.contenttypes.models import ContentType
models_with_mixin = [
x.model_class()
for x in ContentType.objects.all()
if issubclass(x.model_class(), MyMixin)
]
My django app must be translatable, static pages and models too. For translating models I'm using django-parler app. This works fine, but for simple models, I mean, models that doesn't inherits from an abstract model class.
Let's say that we have a Vehicle abstract model
class Vehicle(TranslatableModel):
translations = TranslatedFields(
description=models.CharField(max_length=100)
)
class Meta:
abstract = True
and a child model which is Car:
class Car(Vehicle)
"""..."""
This raised me this error: TypeError: Can't create TranslatedFieldsModel for abstract class Vehicle.
I'd like still using django model inheritance. So, what can I do for translating my models using django-parler, it support translations for abstract models or I'll need to use another app to achieve this, in that case any suggestion on any?
The problem is, parler implicitly creates an extra db table for the translations which has a ForeignKey to the model that the translated fields are declared on. You cannot have a FK to an abstract model because it does not have its own db table. What if you have two models subclassing this abstract model? Which table is the translation table's FK pointing to?
You could try to implement the translatable fields outside of your model if you want to share the same translatable fields across models and still be relatively DRY:
vehicle_translations = TranslatedFields(
description=models.CharField(max_length=100)
)
class Car(TranslatableModel):
translations = vehicle_translations
The best solution is to use TranslatedField as explained in the docs: https://django-parler.readthedocs.io/en/latest/api/parler.fields.html#the-translatedfield-class
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:
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!