I want to create base model for my submodels, for example: Car(Base) and Truck, Sportcart etc. And I want to bind them all using base class with another class, cuz I don't want to bind all of them separately with another class.
Example:
I have a user and I want to add to him cars (I will do it separately for each class, yes). And I want to get all of them using my base Car class.
Mark your base model as abstract:
class Car(models.Model):
# Your fields
class Meta:
abstract = True
Then inherit from the abstract model:
class SportCar(Car):
# Your fields
pass
In this case Django will make migrations only for SportCar, because Car is an abstract model.
Related
When using a Custom Model Manager the way it is shown in the documentation and examples that I have found, the Custom Managers are placed in the same source file as the Model.
My models.py file has a base class with four sub-classes and the base class has several static methods to provide some common queries. I will need to add quite a few custom queries. I would prefer to put these in a Custom Model Manager that is a Base class for each of the subclasses Model Managers. I would also like to be able to separate the Model Managers into a separate source file called managers.py to make the code less messy.
The problem is that there is a cyclic dependency between the Models and Managers.
Is there a way to set the Manager to the "objects" variable by name instead of the actual Model Manager class? Or perhaps some other way to be able to put the code into the two separate files?
models.py
class MyBaseModelClass(models.Model): (abstract)
list_of_values (Many to Many Field)
class class SubclassA(MyBaseModelClass):
objects = SubclassAManager()
# list_of_values pulled from external system
class class SubclassB(MyBaseModelClass):
objects = SubclassBManager()
# list_of_values manually added by the user in the UI and stored in the DB
class class SubclassC(MyBaseModelClass):
objects = SubclassCManager()
# list_of_values derived from subclass fields and not stored in the DB
class class SubclassD(MyBaseModelClass):
objects = SubclassDManager()
# list_of_values derived from subclass fields and not stored in the DB
managers.py
class MyCustomBaseManager(models.Manager):
# Does custom queries that do calculations and other data manipulations that are common to all of the
# Subclasses. Note that MyBaseModelClass can't have a Manager because it is Abstract.
class SubclassAManager(MyCustomBaseManager):
class SubclassBManager(MyCustomBaseManager):
class SubclassCManager(MyCustomBaseManager):
class SubclassDManager(MyCustomBaseManager):
I we have this models in django:
class FotherModel(models.Model):
# Some fields goes here!
class Meta:
# Some fields goes here!
abstract = True
class ChildModel(FotherModel):
# Some fields goes here!
class Meta(FotherModel.Meta):
#s Some fields goes here!
When we inherit a field from the meta class of Django models, that field appears in child meta class, But this rule does not apply to abstract=True.
I know that if this happens, no table in database will be created, But I don't know how this inheritance didn't happen. Please explain this process for me.
The Model metaclass resets abstract in a model's Meta class. In this document you can see:
Django does make one adjustment to the Meta class of an abstract base
class: before installing the Meta attribute, it sets abstract=False.
This means that children of abstract base classes don’t automatically
become abstract classes themselves.
Also, you can see the source code of this process in this link:
if abstract:
# Abstract base models can't be instantiated and don't appear in
# the list of models for an app. We do the final setup for them a
# little differently from normal models.
attr_meta.abstract = False
new_class.Meta = attr_meta
return new_class
Because of the concept and effect of some fields in meta section in many cases it doesn't make sense that the field is inherited by chidren.
It has been described here
I'm using Python 3.6+PostgreSQL 10+latest Django and DjangoRestFRamework. I have the following models, in which several models inherit from a class which is the ForeignKey (One-to-Many) of another class.
class Voteable(models.Model):
Voteable_id = models.BigAutoField(primary_key=True);
class base(Voteable):
class Meta:
abstract = False
class traslated_info(models.Model):
info_about=models.ForeignKey(base)
info_body=models.TextField()
info_language=models.CharField(max_length=2)
class A(base):
A_id=models.BigAutoField(primary_key=True)
A_field=models.TextField()
class B(base):
B_id=models.BigAutoField(primary_key=True)
B_field=models.TextField()
B_belongs_to=models.ForeignKey(A)
class C(base):
C_id=models.BigAutoField(primary_key=True)
C_field=models.TextField()
C_belongs_to=models.ForeignKey(A)
C_belongs_to=models.ForeignKey(B)
Whenever I try saving an object A (via curl), django says that base_ptr is required. I don't know how to model this situation. The end user is not expected to create item base and then item A, B or C. I tried class base as abstract, but an abstract class can't be ForeignKey. I want to automatically create a base class whenever a class A is created.
I think I have two options: A) Remove the ForeignKey and store the language-specific info fields as HStoreField. This makes the code somewhate dependent on Postgree. B) Create some sort of routine that automatically creates parent base item whenever a child A item is created (preserving the one to one relationship).
What do you recommend? Is there some django easy option I'm missing to make option B? I have not found this. Thank you.
Having an autofield as primary_key in the models A, B or C causes this error, as creating a child model doesn't cascade-create parents.
I found two workarounds:
Change autofield option primary_key to false and add
SILENCED_SYSTEM_CHECKS=['fields.E100']
Overriding Viewset create method:
#transaction.atomic
def create(self,request,*args,**kwargs):
request.data['base_ptr'] = base.objects.create(user=request.user,created_date=datetime.utcnow()).pk
return super(viewsets.ModelViewSet,self).create(request,*args,**kwargs)
I will stick with the second, I'm quite sure more issues will arise.
Make your serializer as below, you dont need to create base classes explicitly, it will be created automatically.
class ASerializer(serializers.ModelSerializer):
class Meta:
model = A
read_only_fields = ('base_ptr',)
fields = '__all__'
So I have a base abstract model class
class AbstractBase(models.Model):
category = models.CharField()
// Some fields
class Meta:
abstract = True
Now many classes inherit from this Base. Each category has its own fields
class Category1(AbstractBase):
//some code
class Category2(AbstractBase):
//some code
.
.
.
class CategoryN(AbstractBase):
//some code
Now I do not wish to create separate inlines etc for each of these models.
This is because in the admin only one of these models need to be displayed depending on which category it is.
class CategoryAdminInLine(nested.NestedTabularInline):
model = Category
fields = //some common fields
Is there any easy way to do it?
Try the package django-polymorphic https://github.com/django-polymorphic/django-polymorphic
It adds transparent admin and QuerySet integration for inherited models.
Another solution is to simply remove the abstract=True from the base class.
However, I'm afraid this may not be the right way to do it as it may be copying and duplicating the tables and stuff but works great if the tables won't get too big!..
According to how it's done here.. https://godjango.com/blog/django-abstract-base-class-multi-table-inheritance/
If a django model is made abstract, like below, is there a way to inspect the class to determine that it is abstract?
class MyModel(models.Model):
class Meta:
abstract = True
I would expect that I could examine MyModel.Meta.abstract, but according to Django docs:
Django does make one adjustment to the Meta class of an abstract base class: before installing the Meta attribute, it sets abstract=False. This means that children of abstract base classes don't automatically become abstract classes themselves.
Any ideas? Thanks!
You can instantiate MyModel and then check ._meta.abstract.
So in code:
m = MyModel()
print m._meta.abstract
I'd like to point out that you don't need to instantiate a model to check if it's abstract - Django models inherit an actual metaclass that adds _meta on class instantiation.
So, similarly to #sheats's code, try
from django.db.models import Model
class MyModel(Model):
pass
print MyModel._meta.abstract
Or, for a positive example
from django.db.models import Model
class MyModel(Model):
class Meta(object):
abstract = True
print MyModel._meta.abstract
Of course, this also works for built-in models and anything inheriting from Django's Model.
from django.contrib.auth.models import User
print User._meta.abstract