es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Rellena automáticamente el campo ForeignKey en Django CreateView.

Aquí está mi escenario. Quiero que uno de los campos de mi modelo se autorellene en función de si el usuario está autenticado o no. Como cuando el usuario envía el formulario, necesito verificar si el usuario está autenticado y luego rellenar el campo created_by con <User Object> en caso contrario, dejarlo Null si es posible.

Aquí está mi modelo:

class Snippet(models.Model):
    # ---
    create<em>by = models.ForeignKey(
        User,
        on</em>delete = models.CASCADE,
        null=True,
    )
    # ---

Aquí está mi vista:

class SnippetCreateView(CreateView):
    # ---
        def save(self, request, *args, **kwargs):
            if request.user.is_authenticated:
                user = User.objects.get(username=request.user.username)
                request.POST['create_by'] = user       # --->> TraceBack: debido a la inmutabilidad..
            return super().post(request, *args, **kwargs)
    # ---

Dado que el objeto QueryDict de request.POST es inmutable, ¿cómo puedo implementarlo? He intentado varias formas, como crear una copia, pero no sucede nada y no cambia nada.

Pero…

Puedo implementarlo de esta forma y funciona sin problema. Creo que esta solución es lo suficientemente mala como para encontrar una mejor manera. ¿Qué piensas de esta solución?

class Snippet.CreateView(CreateView):
    # ---
        def save(self, request, <em>args, *</em>kwargs):
            if request.user.is<em>authenticated:
                user = User.objects.get(username=request.user.username)
            data = {
                'title': request.POST['title'],
                # ---
                'create</em>by': user if user else None,
            }

        snippet = Snippet.objects.create(**data).save()
        # redirigiendo a Snippet.get_absolute_url()
    # ---
Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Solución:

    Ya que el QueryDict request.POST es inmutable, no podemos modificar directamente sus valores. En su lugar, podemos hacer uso del método copy() de QueryDict para crear una copia mutable de él y modificar esa copia. Así es como podemos implementarlo:

    class SnippetCreateView(CreateView):
        # ---
        def form_valid(self, form):
            if self.request.user.is_authenticated:
                user = self.request.user
                data = form.cleaned_data
                data['create_by'] = user
                self.object = form.save()
                return HttpResponseRedirect(self.get_success_url())
            else:
                # Si el usuario no está autenticado, deja el campo nulo.
                self.object = form.save(commit=False)
                self.object.save()
                return HttpResponseRedirect(self.get_success_url())
    
        def form_invalid(self, form):
            return self.render_to_response(self.get_context_data(form=form))
        # ---
    

    Explicación:

    • Sobrescribimos el método form_valid() de CreateView que se llama cuando el formulario se valida correctamente.
    • Primero comprobamos si el usuario está autenticado usando self.request.user.is_authenticated. Si es así, entonces creamos una copia mutable del diccionario cleaned_data del formulario usando data = form.cleaned_data. Esto es importante ya que no queremos modificar los datos originales del formulario.
    • Luego establecemos el valor del campo create_by en el diccionario data a self.request.user.
    • Finalmente, guardamos el formulario usando self.object = form.save(), que devuelve la instancia guardada del modelo Snippet.
    • Si el usuario no está autenticado, entonces establecemos commit=False al guardar el formulario, lo que crea una instancia no guardada del modelo Snippet. Luego guardamos esta instancia manualmente usando self.object.save().
    • En ambos casos, luego redirigimos a la URL de éxito usando return HttpResponseRedirect(self.get_success_url()).
    • Si el formulario no es válido, simplemente volvemos a renderizar el formulario usando return self.render_to_response(self.get_context_data(form=form)).

    Resultado:

    Con esta implementación, el campo create_by del modelo Snippet se rellenará automáticamente con el usuario autenticado actualmente, si lo hay, cuando se envíe el formulario. Si el usuario no está autenticado, entonces el campo se dejará nulo.

Comments are closed.