views.py
    
        from django.contrib.messages.views import SuccessMessageMixin
        from django.http import request
        from django.views.generic import ListView
        from django.views.generic.detail import DetailView
        from django.views.generic.edit import CreateView, DeleteView, FormView, UpdateView
        from django.contrib.auth.mixins import LoginRequiredMixin
        from django.contrib.auth.forms import PasswordChangeForm
        from django.contrib.auth import get_user_model
        from django.http import HttpResponse
        from django.views import View
        
        from .forms import AnimalForm, UserRegistrationForm, UserUpdateForm
        from .models import Animal, TipoAnimal, Municipio
        
        
        User = get_user_model()
        
        
        class HomeView(LoginRequiredMixin, ListView):
            """
            Clase para para la pagina home, donde podremos filtrar los datos segun 
            los intereses del usuario
            """
            template_name = "index.html"
        
            def get_context_data(self, **kwargs):
                context = super().get_context_data(**kwargs)
                context["tipo_de_animal"] = TipoAnimal.objects.all()
                context["municipios"] = Municipio.objects.all()
                return context
        
            def get_queryset(self):
                queryset = Animal.objects.all()
        
                tipo_de_animal = self.request.GET.get('tipo_de_animal')
                municipio = self.request.GET.get('municipio')
                fecha_perdida = self.request.GET.get('fecha_perdida')
        
                if tipo_de_animal:
                    queryset = queryset.filter(tipo_de_animal__name__iexact=tipo_de_animal)
                if municipio:
                    queryset = queryset.filter(municipio__name__iexact=municipio)
                if fecha_perdida:
                    queryset = queryset.filter(fecha_perdida=fecha_perdida)
                return queryset
        
        
        class RegistroUsuario(SuccessMessageMixin, CreateView):
            """
            Una vez validado el formulario nos reenvia al login para poder iniciar sesion
            con el nuevo usuario, y nos muestra un mensaje de operacion satisfactoria
            """
            template_name = "register.html"
            form_class = UserRegistrationForm
            success_url = "/login"
            success_message = "Te has registrado correctamente ! Ahora puedes iniciar sesion."
        
        
        class ActualizarPerfil(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
            """
            Una vez actualizado el formulario con los nuevos cambios nos reenvia al perfil
            , y nos muestra un mensaje de operacion satisfactoria
        
            UpdateView-> Una vista que muestra un formulario para editar un objeto 
            existente, volver a mostrar el formulario con errores de validación 
            (si los hay) y guardar los cambios en el objeto. Esto utiliza un 
            formulario generado automáticamente a partir de la clase de modelo 
            del objeto (a menos que se especifique manualmente una clase de formulario).
        
            LoginRequiredMixin-> Si una vista usa esta combinación, 
            todas las solicitudes de usuarios no autenticados serán 
            redirigidas a la página de inicio de sesión o se mostrará un error 
            HTTP 403 Prohibido, según el parámetro raise_exception.
            """
            template_name = "profile.html"
            form_class = UserUpdateForm
            success_url = "/profile"
            success_message = "El perfil se ha actulizado perfectamente"
        
            def get_object(self):
                return self.request.user
        
        
        class CambiarContrasena(LoginRequiredMixin, SuccessMessageMixin, FormView):
            """
            Una vez actualizado el formulario con los nuevos cambios nos reenvia al perfil
            , y nos muestra un mensaje de operacion satisfactoria
            """
            template_name = "password_change.html"
            form_class = PasswordChangeForm
            success_url = "/profile"
            success_message = "La contraseña se ha actualizado correctamente"
        
            def get_form_kwargs(self, **kwargs):
                data = super(CambiarContrasena, self).get_form_kwargs(**kwargs)
                data['user'] = self.request.user
                return data
        
        
        class MiListaReportes(LoginRequiredMixin, ListView):
            """
            LoginRequiredMixin-> Si una vista usa esta combinación, 
            todas las solicitudes de usuarios no autenticados serán 
            redirigidas a la página de inicio de sesión o se mostrará un error 
            HTTP 403 Prohibido, según el parámetro raise_exception.
            """
            template_name = "own_reports.html"
        
            def get_queryset(self):
                animales = Animal.objects.filter(user=self.request.user)
                return animales
        
        
        class CrearAnimal(LoginRequiredMixin, SuccessMessageMixin, CreateView):
            """
            LoginRequiredMixin-> Si una vista usa esta combinación, 
            todas las solicitudes de usuarios no autenticados serán 
            redirigidas a la página de inicio de sesión o se mostrará un error 
            HTTP 403 Prohibido, según el parámetro raise_exception.
        
            SuccessMessageMixin-> nos muestra un mensaje de operacion satisfactoria
            """
            template_name = "create_animal.html"
            form_class = AnimalForm
            success_url = "/mis-reportes/"
            success_message = "El reporte se ha añadido correctamente"
        
            def form_valid(self, form):
        
                if form.is_valid():
                    animal_obj = form.save(commit=False)
                    animal_obj.user = self.request.user
                    animal_obj.save()
                return super().form_valid(form)
        
        
        class DetallesAnimal(LoginRequiredMixin, DetailView):
            """
            Nos permite ver los detalles de un animal en concreto
        
            LoginRequiredMixin-> Si una vista usa esta combinación, 
            todas las solicitudes de usuarios no autenticados serán 
            redirigidas a la página de inicio de sesión o se mostrará un error 
            HTTP 403 Prohibido, según el parámetro raise_exception.
        
            DetailView -> Mientras se ejecuta esta vista, self.object contendrá el objeto 
            sobre el que está operando la vista.
            """
            template_name = "animal_detail.html"
            queryset = Animal.objects.all()
        
        
        class ActualizarAnimal(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
            """
            Nos permite actualicar los datos de un animal en concreto
        
            LoginRequiredMixin-> Si una vista usa esta combinación, 
            todas las solicitudes de usuarios no autenticados serán 
            redirigidas a la página de inicio de sesión o se mostrará un error 
            HTTP 403 Prohibido, según el parámetro raise_exception.
        
            UpdateView -> Una vista que muestra un formulario para editar un 
            objeto existente, volver a mostrar el formulario con errores de 
            validación (si los hay) y guardar los cambios en el objeto. Esto 
            utiliza un formulario generado automáticamente a partir de la clase 
            de modelo del objeto (a menos que se especifique manualmente una 
            clase de formulario).
        
            SuccessMessageMixin-> nos muestra un mensaje de operacion satisfactoria
            """
            template_name = "update_animal.html"
            form_class = AnimalForm
            success_url = "/mis-reportes/"
            success_message = "El reporte se ha actualizado correctamente"
        
            def get_queryset(self):
                return Animal.objects.filter(user=self.request.user)
        
        
        class BorrarAnimal(LoginRequiredMixin, DeleteView):
            """
            Nos permite borrar los datos de un animal en concreto, despues nos 
            reenvia a la zona de mis reportes para poder seguir operando.
        
            LoginRequiredMixin-> Si una vista usa esta combinación, 
            todas las solicitudes de usuarios no autenticados serán 
            redirigidas a la página de inicio de sesión o se mostrará un error 
            HTTP 403 Prohibido, según el parámetro raise_exception.
        
            DeleteView-> Una vista que muestra una página de confirmación 
            y elimina un objeto existente. El objeto dado solo se eliminará si 
            el método de solicitud es POST. Si esta vista se obtiene a través de GET, 
            mostrará una página de confirmación que debe contener un formulario que se 
            envía a la misma URL.
        
            """
            template_name = "animal_delete_confirm.html"
            success_url = "/mis-reportes/"
        
            def get_queryset(self):
                return Animal.objects.filter(user=self.request.user)
        
            """ Revisar
            class GenerarVistaPdf(View):
                def get (self, request, *args, **kwargs):
                    return HttpResponse('Hello world!')
            """