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
Related
In Django, is there a way to combine two models that inherit the same class into one serializer?
from django.db.models import Model
class A(Model):
a = IntegerField(...)
# other fields...
class Meta:
abstract = True
class B(A):
# There may or may not be such a thing as class C.
class C(A):
# There may or may not be such a thing as class B.
I have code like above.
Could it be possible to create a serializer based on the class A model?
I tried to create a view table in SQL, but gave up due to performance issues.
Any good ideas please. It's so painful...😥
In general it is not a good idea to reuse serializes because doing so may expose you to unexpected behavior, when something changes in the base serializer or when you add/remove attributes to one of your models.
If model B and C have some attributes in common, then perhaps, you should consider changing your DB design.
However, in this case I would define 2 serializes that have the attribute of the abstract model:
class BSerializer(serializers.Serializer):
a = serialzier.IntegerField()
...
class CSerializer(serialziers.Serializer):
a = serializer.IntegerField()
...
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 have an abstract model that contains a field type that I would like to override the widget for in the admin view.
Now you can't register abstract models in the admin view so I have had to override the widget for each of the models that inherit from the abstract model. This feels clunky - is there a neater way to do this?
models.py
class MyAbstractModel(Model):
field_with_widget_i_want_to_override = MyFieldType()
class Meta:
abstract = True
class ModelA(MyAbstractModel):
extra_field = AnotherFieldType()
class ModelB(MyAbstractModel):
different_extra_field = ADifferentFieldType()
admin.py
class ModelAAdmin(ModelAdmin):
formfield_overrides = {
MyFieldType: {'widget': MyWidget},
}
class ModelBAdmin(ModelAdmin):
formfield_overrides = {
MyFieldType: {'widget': MyWidget},
}
admin.site.register(ModelA, ModelAAdmin)
admin.site.register(ModelB, ModelBAdmin)
Now my actual project is a bit more complicated so I don't want to combine ModelAdmins when registering the models, There are also many more Models that inherit from the abstract base model so I feel like I'm repeating myself alot.
Alternatively is there a way to globally overide the widget used in the admin for a field type (for all models)?
Abstract models can't be registered as ModelAdmin as they are abstract and django can't treat them as data models so most of admin functionalities can't be applied on these classes- so you need to override it with an empty class at least like at documentation here
Abstract classes
There's no way to assign data to abstract models
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/