I'd like to define a new _id autofield in one of the derived classes.
Simply specifying _id field for the derived class results in an error "
A model can't have more than one AutoField."
class Base(models.Model):
class Meta:
abstract = True
class Derived(Base):
_id = models.AutoField(primary_key=True)
Can you specify when its raise an error? I have same configuration in my project which is working fine.
Related
I have an abstract base class and 2 child classes. I want to define the create_product method on the base class, but mypy errors, rightly saying that I haven't defined product on the base class.
How should I do this correctly? I imagine i should declare a sort of empty field on the Base class, but I can't find any docs on this.
Error:
error: Unexpected attribute "product" for model "Base" [misc]
Code:
class Base(Model):
identifier = CharField()
class Meta:
abstract = True
#classmethod
def create_product(
cls,
*,
identifier=identifier,
product=product
):
return cls.objects.create(
identifier=identifier,
product=product # Error here
)
class ChildA(Base):
product = models.OneToOneField(...)
class ChildB(Base):
product = models.OneToOneField(...)
Note I'm using the django-stubs and django-stubs-ext libraries
class BaseModel(models.Model): # base class should subclass 'django.db.models.Model'
creation_date = models.DateTimeField(..) # define the common field1
class Meta:
abstract=True # Set this model as Abstract
Inherit this Base class in models
After creating the abstract base class BaseModel, I inherited this class in my models.
class MyModel1(BaseModel): # inherit the base model class
# define other non-common fields here
...
After creating an object of class 'MyModel1', I want the 'creation_date' field to be shown in admin interface.
So that I can see the datetime when an object of class 'MyModel1' is created.
Solution:
class MyModel1Admin(admin.ModelAdmin):
readonly_fields= ['creation_date',]
admin.site.register(MyModel1,MyModel1Admin)
I am trying to define entity architecture that, if simplified, can be expressed like this:
class M(models.Model):
field_m = models.CharField(max_length=255)
class Meta:
abstract = True
class A(M):
field_a_1 = models.CharField(max_length=255)
field_a_2 = models.CharField(max_length=255)
class Meta:
abstract = True
class B(A):
field_b = models.CharField(max_length=255)
class Meta:
abstract = True
class C(A):
field_c = models.CharField(max_length=255)
class Meta:
abstract = True
class D(A):
field_d = models.CharField(max_length=255)
class Meta:
abstract = True
class DD(D):
class Meta:
abstract = True
class X(B, C, DD):
field_x = models.CharField(max_length=255)
pass
As you can see, X has some mixins (abstract entitites). Each of the mixin has their own custom logic implemented inside them. But ultimately all of them have 1 common parent- abstract class A.
As far as I understand, this should work. And MRO resolution, indeed, works. However, when starting the project I get 2 errors per each field field A (that are inherited in X):
X.field_m : (models.E006) The field 'field_m ' clashes with the field 'field_m ' from model 'X'.
X.field_m : (models.E006) The field 'field_m ' clashes with the field 'field_m ' from model 'X'.
X.field_a_1 : (models.E006) The field 'field_a_1 ' clashes with the field 'field_a_1 ' from model 'X'.
X.field_a_1 : (models.E006) The field 'field_a_1 ' clashes with the field 'field_a_1 ' from model 'X'.
X.field_a_2 : (models.E006) The field 'field_a_2 ' clashes with the field 'field_a_2 ' from model 'X'.
X.field_a_2 : (models.E006) The field 'field_a_2 ' clashes with the field 'field_a_2 ' from model 'X'.
I am working with Django 1.11
There is an old issue ticket here that resulted in making Django validate these kinds of problems
https://code.djangoproject.com/ticket/24542
It is because B and C inherit from A so they will have the same field_m and it is not valid. Django devs decided that Django will validate this instead of
ignore subsequent model fields from abstract model base classes (per MRO-order) with the same name as existing fields.
On a side note. This is bad design and you should keep your inheritance simple as per the docs https://docs.djangoproject.com/en/2.2/topics/db/models/#s-multiple-inheritance
Generally, you won’t need to inherit from multiple parents. The main use-case where this is useful is for “mix-in” classes: adding a particular extra field or method to every class that inherits the mix-in. Try to keep your inheritance hierarchies as simple and straightforward as possible so that you won’t have to struggle to work out where a particular piece of information is coming from.
I.e. we have SomeSeries with several SomeDecors, where ForeignKey of SomeDecor points to SomeSeries. I want both to be abstract and later instantiate several pairs of it (with it's own tables in db). Is it possible?
I.e.
class SomeSeries(models.Model):
class Meta:
abstract = True
vendor = models.ForeignKey(Vendor)
name = models.CharField(max_length=255, default='')
def __unicode__(self):
return "{} {}".format(self.vendor, self.name)
class SomeDecor(WithFileFields):
class Meta:
abstract = True
series = models.ForeignKey(SomeSeries) # some magic here to make ForeignKey to abstract model
texture = models.ImageField()
# -------------------------------------------
class PlinthSeries(SomeSeries): pass
class PlinthDecor(SomeDecor): pass
# Some magic to make PlinthDecor.series points to PlinthSeries
EDIT
Actually I don't want complicity of polymorphic relations, I want pure abstract models just to save typing (what abstract models are initially for). Suppose in my case the simplest way is to exclude ForeignKey from base model and type it only in all inherited models:
class SomeSeries(models.Model):
class Meta:
abstract = True
#...
class SomeDecor(WithFileFields):
class Meta:
abstract = True
series = None #?
#..
texture = models.ImageField()
def do_anything_with_series(self): pass
class PlinthSeries(SomeSeries): pass
class PlinthDecor(SomeDecor): pass
series = models.ForeignKey(PlinthSeries)
You can't create ForeignKey referencing abstract model. It's, even, doesn't make any sense, because ForeignKey translates into Foreign Key Constraint which have to reference existing table.
As a workaround, you can create GenericForeignKey field.
You can not do it because if you create two class inherit from your abstract class to what class your foreignkey should do? for first or for second?
So you need to create GenericForeignKey or not do any field and only after create model inherits from your abstract model add your foreign key.
I'm trying to create a Django ORM mapping that's compatible with an existing data model, so I'm trying to work with an existing set of table and column names.
I've got a multi-table inheritance situation where a class InformationObject derives from class Object. I'd like to let Django handle this the usual way:
class Object(models.Model):
class Meta:
db_table = "object"
class InformationObject(Object):
class Meta:
db_table = "information_object"
In this case Django would automatically create a one-to-one field on the inheriting model called object_ptr_id. However, on the schema I'm constrained to use, the reference to the Object is simply called "id". So:
Is there a way to somehow specify the name of the column Django auto-magically uses for multi-table inheritance?
The alternative, which I'll have to use otherwise, is to use an explicit one-to-one field, but then I won't be able to inherit non-database methods from the Object model:
class Object(models.Model):
class Meta:
db_table = "object"
class InformationObject(models.Model):
class Meta:
db_table = "information_object"
id = models.OneToOneField(Object, primary_key=True, db_column="id")
Any ideas? Maybe I could create a common base class for both of them and put non-db methods there...?
From the django docs (development version):
As mentioned, Django will automatically create a OneToOneField linking your child class back any non-abstract parent models. If you want to control the name of the attribute linking back to the parent, you can create your own OneToOneField and set parent_link=True to indicate that your field is the link back to the parent class.
As mentioned by #fusion quoting from the docs, you will have to create a OneToOneField if you want to specify the column, while using model inheritance. The inherited fields will be available in the child class in both self scope AND the one-to-one field.
class Object(models.Model):
class Meta:
db_table = "object"
column_1 = models.CharField()
class InformationObject(Object):
class Meta:
db_table = "information_object"
# arbitrary property name (parent_link)
parent_link = models.OneToOneField(Object, primary_key=True, db_column="id", parent_link=True)
In this example:
>>> inf_obj = InformationObject.objects.get(pk=1)
>>> print inf_obj.column_1 == inf_obj.parent_link.column_1
True