简体   繁体   中英

How do I correctly pass multiple arguments (from the template/context) to a view in Django?

I am relatively new to Django (v=2.1). I am stuck since few days searching for a solution to this problem which I think is fairly easy but, despite reading many posts here and elsewhere, did not manage to solve it yet. I have two models: Teacher and Assignment. Very simplified:

models.py    

class Teacher(models.Model):
    name = models.CharField(max_length=200)

class Assignment(models.Model):
    title = models.CharField(max_length=200)
    teacher = models.ForeignKey(Teacher, on_delete=models.SET_NULL, null=True)

I have a (working) site with a list of Assignments of teacher nr. x which I produced with a generic DetailView function and some of the code looks like this:

assignments_list.html

{% for assignment in teacher.assignment_set.all %}
    ...
    <a href="{% url 'assignment-detail' pk1=assignment.teacher.pk pk2=assignment.pk %}">{{assignment.title}}</a>
    ...
{% endfor %}

When I click on the assignment.title I want to get the detail page of the assignment of this specific teacher. I use this url conf:

urls.py

urlpatterns += [path('teacher/<int:pk1>/assignment/<int:pk2>/', views.AssignmentDetailView.as_view(), name = 'assignment-detail')]

and I use this view function (I tried several variants):

views.py

from .models import Teacher, Assignment
from django.views import generic

class AssignmentDetailView(generic.DetailView):
    model = Assignment
    template_name = 'assignment_detail.html'

    def get_queryset(self, **kwargs):
        queryset = super(AssignmentDetailView, self).get_queryset()
        return queryset.filter(teacher_id=self.kwargs['pk1'], pk=self.kwargs['pk2'])

I'm trying to pass the two parameters (pk1 and pk2) that are in the context of the page (that contains the list of assignments). If I click on the link (assignment.title) I do see a url with the correct numbers for pk1 and pk2 (I see that in the url address bar, eg http://localhost:8000/teacher/2/assignment/4 ). But no page is displayed. By tweaking a bit things I get different errors:

  • Syntax errors, problems with missing arguments... so far solved.
  • 'The queryset didn't retrieve any object' (or similar wording).
  • Current error: 'The view app.views.AssignmentDetailView didn't return an HttpResponse object. It returned None instead.'

My questions:

  1. What am I doing wrong? Am I passing correctly? Or is the problem in my view?... How to pass arguments (Teacher pk and Assignment pk) from the template (or, simply, the context?) to a view function? And how to use them to return the correct object(s) from my model(s)?
  2. Do I have to pass parameters every time a call a view function or are parameters passed automatically from one view(template) to another?
  3. Initially I will pass arguments through the URL but later I would like to pass them without going through the URL: can I still use the template arguments but use them only in the view (not in the url)? Is this the way to go?

Thank you so much for any advice.

Your view only returns a query set, not an actual object (which a detail view needs). If you are just trying to get the assignment object you don't even need to pass the teacher_id. On your first page you list all the assignments from a single teacher, you just need to pass the assignment.pk to the detail view.

path('assignment/<int:pk>/', views.AssignmentDetailView.as_view(), name='assignment-detail')

If you create your url like above, the detail view handles getting the object by the pk. If you want to have the teacher id in your url you can still do that but call it something like <int:teacher_id> . The detailview will by default only look for a 'pk' in the kwargs, so ignore the teacher_id

Thank you all so much for the fast reply (I did not expect that!) Sorry if I do not react to all comments but I appreciate every help.

I worked on it again and now understand that queryset returns a set and not a single model instance (for which I better use 'get'). I changed as follows and now it works:

assignments_list.html

<a href="{% url 'assignment-detail' pk=assignment.teacher.pk pk1=assignment.pk %}">


views.py

class AssignmentDetailView(generic.DetailView):
    model = Assignment
    template_name = 'assignment_detail.html'

def get_object(self, **kwargs):
    assignment = Assignment.objects.get(id=self.kwargs['pk1'])
    return assignment

def get_context_data(self, **kwargs):
    context = super(AssignmentDetailView, self).get_context_data(**kwargs)
    context['teacher'] = Teacher.objects.get(id=self.kwargs['pk'])
    return context

Now it works. I needed both pk numbers because the header on 'assignment_detail.html' is an {% include 'header-teacher.html' %} that contains <a href="{% url 'teacher-profile' teacher.pk %}"> . Now I have passed two values from the url: pk1 for retrieving the correct assignment and pk to provide the (extra) correct context (that delivers the teacher pk).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM