Django: Foreign key relation depending on choice - django

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.

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.

Displaying all fields of Foreign Key Model

What I want is to retrieve all the fields belonging to a Model of a foreign key.
My models for example:
class BaseProduct(models.Model):
name = models.CharField(max_length=256)
variant = models.CharField(max_length=256, default='N/A')
type = models.ForeignKey(ProductType)
class ProductType(models.Model):
name = models.CharField(max_length=256,blank=False,null=False)
sofa = models.ForeignKey(SofaProduct, blank=True, null=True)
toaster = models.ForeignKey(ToasterProduct, blank=True, null=True)
These are just examples, there can be any number of ProductType models each with any number of fields.
In my template I can display all the fields of the BaseProduct by using the BaseProduct ID. What I want is to display all the fields of the FK.
For example if type = sofa in BaseProduct, I need to retrieve and display all sofa fields as well as BaseProduct fields.
(disclaimer: I have a tendency to give really long answers. You'll have to forgive me for that)
First rule of schema design - It should reflect your real world business logic (not the actual business action mind you, just the implications of the relationships). For example, if I have a class Person I can create a class Pet with a foreginKey to Person which translates to - every person can have multiple pets.
If we apply that logic to your schema we see that ProductType is a class that has a foreignKey to both Sofas and Toasters, which means each Toaster can have multiple Sofas and vice versa. Last time I checked, I never heard of a Sofa that had a Toaster.
In other words - you need to think what you're actually trying to achieve here. I'm guessing BaseProduct is a basic class that has common fields, and Sofa and Toaster are different types of products. Since they are different, they have their own special fields, and shouldn't be related, so it makes sense to have them as separate models. So why do you even need ProductType? To define the name Toaster? You're already defining an entire model! Why do you need to keep its name on a different table (and not, say, some custom method that always returns "I am a toaster, hear me roar")?
My best guess is that you want to be able to define new types of products on the go. However, if you intend to keep them separated on the model level, then you'll have to create a model for each new product. And if you want to be able to simple define a new model with ProductType, then you either need to have one Product class to manage them all, or you want a complicated dynamic system that can create new models on the fly.
Let's break those options down:
Create a generic product and a type class, like you did there:
class ProductType(models.Model):
name = models.CharField(max_length=256,blank=False,null=False)
class Product(models.Model):
name = models.CharField(max_length=256)
variant = models.CharField(max_length=256, default='N/A')
type = models.ForeignKey(ProductType)
Now each product can only be of one type, and you can always create new types on the go. This of course means all Product objects will share the same fields, and is very limiting. You won't have the same flexibility for each type like you would before (no sofa-only fields), but on the other hand it will be easier to create dynamic types of objects - you just define a new ProductType and bam you have a whole new group of products.
Create a basic abstract Product model, and define a new sub-model for each new type of product. You'll have a lot more flexibility for each one, but defining new types will always require defining a new model and setting up a table for it. With this scheme you don't need the ProductType object at all because the different models define the different types (there's no need for duplicity).
You can create some kind of admin page for the process, but it's not going
to be very easy to setup, and you might find yourself eventually with too many tables
(which can be especially problematic if you need to sometimes query
on all products - you'll have to join a lot of different tables,
which is not very efficient).
Use a non-relational database with some dynamic-models know how and disco*
*ok, it's actually more complicated than that, but the explanation on how to combine them is way too long, even for my answer. If it seems over your head, forget about it. If you have some idea about how non-relation databases work, you can probably figure it out yourself
Your question is somewhat unclear.
I think you want Django modal forms to display all fields of an modal.
def ListForm(Forms.form):
model = MyModel
fields='__all__' #Sets display all
fk_name ="Model_to_use" #Is needed when your model has more then one fk
Django model form
You can use _set for accessing related objects. For example, if you have two models like these:
class MyModel(models.Model):
name = models.CharField(max_length=200)
somedata = models.CharField(max_length=200)
class AnotherModel(models.Model):
name = models.CharField(max_length=256,blank=False,null=False)
referral = models.ForeignKey(MyModel)
type = models.CharField(max_length=256,blank=False,null=False)
you can access the name field of AnotherModel with
>>> m = MyModel.objects.get(id=1)
>>> m.AnotherModel_set.all()[0].name
See: https://docs.djangoproject.com/en/dev/topics/db/queries/#related-objects
On a side note, you should probably rethink your models structure, as yuvi pointed out.

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

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.

Django ModelForm for MultiTableInheritance

So I have a model heirarchy using multi-table inheritance and I was wondering if there was a some sort of ModelForm or similar approach for creating an object like a normal model form and have the user choose which of the subclasses they want to use in the form in like a choice field.
The heirarchy is as follow:
class Base(models.Model):
field1 = models.CharField(max_length=10)
field2 = models.CharField(max_length=20)
class A(Base):
pass
class B(Base):
pass
class C(Base):
pass
I can't use Meta abstract models because I have one class that needs a foreign key to the Base which is why I'm using multi-table inheritance and in the future the child classes may have additional field. Do you have any suggestions of how I go about doing this?
Currently the way I'm doing it is using a normal form and having all the common fields in that form as well as a choice field which they can select the type of the model they want to use and then I've created a save method which interprets the type from the choice field and creates the object of that type. I can't help but feel there is a better method of doing this.