Search code examples
pythondjangodjango-modelsforeign-keys

Django: Handling Foreign Key value in template


I have recently started working with Django and I am struggling to work with 2 models in a single form. I have looked a lot of questions in stackoverflow but I couldn't find any that answers this question.

I have 2 models - Student & Address

This is my models.py

class Students (models.Model):
    Student_Name = models.CharField(max_length=50, db_column='Student_Name')
    College_Number = models.CharField(
        max_length=10, db_column='College_Number')

    Gender = models.CharField(max_length=50, db_column='Gender')

    Blood_Group = models.CharField(max_length=50, db_column='Blood_Group')

    Set = models.CharField(max_length=50, db_column='Set')

    Standard = models.CharField(max_length=50, db_column='Standard')


class Addresses (models.Model):
    Student_ID = models.ForeignKey(
        Students, on_delete=models.CASCADE, db_column='Student_ID')
    City = models.CharField(max_length=50, db_column='City')
    State = models.CharField(max_length=50, db_column='State')
    Pincode = models.CharField(max_length=50, db_column='Pincode')
    AddressLine1 = models.CharField(max_length=1024, db_column='AddressLine1')
    AddressLine2 = models.CharField(max_length=1024, db_column='AddressLine2')

This is my views.py

def student_create_view(request):
    student_form = StudentFrom(request.POST or None)
    address_form = AddressForm(request.POST or None)
    if (request.POST.get('Student_Name')
            and request.POST.get('College_Number')
            and request.POST.get('Gender')
            and request.POST.get('Blood_Group')
            and request.POST.get('Set')
            and request.POST.get('Standard')
            and request.POST.get('AddressLine1')
            and request.POST.get('AddressLine2')
            and request.POST.get('City')
            and request.POST.get('State')
            and request.POST.get('Pincode')
            and student_form.is_valid()
            and address_form.is_valid()):
        # Fetch values from the Student Form
        student_form.name = request.POST.get('Student_Name')
        student_form.collegenumber = request.POST.get('College_Number')
        student_form.Gender = request.POST.get('Gender')
        student_form.Blood_Group = request.POST.get('Blood_Group')
        student_form.Set = request.POST.get('Set')
        student_form.Standard = request.POST.get('Standard')
        # Fetch values from the Address Form
        address_form.AddressLine1 = request.POST.get('AddressLine1')
        address_form.AddressLine2 = request.POST.get('AddressLine2')
        address_form.City = request.POST.get('City')
        address_form.State = request.POST.get('State')
        address_form.Pincode = request.POST.get('Pincode')
        student_form.save()
        address_form.save()
        return redirect('/create')
    else:
        print(student_form.errors, address_form.errors)
        messages.error(request, student_form.errors)

    context = {
        'student_form': student_form, 'address_form': address_form
    }
    return render(request, "students/student_create.html", context)

This is my forms.py

from django import forms
from .models import Students, Addresses

SET_CHOICES = (
    ('Bikrams', 'Bikrams'),
    ('Ranas', 'Ranas'),
    ('Aryans', 'Aryans'),
    ('Rajputs', 'Rajputs')
)

GENDER_CHOICES = (
    ('Male', 'Male'),
    ('Female', 'Female')
)
BLOODGROUP_CHOICES = (
    ('A-Positive', 'A-Positive'),
    ('AB-Positive', 'AB-Positive'),
    ('B-Positive', 'B-Positive'),
    ('O-Positive', 'O-Positive'),
    ('A-Negative', 'A-Negative'),
    ('AB-Negative', 'AB-Negative'),
    ('B-Negative', 'B-Negative'),
    ('O-Negative', 'O-Negative')
)

STANDARD_CHOICES = (
    ('Nursery', 'Nursery'),
    ('KG1', 'KG1'),
    ('KG2', 'KG2'),
    ('Class1', 'Class1'),
    ('Class2', 'Class2'),
    ('Class3', 'Class3'),
    ('Class4', 'Class4'),
    ('Class5', 'Class5'),
    ('Class6', 'Class6'),
    ('Class7', 'Class7'),
    ('Class8', 'Class8'),
    ('Class9', 'Class9'),
    ('Class10', 'Class10'),
    ('Class11', 'Class11'),
    ('Class12', 'Class12')
)


class StudentFrom(forms.ModelForm):
    Set = forms.ChoiceField(choices=SET_CHOICES,
                            widget=forms.RadioSelect(attrs={'class': 'ml-2'}))
    Gender = forms.ChoiceField(
        choices=GENDER_CHOICES, widget=forms.RadioSelect(attrs={'class': 'ml-2'}))

    Blood_Group = forms.ChoiceField(choices=BLOODGROUP_CHOICES)
    Standard = forms.ChoiceField(choices=STANDARD_CHOICES)

    class Meta:
        model = Students
        fields = ['Student_Name', 'College_Number',
                  'Gender', 'Blood_Group', 'Set', 'Standard']


class AddressForm(forms.ModelForm):
    AddressLine1 = forms.CharField(label='Address Line 1', widget=forms.Textarea(
        attrs={'rows': '1', 'cols': '35'}))
    AddressLine2 = forms.CharField(label='Address Line 2', widget=forms.Textarea(
        attrs={'rows': '1', 'cols': '35'}))

    class Meta:
        model = Addresses
        fields = ['AddressLine1',
                  'AddressLine2', 'City', 'State', 'Pincode']

I am successfully able to migrate this to mysql db and I can see the foreign key relation(1 Student can have many Address) in Django admin. However, I am trying to populate both the models using a single form and I am unable to do that because I am not sure how to set my foreign key value(Student_ID) in Addresses.

Looking for a solution where I can populate the Student_ID foreign key field in *Addresses with the primary key value in Student (which is the default primary key created by Django) model.

Is there a way to automatically do that so that I don't have to handle this in the template ?


Solution

  • You can obtain the result of the student_form.save() and assign it to the Student_ID of the .instance wrapped in the address_form:

    def student_create_view(request):
        if request.method == 'POST':
            student_form = StudentFrom(request.POST)
            address_form = AddressForm(request.POST)
            if student_form.is_valid() and address_form.is_valid():
                # Fetch values from the Student Form
                student = student_form.save()
                address_form.instance.Student_ID = student
                address_form.save()
                return redirect('/create')
            else:
                print(student_form.errors, address_form.errors)
                messages.error(request, student_form.errors)
        else:
            student_form = StudentFrom()
            address_form = AddressForm()
        context = {
            'student_form': student_form, 'address_form': address_form
        }
        return render(request, "students/student_create.html", context)

    Normally a ForeignKey does not end with _ID, you thus might want to rename the field to student (field names are written in snake_case not PascalCase), and thus write this as:

    address_form.instance.student = student