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.
Related
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):
...
In Django I have 2 models that are inherited from an abstract base class. The base class has an IntegerField that I want to rename and change to DecimalField for some instances. There is a ForeignKey linking the 2 child models. I've read about model inheritance in docs, but there seems to be some constraints. What's the best way to change the IntegerField to DecimalField?
class Parent(models.Model):
intfield = models.IntegerField()
class Meta:
abstract=True
class Child1(Parent):
addedfield = models.CharField(max_length=20)
class Child2(Parent):
addedfield2 = models.DecimalField(max_digits=10, decimal_places=2)
linked = models.ForeignKey(Child1, on_delete=models.CASCADE)
class GrandChild1(Child1):
# change intfield to decimal
class GrandChild2(Child2):
# change intfield to decimal
# linked to GrandChild1 instead of Child1
You can use extra abstract models to alter the fields in the hierarchy:
class Parent(models.Model):
intfield = models.IntegerField()
class Meta:
abstract = True
class DescendantType1(Parent):
"""This is an abstract model that inherits from the Parent model, with the "type 1"
attributes.
"""
addedfield = models.CharField(max_length=20)
class Meta:
abstract = True
class DescendantType2(Parent):
"""This is an abstract model that inherits from the Parent model, with the "type 2"
attributes.
"""
addedfield2 = models.DecimalField(max_digits=10, decimal_places=2)
linked = models.ForeignKey(
"Child1",
on_delete=models.CASCADE,
# This is required on foreign key fields in abstract models.
# See the "Note about foreign key related names" below.
related_name="%(app_label)s_%(class)s_related",
related_query_name="%(app_label)s_%(class)ss",
)
class Meta:
abstract = True
class Child1(DescendantType1):
"""A descendant with "type 1" attributes."""
class Child2(DescendantType2):
"""A descendant with "type 2" attributes."""
class GrandChild1(DescendantType1):
intfield = models.DecimalField(...)
class GrandChild2(DescendantType2):
intfield = models.DecimalField(...)
linked = models.ForeignKey(
"GrandChild1",
on_delete=models.CASCADE,
)
Note about foreign key related names
An abstract model that has a foreign key needs to use a different related_name and related_query_name for each concrete model that inherits from it, otherwise the names for the reverse relationship would be the same for each subclass.
To handle this, django allows you to use template strings with the variables app_label and class so that the names are unique for the child model.
You can find more about this in the documentation.
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.
I have two django models
model A
class A(models.Model):
aname = models.CharField(max_length=64, verbose_name='name')
and model B
class B(models.Model):
bname = models.CharField(max_length=64, verbose_name='name')
mod = models.ForeignKey(A, related_name='a_b',null=True,on_delete=models.CASCADE)
The serializer for model B is
class BSerializer(serializers.ModelSerializer):
mod= ASerializer(many=False, read_only=True)
class Meta:
model = B
fields = (','id','bname','mod.aname')
I want the aname field of model A to be accessed with the serializer of model B. Using mod.aname doesn't work. It says
Field name mod.aname is not valid for model B.
How can i do it?
How about this one? using parameter source inside serializers.CharField:
class BSerializer(serializers.ModelSerializer):
mod = serializers.CharField(
source='mod.aname',
read_only=True
)
class Meta:
model = B
fields = ('id','bname','mod')
Use two underscores when referencing fields of related models as a string, like 'mod__aname'.
class HotelSerializer(serializers.ModelSerializer):
mod= ASerializer(many=False, read_only=True)
class Meta:
model = Hotel
fields = ('id','bname','mod__aname')
This should work if ASerializer looks something like this:
class ASerializer(serializers.ModelSerializer):
class Meta:
model = A
fields = '__all__'
I want to set the db_table Meta class attribute in a base class so that all inherited classes will have their names in it, similar to how Django treats related_name model field attribute:
class BaseModel(models.Model):
class Meta:
db_table = 'prefix_%(class)s'
So the inherited model:
class SubModel(BaseModel):
pass
will have db table prefix_submodel.
Is that possible? Can the Meta class access the inheriting class' model name?
No. You can't do that. It is not that simple to have same table to store for multiple classes.
What you need is probably djeneralize project.
From the examples:
class Fruit(BaseGeneralizedModel):
name = models.CharField(max_length=30)
def __unicode__(self):
return self.name
class Apple(Fruit):
radius = models.IntegerField()
class Meta:
specialization = 'apple'
class Banana(Fruit):
curvature = models.DecimalField(max_digits=3, decimal_places=2)
class Meta:
specialization = 'banana'
class Clementine(Fruit):
pips = models.BooleanField(default=True)
class Meta:
specialization = 'clementine'
which then allows the following queries to be executed:
>>> Fruit.objects.all() # what we've got at the moment
[<Fruit: Rosy apple>, <Fruit: Bendy banana>, <Fruit: Sweet
clementine>]
>>> Fruit.specializations.all() # the new stuff!
[<Apple: Rosy apple>, <Banana: Bendy banana>, <Clementine: Sweet
clementine>]