Marko Maksimovic
Marko Maksimovic

Reputation: 87

Django adding to database with foreign key while still showing the informations from the other model

I want to add elements to my database (for model Student) while having stuff from another model (School) be displayed alongside the form for the Student.\

This is the models.py

class School(models.Model):
    name = models.CharField(max_length=256)
    principal = models.CharField(max_length=256)
    location = models.CharField(max_length=256)

    def get_absolute_url(self):
        return reverse('basiccbv:detail', kwargs={'pk':self.pk})

    def __str__(self):
        return self.name


class Student(models.Model):
    name = models.CharField(max_length=256)
    age = models.PositiveIntegerField(validators= [validators.MinValueValidator(1),validators.MaxValueValidator(20)],default=1)
    school = models.ForeignKey(School, related_name='students')

def __str__(self):
    return self.name

In my views.py I have this:

class SchoolDetailedView(DetailView):
    context_object_name = 'school_detail'
    model = models.School
    template_name = 'basiccbv/school_detail.html'
    # What i want is when I visit the link in the description I want to
    # to see the school stuff and the form to add the student in this new 
    # view

class StudentCreateView(CreateView):
    model = models.School
    # I tried using the Student but that I don't know how to display the 
    # school information, I tried with related_name = 'students' but it 
    # didn't work(I don't know if that can be done the way that intended it 
    # or I just don't have the knowledge )  
    fields = ['name', 'age']
    # If I use School I could get the name of the school in the title and 
    # its primary key, but than I don't know how to display the form and 
    # vise versa 
    template_name = 'basiccbv/student_update.html'

This is the .html file that gets me to the page where I need the form. The link is the one calling 'basiccbv:studentupdate' The related_name students was used here but I still can't figure out if it can be done for adding stuff the way I want

<h1>Welcome to the school details page</h1>
<h2>School details:</h2>
<p>Name: {{ school_detail.name }}</p>
<p>Principal: {{ school_detail.principal }}</p>
<p>Location: {{ school_detail.location }}</p>
<h3>Students:</h3>
{% for student in school_detail.students.all %}
<p>{{ student.name }} who is {{ student.age }} years old.</p>
{% endfor %}
<div class="container">
<p><a href="{% url 'basiccbv:studentupdate' pk=school_detail.pk %}">Add a 
student</a></p>

And here is the .html file with the form

              ## I changed this part bellow but nothing worked
<h1>Student coming to {{ student.school.name }}</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
    <input type="submit" class="btn btn-primary" value="Add student">
</form>

I'm really stuck and can't find any information about this but if you can help me or give any advice thank you.

The way I used to add students was with admin and for schools I used admin until I created the view for creating Schools which worked with no problems(probably because there were no foreign keys).

Upvotes: 1

Views: 411

Answers (1)

ruddra
ruddra

Reputation: 51988

I think you can take this approach

Forms:

# We need to define a new form first
class StudentForm(forms.ModelForm):
     class Meta:
         model = Student
         fields = ['name', 'age']

Views:

# we are using form view for using the form mentioned above
class StudentCreateView(FormView):
     form_class = StudentForm
     success_url = "/"

     def get(self, request, school_id, **kwargs):
         context = self.get_context_data(**kwargs)  # getting context, ie: the form
         context[school] = School.objects.get(pk=school_id)  # updating the context with school object using the PK provided with the url
         return self.render_to_response(context)

     def post(self, request, school_id, **kwargs):
        # overriding default implementation
        form = self.get_form()  
        if form.is_valid():
            return self.form_valid(form, school_id)  # passing the pk value to form valid function to override
        else:
            return self.form_invalid(form)

    def form_valid(self, form, school_id):
        # overriding default implementation
        self.object = form.save(commit=False)
        self.object.school = School.objects.get(id=school_id)  # saving the school information to the object
        self.object.save()
        return super(StudentCreateView, self).form_valid(form)

Template

# template
    <h1>Student coming to {{ school.name }}</h1>
    <form method="post">
    {% csrf_token %}
    {{ form.as_p }}
        <input type="submit" class="btn btn-primary" value="Add student">
    </form>

Urls

path('school/student-update/<int:school_id>/', StudentCreateView.as_view(), name='studentupdate'),

Upvotes: 1

Related Questions