0

Let's say I have these two models (in models.py file):

class FullName (models.Model):
    firstName = models.CharField(max_length=30,null=True,blank=False,unique=True)
    lastName = models.CharField(max_length=30,null=True,blank=False,unique=True)

class Address (models.Model):
    addressLine = models.CharField(max_length=30,null=True,blank=False)
    city = models.CharField(max_length=30,null=True,blank=False)
    state = models.CharField(max_length=30,null=True,blank=False)
    zipcode = models.CharField(max_length=30,null=True,blank=False)

How can I merge these two models in a new model but with the same Id? So it becomes:

class FullName (models.Model):
    firstName = models.CharField(max_length=30,null=True,blank=False,unique=True)
    lastName = models.CharField(max_length=30,null=True,blank=False,unique=True)

class Address (models.Model):
    addressLine = models.CharField(max_length=30,null=True,blank=False)
    city = models.CharField(max_length=30,null=True,blank=False)
    state = models.CharField(max_length=30,null=True,blank=False)
    zipcode = models.CharField(max_length=30,null=True,blank=False)

class AllInformation (models.Model):
    firstName = models.CharField(max_length=30,null=True,blank=False,unique=True)
    lastName = models.CharField(max_length=30,null=True,blank=False,unique=True)
    addressLine = models.CharField(max_length=30,null=True,blank=False)
    city = models.CharField(max_length=30,null=True,blank=False)
    state = models.CharField(max_length=30,null=True,blank=False)
    zipcode = models.CharField(max_length=30,null=True,blank=False)

    (all fields should be inherited from FullName and Address models)

PS: In my views.py file I called a save method like that:

fullNameData = FullName(request.POST)
fullNameData.save()
        and
AddressData = Address(request.POST)
AddressData.save()

Thanks in advance and I really appreciate who answers that because I see that many people having the same problem. I also took a look at the OneToOneField from django docs but I understood nothing to be honest xD

2 Answers 2

1

A One-To-One would probably be the way to go, it's just a ForeignKey so you don't have duplicate data in the DB

Your Model would look like this

class AllInformation(models.Model):
    fullname = models.OneToOneField(FullName, on_delete=models.CASCADE)
    address = models.OneToOneField(Address, on_delete=models.CASCADE)

And then your save method in the view would look something like this:

# save the full name
fullNameData = FullName(request.POST)
fullname = fullNameData.save()

# save the address
AddressData = Address(request.POST)
address = AddressData.save()

# create the information 'connector'
informationObj = AllInformation.objects.create(fullname=fullname, address=address) 

# example uses
informationObj.fullname.firstName 
informationObj.fullname.lastName 
informationObj.address.city 

Personally I'd just combine all three into a single form like:

forms.py
from django import forms
# + import all 3 models

