Choosing the right user inheritance method for django 1.5 - django

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.

Related

Create a Django's model which can have one of two types

I have a model Client which can be one of two types: PJ or PF. That means that a Client can have the fields of a PJ model or the fields of a PFmodel.
But I'm not sure how I can do it using the Django's models and admin app. I would like to give the user the option to select which type the Client is and then the appropriate fields will be shown to him/her.
Can someone help me with this problem? Should I use some kind of Design Pattern or how should I create my models?
Thanks in advance.
Model PF:
class PF(models.Model):
name = models.CharField(max_length=512)
card = models.IntegerField(unique=True)
Model PJ:
class PJ(models.Model):
ie = models.IntegerField(unique=True, null=True, blank=True)
Model Client:
class Client(models.Model):
type = models.SmallIntegerField(default=0) # 0=PF, 1=PJ
First I'd recommend to look at the commonality between these two models and use inheritance if you can. If a type field is inevitable, I'd recommend using CharField with choices instead.
If the two models are drastically different, I'd recommend separating these two models completely, and call them InternalClient, ExternalClient, however the name would make sense to the data model.

django models-design: "ptr field is required"

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

Django parent model and subclassing again

say i have
class Visualizer(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, editable=False, null=True, blank=True )
title = models.CharField(max_length=255)
description = models.TextField()
feed = models.ForeignKey(Feed)
channels = models.ManyToManyField(Channel)
And in my project there can be any number of visualizers that can have extra attributes...
like one visualizer can have a 'base_color' extra attribute, and for another 'change_by_type' extra attribute... etc.. as:
#there can be 5 to 10 visualizer types VisualizerA, VisualizerB ...
class VisualizerA(models.Model):
#base visualizer attributes
base_color = models.CharField()
For now i am doing by adding an attributes text field to the base Visualizer model not adding any sub classes and keep the properties as json string. But i am having hard times with the forms... Is there a better way?
Is subclassing a choice? (But there can be 5 or 10 types of visualizer )
i need a way of doing this right...
Depending or your requirements "Django dynamic model fields" may be the solution. See post
Django dynamic model fields
In terms of of inheritance you can have Model inheritance with specialized Forms
Here is "Advanced Django Forms Usage" http://www.slideshare.net/pydanny/advanced-django-forms-usage
and/or Forms inheritance with common Model
see post http://pydanny.com/overloading-form-fields.html
Subclassing is imo best solution, in database You will have 1 table for all Visualizers with all fields from base class and 1 table for each child class with id column that will have same values as in base class and columns from child class fields. It's one to one relation under the hood, but when You save new instance of child model, django will automatically make corresponding field in base model.
More here: Django model interhitance

Django: Foreign key relation depending on choice

In Django, is there a way to create the following dynamic relationship between models?
class ClothingMale(models.Model):
# male specific fields
class ClothingFemale(models.Model):
# female specific fields
class Person(models.Model):
gender = models.IntegerField(max_length=2, choices=GENDER_CHOICES, blank=True)
clothes = models.ForeignKey(???)
I am using a ModelForm for Person. The clothes fields inside the form should change dynamically depending on which gender was selected. I am aware of GenericForeignKeys but I was wondering if there is better way to solve this?
IMHO it's a question of DB design; I would go for a PersonClothing superclass and subclass it with MalePersonClothing and FemalePersonClothing. The PersonClothing superclass would be a Django abstract base class; a specific class useful when you want to put some common information into a number of other models.
To do it just specify the following option in your model's meta:
class Meta:
abstract = True
One option is to use GenericForeignKey. This of course has int's down-sides, for exampl you cannot filter() on GenericForeignKey
Another option is to use model inheritance, which also has quite a few gotchas.

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.