Search code examples
djangodjango-generic-views

How to use Generic View for a child


I am starting to learn how to use the generic view. Considering that we`ve got a foreign key to parent. How can I create a child view using Generic View? Would that be the same way we are creating the parentview?

views?.py

class ChildCreateView(generic.CreateView):
    template_name = "app/create_child.html"
    model = Child
    form_class = ChildForm
    success_url = reverse_lazy("app:index_child")

models.py

class Parent(models.Model):
    pass

class Child(models.Model):
    parent = models.ForeignKey(Parent, on_delete=models.CASCADE)

views1.py

class ParentCreateView(generic.CreateView):
    template_name = "app/create_parent.html"
    model = Parent
    form_class = ParentForm
    success_url = reverse_lazy("app:index_parent")

Solution

  • You need to communicate to the child view what the parent is. The common solution is to use nested urls:

    urlpatterns = [
        path("/app/parents/", ParentListView.as_view()),
        path("/app/parents/<int:parent_id>/", ParentDetailView.as_view()),
        path("/app/parents/<int:parent_id>/children/", ChildListView.as_view()),
        path("/app/parents/<int:parent_id>/children/<int:child_id>/", ChildDetailView.as_view()),
    ]
    

    Now you can restrict the child to specific a parent in the ChildDetailView:

    class ChildDetailView(generic.DetailView):
        model = Child
        pk_url_kwarg = 'child_id'
    
        def get_queryset(self, queryset):
            qs = super().get_queryset(queryset)
            return qs.filter(parent__pk=self.kwargs['parent_id'])
    
    class ChildCreateView(generic.CreateView):
        model = Child
        pk_url_kwarg = 'child_id'
    
        def get_queryset(self, queryset):
            qs = super().get_queryset(queryset)
            return qs.filter(parent__pk=self.kwargs['parent_id'])
    
    class ChildUpdate...
    

    Wait, this gets repetitive:

    class NestedParentMixin(generic.base.SingleObjectMixin):
        parent_lookup = 'parent__pk'
        parent_url_kwarg = 'parent_id'
    
        def get_queryset(self, queryset):
            qs = super().get_queryset(queryset)
            filter_kwargs = {self.parent_lookup: self.kwargs[self.parent_url_kwarg]}
            return qs.filter(**filter_kwargs)
    
    
    class ChildDetailView(NestedParentMixin, generic.DetailView):
        model = Child
        pk_url_kwarg = 'child_id'
    
    class ChildUpdateView(NestedParentMixin, generic.UpdateView):
        model = Child
        pk_url_kwarg = 'child_id'
    
    class SiblingDetailView(NestedParentMixin, generic.DetailView):
        model = Sibling
        pk_url_kwarg = 'sibling_id'