# Note: NOT a model form, this is Custom Form so it can handle more than 1 model
class InformationForm(forms.Form):

    # I Made some fields required so a form submit will always create both a FullName + Address Object
    # - else it's extra code to handle that + I assume you want both anyways

    firstName = forms.CharField(required=True)
    lastName = forms.CharField(required=True)

    addressLine = forms.CharField(required=True)
    city = forms.CharField()
    state = forms.CharField()
    zipcode = forms.CharField()

    def __init__(self,  *args, **kwargs):
        # Holds Obj if it's an Edit Form (needs to pop here as super() doesn't like it)
        self.instance = kwargs.pop('instance') if 'instance' in kwargs else None

        super(InformationForm, self).__init__(*args, **kwargs)

        if self.instance:
            # is an edit form, set initial fields
            self.initial = {
                'firstName': instance.fullname.firstName, 
                'lastName': instance.fullname.lastName, 
                'addressLine': instance.address.addressLine,
                'city': instance.address.city,
                'state': instance.address.state,
                'zipcode': instance.address.zipcode,
            }

        # Add HTML attributes / HTML Validation
        self.fields['firstName'].widget.attrs={'maxlength': '30'}
        self.fields['lastName'].widget.attrs={'maxlength': '30'}

        self.fields['addressLine'].widget.attrs={'maxlength': '30'}
        self.fields['city'].widget.attrs={'maxlength': '30'}
        self.fields['state'].widget.attrs={'maxlength': '30'}
        self.fields['zipcode'].widget.attrs={'maxlength': '30'}

    def is_valid(self):
        valid = super(InformationForm, self).is_valid()

        # Check for Duplicates!

        if FullName.objects.filter(firstName= self.cleaned_data.get('firstName'), lastName= self.cleaned_data.get('lastName')).first():
            self.add_error('firstName', 'FullName Already Exists')
            self.add_error('lastName', 'FullName Already Exists')
            valid = False

        if Address.objects.filter(
            addressLine = self.cleaned_data.get('addressLine'),
            city = self.cleaned_data.get('city'),
            state = self.cleaned_data.get('state'),
            zipcode = self.cleaned_data.get('zipcode')
            ).first():
            self.add_error('addressLine', 'Address Already Exists')
            self.add_error('city', 'Address Already Exists')
            self.add_error('state', 'Address Already Exists')
            self.add_error('zipcode', 'Address Already Exists')
            valid = False
        return valid

    def save(self):
        # There is no .save(commit=False) method with this form.

        if self.instance:
            # is an edit form

            self.instance.fullname.firstName = self.cleaned_data.get('firstName'),
            self.instance.fullname.lastName = self.cleaned_data.get('lastName'),
            self.instance.fullname.save()

            self.instance.address.addressLine = self.cleaned_data.get('addressLine'),
            self.instance.address.city = self.cleaned_data.get('city'),
            self.instance.address.state = self.cleaned_data.get('state'),
            self.instance.address.zipcode = self.cleaned_data.get('zipcode'),
            self.instance.address.save()

            return self.instance
        else:
            # is a new form

            fullNameObj = FullName.objects.create(
                firstName = self.cleaned_data.get('firstName'),
                lastName = self.cleaned_data.get('lastName'),
            )
            addressObj = Address.objects.create(
                addressLine = self.cleaned_data.get('addressLine'),
                city = self.cleaned_data.get('city'),
                state = self.cleaned_data.get('state'),
                zipcode = self.cleaned_data.get('zipcode'),
            )

            informationObj = AllInformation.objects.create(
                fullname=fullNameObj, address=addressObj
            ) 
        return informationObj
views.py
from django.shortcuts import render, redirect, get_object_or_404
# + import form & AllInformation

def informationFormView(request, pk=None):

    # This being None = New Form
    informationObj = None

    if pk:
        informationObj = get_object_or_404(AllInformation, pk=pk)

    infoform = InformationForm(data=request.POST or None, instance=informationObj)

    if request.method == 'POST':
        if infoform.is_valid():
            infoform.save()

            redirect('success')

        # on not valid it'll re-render the page with errors 

    data = {
        'obj': informationObj
        'form': infoform,
    }
    return render(request, 'informationForm.html', data)
urls.py
from django.urls import path
from . import views

urlpatterns = [

    # Two URLs -> 1 View
    path('informationform', views.informationFormView, name='informationFormView'),
    path('informationform/<int:pk>', views.informationFormView, name='informationFormView'),

    ]
informationForm.html
  • Basic form ripped from Docs, changed the Action to handle edits
<form action="{% if obj %}{% url 'informationFormView' pk=obj.pk %}{% else %}{% url 'informationFormView' %}{% endif %}" method="post">
    {% csrf_token %}
    {{ form }}
    <input type="submit" value="Submit">
</form>
Sign up to request clarification or add additional context in comments.

Comments

0

Solution:

When submitting the FullName form I just do:

data = AllInformation(firstName = request.POST.get("firstname"), lastName = request.POST.get("lastname"))
data.save()

Then in the 2nd function when submitting the Address form, I just do:

AllInformation.objects.filter(firstName=the first name got from FullName Form).update(addressLine = value, city = value, ... )

Hope it helps anyone who is trying to merge two (or more) models in one other model that should contain all of the previous model fields.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.