Model Inheritance or Foreign Key? - python

I'm sure there are probably several ways to do what I am achieving, but have run into some problems. I have a "Member" model and I'm also trying to add a "Dependent" model that inherits some fields and data from the parent (Member) but also has some of the same fields, but their own data. What would be the best way to achieve this? ForeignKey, OneToOne, or ManyToMany, or is it even possible?
Example:
class Member(models.Model):
name = models.CharField(max_length=128)
address = models.CharField(max_length=128)
age = models.DateField()
class Dependent(models.Model):
name = models.CharField(max_length=128) (different name)
address = models.CharField(max_length=128) (same address as Member)
age = models.DateField() (different age)
Thank you for your help.

Since Dependent has the same fields as Member but has some extra fields, you can make both Dependent and Member inherit an abstract base class (thanks to #WillemVanOnsem for pointing it out) to avoid redefining the same fields, and since Member and Dependent have a parent-child relationship, you should add a foreign key to Member as an additional field in the Dependent model. You can also override the save method of Member to make it sync the addresses of its Dependent children when saved.
class Person(models.Model):
name = models.CharField(max_length=128)
address = models.CharField(max_length=128)
age = models.DateField()
class Meta:
abstract = True
class Member(Person):
def save(self):
super().save()
self.dependents.exclude(address=self.address).update(address=self.address)
class Dependent(Person):
parent = models.ForeignKey(Member, related_name='dependents')
extra_field = ...

Related

Pre-populate form field with data from table linked via foreign key

Probably a very novice Django question, but here goes. In my Django project, I have this in my models
#models.py
class Classes(models.Model):
classcode = models.CharField(max_length=15)
classname = models.TextField()
students = models.ManyToManyField(User)
class Test(models.Model):
classes = models.ForeignKey(Classes, on_delete=models.CASCADE)
name = models.TextField(max_length=100)
points = models.ManyToManyField(User, default=0)
I also have a form for Test, which is:
#forms.py
class TestForm(forms.ModelForm):
class Meta:
model = Test
fields = ('classes', 'name')
When I get to the actual form, the drop-down menu for 'classes' in TestForm merely comes up with 'Classes object' for the number of 'Classes' that I have in my DB. I want to change that so the form lists the names of the classes, which are stored in the 'Classes' model as 'classname'
Can anyone point me in the right direction please?
The easiest way to do it is to provide a string representation of your object, this would replace any where you access the class throughout your application
class Classes(models.Model):
classcode = models.CharField(max_length=15)
classname = models.TextField()
students = models.ManyToManyField(User)
def __str__(self):
return "{0}: {1}".format(self.classcode, self.classname)
From the docs
The __str__ (__unicode__ on Python 2) method of the model will be called to generate string representations of the objects for use in the field’s choices; to provide customized representations, subclass ModelChoiceField and override label_from_instance.

Dynamically creating the related_name from META class

Most of my Django models use the same User Mixin, because of this I would like to dynamically create the related_name for the field.
I would like it to be the class name where TestModel becomes test_models or maybe even a set name from the meta class on the main model.
I have looked at self__class__.__name__ but this give me the name of the User class.
Would it be possible to do something like below, if so how....
class User(models.Model):
user = models.ForeignKey(USER, related_name=META.related_name)
class Meta:
abstract = True
class TestModel(User):
title = models.CharField(max_length=80)
class Meta:
related_name = "test_model"
I think it might be sufficient to handle this like it is documented here.
# myapp/models.py
class User(models.Model):
user = models.ForeignKey(
USER,
related_name="%(app_label)s_%(class)s_related"
)
class Meta:
abstract = True
class TestModel(User):
title = models.CharField(max_length=80)
This way the related name would dynamically become myapp_testmodel_related. Of course you can tweak the name and simplify the pattern, if it is certain that the names can't clash between multiple apps.

Django model inheriting from different models, which each inherit from a single class

I am creating a form with Django. This form's ModelForm is built upon multiple models that inherit from base models. The structure of the models is similar to this:
class BaseModel(models.Model):
first_name = models.CharField("First name", max_length=20)
middle_name = models.CharField("Middle name", max_length=20)
last_name = models.CharField("Last Name", max_length=20)
email = models.EmailField("Email address")
phone = models.CharField("Phone number", max_length=16)
Is inherited by
class EmployerModel(BaseModel):
company = models.CharField("Company", max_length=20)
and..
class AdvisorModel(BaseModel):
department = models.CharField("Department", max_length=20)
which is contained in my highest level model (the model that is used in my ModelForm):
class FormModel(EmployerModel, AdvisorModel):
another_field = models.CharField(max_length=20)
and_another_field = models.CharField(max_length=20)
#...
class FormModelForm(forms.ModelForm):
class Meta:
model = FormModel
Can I take this approach while making the form and avoid ORM errors because I have duplicate field names? Is there a way to separate and say; "THESE fields are for a 'Employer'; THESE fields are for an 'Advisor'?"
EDIT
It looks like I need to go with abstract base classes, but I don't know if that fixes the multiple inheritance problem.
Go abstract with parent models, I've successfully written models with this kind of definition:
class Content(ModeratedModel, NullableGenericModel, RatedModel, PicturableModel, PrivacyModel, CommentableModel):
pass
and ModelForms using Content as a model work fine.

Validating admin site save in Django

I have the following two classes defined in models.py
class Part(models.Model):
name = models.CharField(max_length=32)
value = models.CharField(max_length=32)
class Car(models.Model):
name = models.CharField(max_length=32)
parts = models.ManyToManyField(Part)
So my model allows for multiple parts, but I want the part names to be unique. For example, only one part with name "engine" should be allowed for a given car. How do I enforce this uniqueness?
Things I have looked into:
class save()
Overriding the default save() for Car doesn't help because parts isn't updated until save is hit.
class save_model()
This will not work because it always saves.
So what are my options for enforcing uniqueness of part names?
UPDATED:
Although I want only one part with name engine to be associated with a car, I still want the ability to define multiple parts with name engine, of course with different values.
So a car with can have a part (part.name=Engine and part.value=V6) and another car can have a part (part.name=Engine and part.value=V4, but a car can't have two parts that have part.name == engine.
EDIT:
class Part(models.Model):
name = models.CharField(max_length=32)
value = models.CharField(max_length=32)
class CarPart(models.Model):
car = models.ForeignKey(Car)
part_type = models.CharField(max_length=32, unique=true)
part = models.ForeignKey(Part)
class Car(models.Model):
name = models.CharField(max_length=32)
treat part_type as part type id (e.g. type='engine') for engines it will be unique
more about ForeignKey

If I use Multi Table Inheritance for a set of related classes can they have separate admins?

I need to choose between Multi Table Inheritance and ABC Inheritance and I am not sure if I can still have separate admins for each subclass. I need all the base class fields and all the fields from the subclass in each subclass admin screen.
I am sorry if this is a stupid question, I am still not even finished with the manual but I have a deadline.
Of course, you can have an admin screen for each of your models, and all the fields from base model would be present on child models.
from django docs:
each model in the hierarchy is a model all by itself
Then, if you have:
models.py
class Service(models.Model):
owner = models.ForeignKey('auth.User')
name = models.CharField(max_length=128)
class VariationAService(Service):
# fields
class VariationBService(Service):
# more fields
You can do something like this:
admin.py
class ServiceAdmin(admin.ModelAdmin):
[...]
class VariationAServiceAdmin(admin.ModelAdmin):
[...]
class VariationBServiceAdmin(admin.ModelAdmin):
[...]
You'll get all fields either way. The difference between the two is that with multi-table inheritance...
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
...you'll get both a Place object and Restaurant object, which can both be edited in the admin, but with abstract base classes...
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Meta:
abstract = True
class Restaurant(Place):
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
...you'll only get a Restaurant object, which can be edited in the admin.

Categories