Django: parametrizing db_table for inheritance - django

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>]

Related

Common fields for different django models in one place

I have some columns that are repeated in multiple models. is there any solution to place them somewhere and use it any model?
You can achieve this by creating base classes and inheriting them in your models.
Example:
class TimestampsModel(models.Model):
#classmethod
def get_fields(cls, fields: tuple):
return fields.__add__(('created_at', 'updated_at'))
created_at = models.DateTimeField(("created_at"), auto_now_add=True)
updated_at = models.DateTimeField(("updated_at"), auto_now=True)
You can also make it abstract and Django won't create migrations for this.
class Meta:
abstract = True
Finally, a model would be:
class Blog(baseModels.TimestampsModel):
class Meta:
db_table = "blog"
title = models.CharField(max_length=100)

Django change IntegerField to DecimalField on inherited model

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.

Serialize Model from Derived (Abstract) Model

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.

How can I split a Django model into multiple models that inherit from the first

I have a Django model used extensively in my app. I'd like to create another model that inherits from that one so I can continue using the original model throughout the code, but move a field to the new model
I have:
class MyModel(models.Model):
field1 =...
field2=...
field3=...
I want to move field3 to a new model:
class MyModel2(MyModel):
field3=...
Then I'd like MyModel instances where field3 is not null to become MyModel2 instances.
The code would continue to refer to MyModel, but in some special cases, I'd use MyModel2 instead. Is this possible? Advisable? Is there a better way? I considered making a base abstract model that both could inherit from, but then you can't use the abstract model in forms and things.
Actual model:
class Unit(models.Model):
address = models.ForeignKey(Address)
name = models.CharField(max_length=500, verbose_name="Unit Name")
payments = GenericRelation("Payment", content_type_field='content_type', object_id_field='object_pk')
permissions = GenericRelation("CustomPermission", content_type_field='content_type', object_id_field='object_pk')
association = models.ForeignKey(Association, blank=True, null=True)
def __unicode__(self):
return self.name
"association" is the field I want to move to another model.
I guess you should use abstract = True https://docs.djangoproject.com/en/1.10/topics/db/models/#abstract-base-classes
class MyModel(models.Model):
field1 =...
field2=...
field3=...
class Meta:
abstract = True
class MyModel2(MyModel):
field4=...
class AssociationBase(models.Model):
association = models.ForeignKey(Association, blank=True, null=True)
class Meta:
abstract = True
class Unit(AssociationBase):
address = models.ForeignKey(Address)
name = models.CharField(max_length=500, verbose_name="Unit Name")
payments = GenericRelation("Payment", content_type_field='content_type', object_id_field='object_pk')
permissions = GenericRelation("CustomPermission", content_type_field='content_type', object_id_field='object_pk')
def __unicode__(self):
return self.name

How to retrieve the app name from within my model declaration

In my application pos, I have the following model::
class Receipt(Model):
class Meta:
db_table = 'pos_receipt'
I want to rename the table as pos_receipt_ghost and I don't want to hardcode the app name.
I want to do this:
class Receipt(Model):
class Meta:
db_table = '%s_receipt_ghost` % get_app_name()
Does something like get_app_name exists ?
Name of the app is available in Meta.app_label
class Receipt(Model):
class Meta:
pass
Receipt._meta.db_table = '%s_receipt_ghost' % Receipt._meta.app_label
Or
class Receipt(Model):
class Meta:
db_table = '%s_receipt_ghost'
Receipt._meta.db_table %= Receipt._meta.app_label