postelrich
postelrich

Reputation: 3496

Django form for model of models

I have the following models to define a Customer. I figured for reusability to separate out the address and 'person' fields into separate models. Since Customer contains a Person which in turn contains an Address, how can I make a CreateView for Customer? Not quite understanding how to use something like inline_formset to achieve what I want.

models.py:

import localflavor.us.models as us_models
from django.db import models
from datetime import date

class Address(models.Model):
    address1 = models.CharField(max_length=100)
    house_number = models.CharField(max_length=10, blank=True)
    address2 = models.CharField(max_length=100, blank=True)
    city = models.CharField(max_length=50)
    state = us_models.USStateField()
    zip = models.CharField(max_length=5)


class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    creation_date = models.DateTimeField('date created')
    home_phone = us_models.PhoneNumberField()
    work_phone = us_models.PhoneNumberField(blank=True)
    cell_phone = us_models.PhoneNumberField(blank=True)
    email = models.EmailField(blank=True)
    address = models.OneToOneField(Address, primary_key=True)


class Customer(models.Model):
    person = models.OneToOneField(Person, primary_key=True, default=None)
    creation_date = models.DateTimeField('date created', auto_now_add=True)

Upvotes: 1

Views: 167

Answers (1)

user764357
user764357

Reputation:

For your address field, its quite straight forward and you probably want to look at using an inline formset. There is a fair bit of code required for it, but the tutorial is quite straight forward.

However, for the Person/Customer issue, don't forget that models are first and foremost Python objects so you can use lots of OOP inheritance principles. If a Customer is a Person document that:

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    # ... fields trimmed ...
    address = models.OneToOneField(Address, primary_key=True)

class Customer(person):
    creation_date = models.DateTimeField('date created', auto_now_add=True)

Here we've clearly defined the relationship, and the relation is taken care behind the scenes. However, an important caveat, the name and adderss are still in the Person table, so queries for Persons would return Customers too.

Another alternative is using an abstract class, like so:

class Person(models.Model):
    class Meta:
        abstract = True
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    # ... fields trimmed ...
    address = models.OneToOneField(Address, primary_key=True)

class Customer(person):
    creation_date = models.DateTimeField('date created', auto_now_add=True)
class Retailer(person):
    creation_date = models.DateTimeField('date created', auto_now_add=True)

Now, the Person object won't get a database table, and can only be used through inheritance - so we can query for Customers or Retailers, but not Persons.

Upvotes: 1

Related Questions