I'm trying to create a reusable app where I define some abstract models, and some concrete versions of those models that the user can use if they don't want to inherit the models themselves. If the user does want to create their own subclasses then I don't want Django to create these concrete models.
This is the solution I have at the moment:
myapp/abstract.py
class AbstractModel1:
class Meta:
abstract = True
field1 = models.CharField(max_length=255)
class AbstractModel2:
class Meta:
abstract = True
field1 = models.CharField(max_length=255)
field2 = models.ForeignKey(getattr(settings, 'ABSTRACTMODEL1_OVERRIDE', 'myapp.ConcreteModel1'))
myapp/models.py
if not hasattr(settings, 'ABSTRACTMODEL1_OVERRIDE'):
class ConcreteModel1(AbstractModel1):
pass
if not hasattr(settings, 'ABSTRACTMODEL2_OVERRIDE'):
class ConcreteModel2(AbstractModel2):
pass
Then in the user's app, they can either use the concrete models as provided, or if not then they can create their own subclasses of the model like so:
userapp/models.py
class CustomModel1(AbstractModel1):
extrafield1 = models.CharField(max_length=255)
userapp/settings.py
ABSTRACTMODEL1_OVERRIDE = "userapp.CustomModel1"
Is this the best way to achieve this? Am I setting myself up for difficulties when trying to migrate changes in the subclassed models? What if the user wants to use the provided concrete classes first then migrate to a custom class?
Related
Django allows us to use '%(class)s' to automatically create related name from mixins. But when I have a ClassName I'd rather access it using class_name, not classname. I know it's only semantics but I was wondering if it's possible to adjust model field to make it snake case instead.
I was browsing through django.db.models.fields but I can't find where the class interpolation is happening.
Example code
from django.db import models
class User(models.Model):
pass
class UserRelatedMixin(models.Model):
user = models.OneToOneField(
to=User,
parent_link=True,
on_delete=models.CASCADE,
related_name='%(class)s',
related_query_name="%(class)s",
)
class Meta:
abstract = True
class HomeAddress(UserRelatedMixin):
pass
user = User.objects.first()
What I have
user.homeaddress
What I want instead
user.home_address
Right now I'm using a #property but it won't allow ORM queries so it's a partial solution.
Example situation as follows:
# models.py
class Form(models.Model):
name = models.CharField()
class A(models.Model):
form = models.ForeignKey(Form)
class B(A):
name = models.CharField()
# view.py
form = Form.objects.get(id=1)
form.a_set.all() # works
form.b_set.all() # doesn't work
I would like to access all the related B Objects via the parent class A foreign key but I can't seem to do this. And if I access them via A then I just get the generic parent class query set. Thank you.
When you inherit from a concrete model, there will be two tables (unlike inheriting from an abstract model) for Parent and Child models.
Django will implicitly create a OneToOneField from Child to Parent model named parent_ptr, thus:
B.objects.filter(a_ptr__form=form)
# B.objects.filter(a_ptr__form_id=1)
will give you the desired QuerySet.
My app_templ models definition:
models.py
class TableName(models.Model):
name = models.CharField(max_length=100)
#
class TableAbstract(models.Model):
...
class Meta:
abstract = True
It can be used by other apps:
app1 / models.py
from app_templ.models import TableAbstract
class Table1(TableAbstract):
...
app2 / models.py
from app_templ.models import TableAbstract
class Table2(TableAbstract):
...
and so on...
It is necessary for me that in TableName, names of models (tables) of successors registered.
How to make it by means of coding only in the app_templ app?
Technically, what you are describing sounds fine. You are defining an abstract model and then using it to create several models. You do need to import it, and to specify that you want to create these tables (using your above examples). You should think carefully about why you are using the same model multiple times in different apps (should this actually be one app?), but in theory it is fine.
I don't quite understand your first definition, you should probably define your model something like this:
class TableBaseClass(models.Model):
name = models.CharField(max_length=100)
class Meta:
abstract = True
abstract = True will mean that the model is not created in your database (docs) so for clarity, you could store this file in a location distinct from your regular model classes that create tables.
This code:
from app_templ.models import TableAbstract
class Table1(TableAbstract):
...
should be in models.py in your app
I am having the following model class hierarchy:
from django.db import models
class Entity(models.Model):
createTS = models.DateTimeField(auto_now=False, auto_now_add=True)
class Meta:
abstract = True
class Car(Entity):
pass
class Meta:
abstract = True
class Boat(Entity):
pass
class Amphibious(Boat,Car):
pass
Unfortunately, this does not work with Django:
shop.Amphibious.createTS: (models.E006) The field 'createTS' clashes with the field 'createTS' from model 'shop.boat'.
Even if I declare Boat abstract, it doesn't help:
shop.Amphibious.createTS: (models.E006) The field 'createTS' clashes with the field 'createTS' from model 'shop.amphibious'.
Is it possible to have a model class hierarchy with multiple inheritance and a common base class (models.Model subclass) that declares some fields?
Use this and see if it helps. If you are trying to include the timestamp to the models then just create a base model which includes only the timestamp.
from django.db import models
class Base(models.Model):
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Boat(Base):
boat_fields_here = models.OnlyBoatFields()
class Amphibious(Boat):
# The boat fields will already be added so now just add
# the car fields and that will make this model Amphibious
car_fields_here = models.OnlyCarFields()
I hope this helps. I see that it has been 5 months since you posted this question. If you have already found a better solution then please share it with us, will help us a lot for learning. :)
I would like to create a models.Model class that doesn't became part of the database but just an interface to other models (I want to avoid repeating code).
Something like that:
class Interface(models.Model):
a = models.IntegerField()
b = models.TextField()
class Foo(Interface):
c = models.IntegerField()
class Bar(Interface):
d = models.CharField(max_length='255')
So my database should have only Foo (with a,b,c collumns) and Bar (with a,b,d) but not the table Interface.
"Abstract base classes"
Abstract base classes are useful when you want to put some common information into a number of other models. You write your base class and put abstract=True in the Meta class. This model will then not be used to create any database table. Instead, when it is used as a base class for other models, its fields will be added to those of the child class.
You can define your classes like this:
from django.db import models
class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
class Meta:
abstract = True
class Student(CommonInfo):
home_group = models.CharField(max_length=5)