Django data entry with relationships, what is the standard or most effecient way?

Viewed 26

With a model without a relationship the, the most efficient way for data entry would be to use a django.forms.ModelForm. Take the following example:

class Customer(models.Model):

    first_name = models.CharField(max_length=120)
    last_name = models.CharField(max_length=120)

    def __str__(self):
        return f"{self.first_name} {self.last_name}"


class CustomerModelForm(forms.ModelForm):

    class Meta:
        fields = ("first_name", "last_name")
        model = Customer


form = CustomerModelForm(data={"first_name": "Jon", "last_name": "Doe"})
if form.is_valid():
    form.save()

But when you add in relationships, what is the most efficient or best standard to follow, let's update the model to:

class Customer(models.Model):

    first_name = models.CharField(max_length=120)
    last_name = models.CharField(max_length=120)
    address = models.ForeignKey(
        "Address",
        on_delete=models.PROTECT
    )

    def __str__(self):
        return f"{self.first_name} {self.last_name}"


class Address(models.Model):

    street = models.CharField(max_length=120)
    city = models.CharField(max_length=120)
    state = models.CharField(max_length=2)
    zip_code = models.CharField(max_length=5)

    def __str__(self):
        return f"{self.street}, {self.city}, {self.state}  {self.zip_code}"

One solution might be:

class CustomerModelForm(forms.ModelForm):

    class Meta:
        fields = ("first_name", "last_name", "address")
        model = Customer


class AddressModelForm(forms.ModelForm):

    class Meta:
        fields = (
            "street",
            "city",
            "state",
            "zip_code"
        )
        model = Address


class Customer(forms.Form):

    first_name = models.CharField(max_length=120)
    last_name = models.CharField(max_length=120)
    street = models.CharField(max_length=120)
    city = models.CharField(max_length=120)
    state = models.CharField(max_length=2)
    zip_code = models.CharField(max_length=5)

    def save(self):
        address_form = AddressModelForm(
            data={
                "street": "123 Sycamore St",
                "city": "Eagles Harbor",
                "state": "AD",
                "zip_code": "12345"
            }
        )
        if address_form.is_valid():
            address = address_form.save()
            customer_form = CustomerModelForm(
                data={"first_name": "Jon", "last_name": "Doe"}
            )
            if customer_form.is_valid():
                return customer_form.save()

Or would you skip the model forms entirely:

class Customer(forms.Form):

    ...

    def save(self):
        address, c = Address.objects.get_or_create(
            street="123 Sycamore St",
            city="Eagles Harbor",
            state="AD",
            zip_code="12345"
        )

        customer, c = Customer.objects.get_or_create(
            first_name="Jon",
            last_name="Doe",
            address=address,
        )

        return customer
1 Answers

Not sure if I understand you, but can see what you are doing, I would make it quite simple:

class Customer(models.Model):
    first_name=..
    ...
    zip_code=..

class CustomerForm(forms.ModelForm):
    class Meta:
        fields = ('__ALL__')
        model = Customer

When using an ORM it helps to imagine what happens at the database level. Not sure why you would create a whole new table just for adresses.

Edit: You can still do it like this, and have address = models.ForeignKey(Address) on your Customer model. I think you are making a quite simple thing into something more complex than it really is. You are also hard-coding values, there is no need for that.

Related