I have two Django 3.0 models, one of which is a subclass of the other:
# models.py
class BaseCategory(models.Model):
class Meta:
verbose_name_plural = "categories"
class Category(BaseCategory):
# fields 'n' stuff
Only the Category model is registered in the Admin
# admin.py
#admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
# stuff here
In the Admin, the Category model is labeled "Categorys", despite the fact that it should have inherited the Meta inner class and its verbose_name_plural attribute from BaseCategory. In fact, if I copy the same code into the Category model,
# models.py
class Category(BaseCategory):
class Meta:
verbose_name_plural = "categories"
# fields 'n' stuff
the model is correctly labeled "Categories" in the Admin. This indicates that the Category class is not inheriting the Meta inner class of BaseCategory.
Why does a child class not inherit the Meta inner class? Is there another way for me to only specify verbose_name_plural once instead of copying the exact same code into every child of BaseCategory?
According to the Django Docs you need to declare the BaseCategory model abstract in order for its Meta class to be inherited.
class BaseCategory(models.Model):
class Meta:
abstract = True
verbose_name_plural = "categories"
The Category class will then automatically inherit the Meta class, except for the abstract attribute.
Note that if you want to make any changes to the Meta class in Category you need to subclass it explicitly:
class Category(BaseCategory):
class Meta(BaseCategory.Meta):
...
Related
I have the following models:
class Address(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
....
class Meta:
abstract = True
class BillingAddress(Address):
is_default = models.BooleanField()
...
class Meta:
db_table = 'billing_address'
I'm trying to build a serializer for BillingAddress:
class AddressSerializer(serializers.ModelSerializer):
class Meta:
abstract = True
model = AddressModel
class BillingAddressSerializer(AddressSerializer):
def to_representation(self, obj):
return AddressSerializer(obj, context=self.context).to_representation(obj)
class Meta(AddressSerializer.Meta):
model = UserBillingAddress
fields = (
'id',
'is_default',
)
I keep getting:
ValueError: Cannot use ModelSerializer with Abstract Models.
How can I build my BillingAddressSerializer to reflect both classes?
An abstract model is a base class in which you define fields you want to include in all child models. Django doesn't create any database table for abstract models. A database table is created for each child model, including the fields inherited from the abstract class and the ones defined in the child model.
Since there is no "Address" table, so "AddressSerializer" would be invalid.
Hello I have two models
class A(models.Model):
slug = models.SlugField()
class Meta:
abstract = True
class B(A):
slug = models.CharField()
class Meta:
abstract = True
I get error AttributeError: Manager isn't available; B is abstract
How do can to redefine attribute in abstract class?
class A cannot be changedю
Abstract models don't have a manager on them because they don't map to a database table. They are used to define reusable mixins that you can compose into concrete models. To make B a concrete model remove the abstract flag and then it will have an objects attribute defined on its instances.
class A(models.Model):
slug = models.SlugField()
class Meta:
abstract = True
class B(A):
slug = models.CharField()
As an aside, as things stand with your models this is a pointless hierarchy because the slug field on B overrides the slug field that is being inherited from A and therefore there is currently zero shared custom functionality between the two definitions. You may as well just have B inherit from models.Model directly.
Currently, most of my models look like this:
class A(models.Model):
# model attributes
class Meta:
db_table = 'A'
class B(models.Model):
# model attributes
class Meta:
db_table = 'B'
Is there a way to do this automatically? I tried adding the meta class after defining the class, but because of how Django handles Meta classes for models, this doesn't work. Am I just stuck defining the Meta classes by hand?
Not sure why you want to do that but you could do something like:
for model in models:
model._meta.db_table = model.__class__.__name__
I created a model which can be inherited in other models
Parent Model
class Edit_Lane_Info(models.Model):
lane_info = models.OneToOneField(Edit_Lane, related_name='$(class)s', on_delete=models.CASCADE)
def delete(self, *args, **kwargs):
super().delete(*args, **kwargs)
if self.lane_info:
self.lane_info.delete()
class Meta:
abstract = True
class Status (Edit_Lane_Info, models.Model): # parent class inherited
......
class Anpr(Edit_Lane_Info, models.Model): # parent class inherited
....
class Sensor_Details(Edit_Lane_Info, models.Model): # parent class inherited
.............
Now my question is how can I pass related_name in Edit_Lane_Info(parent model) uniquely. I used related_name='$(class)s, but not working
Edit_Lane model
class Edit_Lane(models.Model):
Anpr_Ip = models.GenericIPAddressField(default="NA")
Your related_name contains $ instead of %
To work around this problem, when you are using related_name, part of the name should contain the %(app_label)s or %(class)s
EDIT:
For the the inheritance, you don't need to inherit from models.Model in each following class:Status, Anpr, Sensor_Details since Edit_Lane_Info is already inherited from models.Model
You should have it that way
Edit_Lane_Info(models.Model)
class Status (Edit_Lane_Info):
class Anpr (Edit_Lane_Info):
class Sensor_Details (Edit_Lane_Info):
Django nests the Meta class inside to the plural in models.py:
class Entry(models.Model):
....
class Meta:
verbose_name_plural = 'entries'
'entries' overrides 'entrys'.
I guess this could be done easily without employing a class if I design Django.
class Entry(models.Model):
verbose_name_plural = 'entries'
# set verbose_name_plural as a class attribute
What's the advantage of nested class over a class attribute?
The short answer is roughly that all attributes directly on the class that inherits models.Model should correspond to a column/field in the database table.
class Meta is then the place where you put all other non-column/field related configuration such as verbose_name_plural or label.
Docs explaining it in detail here