Page not found After using UpdateView class

Question:

I have a project that requires an update form, I am using the Django generic views, specifically the UpdateView.

I Think this is an error with the URL, but I dont find where it is.

Error also refers to the url The current path, actualizar_empleado/, didn’t match any of these.

BTW if you see something else in my code that should be corrected, or that I can add a better practice, feel free to let me now.

My code is the following:

Views.py

from django.shortcuts import render, get_object_or_404
from django.views.generic import (
    CreateView,
    DetailView,
    ListView,
    UpdateView,
    ListView,
    DeleteView
)   

from . models import EmployeesInfo
from . forms import EmployeeForm

class EmployeeCreate(CreateView):
    form_class = EmployeeForm
    template_name = 'employeeCreate.html'
    success_url = '/lista_empleados/'

    def form_valid(self, form):
        print(form.cleaned_data)
        return super().form_valid(form)

class EmployeeList(ListView):
    model = EmployeesInfo
    template_name = 'employeeList.html'
    success_url = 'lista-empleados/exitoso'


class EmployeeDetail(DetailView):
    model = EmployeesInfo
    template_name = 'employeeDetail.html'
    success_url = 'detalle-empleado/exitoso'

    def get_object(self):
        id_ = self.kwargs.get("pk")
        return get_object_or_404(EmployeesInfo, pk=id_)


class EmployeeUpdate(UpdateView):
    form_class = EmployeeForm
    queryset = EmployeesInfo.objects.all()
    template_name = 'employeeUpdate.html'
    success_url = '/listaempleados/'

    def form_valid(self, form):
        print(form.cleaned_data)
        return super().form_valid(form)

    def get_object(self):
        id_ = self.kwargs.get("pk")
        return get_object_or_404(EmployeesInfo, pk=id_)

urls.py

from django.contrib import admin
from django.urls import path, re_path
from . views import EmployeeCreate, EmployeeList, EmployeeDetail, EmployeeUpdate


urlpatterns = [
    path('crear_empleado/', EmployeeCreate.as_view(), name = 'createmp'),
    path('lista_empleados', EmployeeList.as_view(), name = 'listemp'),
    path('detalle_empleado/<int:pk>', EmployeeDetail.as_view(), name = 'showemp'),
    path('actualizar_empleado/<int:pk>', EmployeeUpdate.as_view(), name = 'updatemp'),
]  

employeeUpdate.html

<body>
    {%extends 'base.html'%}

    {%block content%}
    <div class="row">
        <div class="col-md-9">
            <div class="card card-body">

                <form method="PUT" action="." enctype="multipart/form-data">
                    {%csrf_token%}
                        <table>
                        {{form.as_table}}
                        </table>
                    <input type="submit" value="Actualizar">
                </form>

            </div>
        </div>
    </div>
    {%endblock%}
</body>

Answers:

  1. Use django.urls.reverse for resolving urls, don’t put raw paths, it’s harder to maintain. Also, your success_url in is wrong in the post (I’m guessing it’s a wrong copy/paste). Anyway, you should use reverse for getting that URL. You also need to add a PK because your URL contains a PK.
  2. As Arif Rasim mentioned in comments, instead of queryset, define model in your EmployeeUpdate view.
  3. Your use of get_object is correct but not necessary as this is done by the views (SingleObjectMixin). See more here
  4. Use absolute imports (recommended by PEP8). It’s not wrong or incorrect to use relative imports but absolute imports give more precise error messages.
  5. The action attribute in your form in the HTML template should be empty (right now it’s ".") if you want to submit the form to the current page (recommended for flexibility).
  6. Specifying enctype in your form is not necessary if the form does not handle file fields. Let the browser and framework take care of it.
  7. The method attribute in your form can only take values of "GET" and "POST".
# ...

# Using absolute imports, yourapp is the package name of your app
from yourapp.models import EmployeesInfo
from yourapp.forms import EmployeeForm


class EmployeeCreate(CreateView):
    form_class = EmployeeForm
    template_name = 'employeeCreate.html'
    # Here you can use reverse_lazy (reverse doesn't work) to keep things
    # shorter (as opposed to using get_success_url method)
    success_url = reverse_lazy('createmp')  # shouldn't it be "createemp"?

    def form_valid(self, form):
        print(form.cleaned_data)
        return super().form_valid(form)


class EmployeeList(ListView):
    model = EmployeesInfo
    template_name = 'employeeList.html'
    success_url = reverse_lazy('listemp')


class EmployeeDetail(DetailView):
    model = EmployeesInfo
    template_name = 'employeeDetail.html'

    # Unnecessary - done by DetailView
    # def get_object(self):
    #     id_ = self.kwargs.get("pk")
    #     return get_object_or_404(EmployeesInfo, pk=id_)

    def get_success_url(self):
        # NOTE: don't forget the comma after the PK as "args" 
        # param should be a tuple
        return reverse('showemp', args=(self.kwargs['pk'],))


class EmployeeUpdate(UpdateView):
    form_class = EmployeeForm
    model = EmployeeInfo

    def form_valid(self, form):
        print(form.cleaned_data)
        return super().form_valid(form)

    # Unnecessary - done by UpdateView
    # def get_object(self):
    #    id_ = self.kwargs.get("pk")
    #    return get_object_or_404(EmployeesInfo, pk=id_)

    def get_success_url(self):
        # NOTE: don't forget the comma after the PK as "args" 
        # param should be a tuple
        # BTW, Shouldn't this be "updateemp"?
        return reverse('updatemp', args=(self.kwargs['pk'],))
<!-- employeeUpdate.html -->
<form method="POST" action="">
Answered By: vinkomlacic