django models-design: "ptr field is required" - django

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__'

Related

How to merge two models inherited from Django into one serializer

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()
...

Why Abstract=True dosen't inherit in Meta class of django model

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

Django inheriting from multiple model classes

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/

Choosing the right user inheritance method for django 1.5

I have a situation where I need to subclass a custom user model for a django 1.5 project (related question/background here: Subclassing AbstractUser in Django for two types of users )
I need an abstract user class SchoolPerson and a number of subclasses (Student, Teacher, etc) based on this. I think I've resolved that I need to have the user model in a separate DB table to the subclasses as other apps rely on AUTH_USER_MODEL, of which there can only be one.
So the way I see it, I have to options to do this: add one-to-one to the standard user model in my abstract SchoolPerson class:
class SchoolPerson(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
...
class Meta:
abstract = True
class Student(SchoolPerson):
year_level = models.CharField(max_length=3)
...
class Teacher(SchoolPerson):
govt_id = models.CharField(max_length=10)
...
Or I can make my SchoolPerson model inherit AbstractUser, but keep this class non-abstract:
class SchoolPerson(AbstractUser):
...
#no Meta abstract here
class Student(SchoolPerson):
year_level = models.CharField(max_length=3)
...
class Teacher(SchoolPerson):
govt_id = models.CharField(max_length=10)
...
Are there any advantages to one of these over the other?
I haven't tested this but what I expect is for your first suggestion to create two db tables:
one for Student and one for Teacher each with a foreign key to the AUTH_USER_MODEL.
For the second one I expect Django to create three db tables:
One for the SchoolPerson(which will be exact as the default Users table with the additional fields) and two for Student and Teacher with foreign keys to SchoolPerson.
So I think the answer depends on your requirements.

modeling extra table information with django's contenttypes

I've just started using Django's contenttypes framework (and it's pretty awesome). I have an Area object that has many specialised Block objects - I've modeled it as below.
class Area(models.Model):
...
class SomeBlock(models.Model):
...
class AreaBlock(models.Model):
area = models.ForeignKey(Area)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
block_object = generic.GenericForeignKey('content_type', 'object_id')
This works very well. Now I want to register these specialised blocks in their own table along with extra 'global' information about it.
class BlockRegistrar(models.Model):
...
My problem is joining SomeBlock to it's global information in the BlockRegistrar model. A foreignkey in the block table would be obvious, but it wouldn't ever change and I can't figure out how to use django's ContentType table to do these joins.
Any help?
So AreaBlock.block_object is a GenericForeignKey to one of several possible SomeXXBlock models?
Do you mean every SomeXXBlock record has a corresponding BlockRegistrar record?
The easiest way to do that would be with model inheritance:
class BlockRegistrar(models.Model):
# 'global' fields common to all SomeXXBlock models
...
class SomeBlock(BlockRegistrar):
...
class SomeOtherBlock(BlockRegistrar):
...
Behind the scenes Django automatically creates a OneToOneField linking the SomeXXBlock instance to it's corresponding BlockRegistrar. In Django this is called 'multi-table inheritance'. From your question it sounds like this may be what you want.
If you never need to access a BlockRegistrar object directly, but just want the global fields to be available on all the SomeXXBlock 'child' models then you could use an Abstract base model:
class BlockRegistrar(models.Model):
# 'global' fields common to all SomeXXBlock models
...
class Meta:
abstract = True
class SomeBlock(BlockRegistrar):
...
class SomeOtherBlock(BlockRegistrar):
...
In this case the BlockRegistrar model does not exist as a table in the db and there is no magic OneToOneField added to the SomeXXBlock models.