Exception Value: null value in column “created_by_id” violates not-null constraint

Pregunta de la clase:
Bernardo Augusto García Loaiza

Bernardo Augusto García Loaiza

Pregunta
studenthace 8 años

Tengo los siguientes modelos, con los cuales, pretendo asociar múltiples imágenes a un objeto de mi modelo

LodgingOffer
, para lo cual estoy tomando mano de los
formsets
en Django

<code> class LodgingOffer(models.Model): created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE ) slug = models.SlugField(max_length=100, blank=True) offered_services = models.ManyToManyField( OfferedServices, related_name="lodgingoffers" ) # Other fields def __str__(self): return "%s" % self.ad_title def get_absolute_url(self): return reverse('host:detail', kwargs = {'slug' : self.slug }) # Create slug to Url object, friendly readable def create_slug(instance, new_slug=None): slug = slugify(instance.ad_title) if new_slug is not None: slug = new_slug qs = LodgingOffer.objects.filter(slug=slug).order_by("-id") exists = qs.exists() if exists: new_slug = "%s-%s" % (slug, qs.first().id) return create_slug(instance, new_slug=new_slug) return slug def pre_save_lodging_offer_receiver(sender, instance, *args, **kwargs): if not instance.slug: instance.slug = create_slug(instance) pre_save.connect(pre_save_lodging_offer_receiver, sender=LodgingOffer) # I get file name to save the images def get_image_filename(instance, filename): title = instance.lodging_offer.ad_title slug = slugify(title) return "lodging_offer_images/%s-%s" % (slug, filename)

El modelo en donde guardaría las múltiples imágenes asociadas a

LodgingOffer
es:

<code> class LodgingOfferImage(models.Model): lodging_offer = models.ForeignKey(LodgingOffer) image = models.ImageField(upload_to=get_image_filename, verbose_name='Imagen',)

Los respectivos formularios de estos dos modelos son:

<code> class LodgingOfferForm(forms.ModelForm): title = "Crear oferta de alojamiento" class Meta: model = LodgingOffer fields = ('ad_title', 'country', 'city', 'address', 'lodging_offer_type', 'stars', 'check_in', 'check_out', 'offered_services', 'featured_amenities', 'room_type_offered', 'number_guest_room_type', 'bed_type', 'bathroom', 'room_information', 'image', 'room_value', 'additional_description', 'is_taked') class LodgingOfferImagesForm(forms.ModelForm): image = forms.ImageField(label='Imagen') class Meta: model = LodgingOfferImage fields = ('image', )

La idea que prentendo es que cuando cree un objeto

LodgingOffer
en su formulario tener la posibilidad de adjuntarle multiples imágenes, por lo cual my vista
CreateView
ha quedado asi:

Estoy sobreescribiedo el

get_context_data()
para enviar al template el formulario de mi modelo y el formset.

<code> class HostingOfferCreateView(SuccessMessageMixin, CreateView): model = LodgingOffer form_class = LodgingOfferForm #success_url = reverse_lazy("articles:article_list") success_message = "Oferta de alojamiento creada con éxito" def get_context_data(self, **kwargs): context = super(HostingOfferCreateView, self).get_context_data(**kwargs) ImageFormSet = modelformset_factory(LodgingOfferImage, form=LodgingOfferImagesForm, extra=3) if self.request.method == 'POST': lodging_offerForm = LodgingOfferForm(self.request.POST) formset = ImageFormSet(self.request.POST, self.request.FILES, queryset=LodgingOfferImage.objects.none()) if lodging_offerForm.is_valid() and formset.is_valid(): lodging_offer_form = lodging_offerForm.save(commit=False) lodging_offer_form.created_by = self.request.user lodging_offer_form.save() for form in formset.cleaned_data: image = form['image'] photo = LodgingOfferImage(lodging_offer=lodging_offer_form, image=image) photo.save() messages.success(self.request, "Offer images saved") #return redirect("articles:article_list") return HttpResponse(lodging_offer_form.get_asolute_url()) #return super(HostingOfferCreateView, self).get_context_data(**kwargs) else: print(lodging_offerForm.errors, formset.errors) else: lodging_offerForm = LodgingOfferForm() formset = ImageFormSet(queryset=LodgingOfferImage.objects.none()) context['lodging_offerForm'] = lodging_offerForm context['formset'] = formset return context

Se también que las validaciones de los formularios aquí hechas son realizadas tradicionalmente en el metodo

form_valid()
solo que no estoy seguro de si allí puedo enviar un contexto a un template, por lo cual lo hice en el
get_context_data()
todo.

Ignoro si esto es correcto no.

Y mi template es:

<code> {% extends 'layout.html' %} {% load staticfiles %} {% load bootstrap3 %} {% block body_content %} <form method="POST" enctype="multipart/form-data"> {% csrf_token %} {% for hidden in lodging_offerForm.hidden_fields %} {{ hidden }} {% endfor %} {% for field in lodging_offerForm %} {{ field }} <br /> {% endfor %} {{ formset.management_form }} {% for form in formset %} {{ form }} {% endfor %} <input type="submit" name="submit" value="Submit" /> </form> {% endblock %}

Cuando realizo un post a traves de mi formulario en mi navegador, obtengo este mensaje:

<code> Exception Type: IntegrityError at /host/lodging-offer/new/ Exception Value: null value in column "created_by_id" violates not-null constraint DETAIL: Failing row contains (65, Apartamento, AF, Envigado, Calle 40D Sur #3221, null, null, Hotel, 1 estrella, 2017-10-11, 2017-10-21, Habitación privada, Para 1 huésped, Cama individual, Baño privado, 2134, 67858, 2017-10-19 17:06:52.310857+00, null, apartamento-24-30-31-43-44-49-50, f, hosting-host-photos/1900-X-1080-Wallpapers-022.jpg)

Sé que la causa de esto es que en el request POST que se hace, no se esta enviando un valor al campo

created_by
de mi modelo
LodgingOffer
el cual es una llave foránea y básicamente aqui debo enviar es el usuario que hace la solicitud de POST o quien graba un registro.

Lo que pasa es que estoy intentándolo de esta manera en mi sección de código previa:

<code> if lodging_offerForm.is_valid() and formset.is_valid(): lodging_offer_form = lodging_offerForm.save(commit=False) # Enviando el valor para created_by lodging_offer_form.created_by = self.request.user lodging_offer_form.save()

Pero aparentemente no es la manera en como debo capturar el request del usuario en mi formulario instanciado

lodging_offerForm
o no lo estoy haciendo bien

Por el momento no he mirado como resolver la situación. ¿Cómo puedo adicionar el request del usuario al momento de grabar el formulario?

1 respuestas
para escribir tu comentario
    Diego Forero

    Diego Forero

    Team Platzihace 8 años

    La parte de validación del formulario y guardado de los datos lo debes hacer en el método post, CreateView tiene un método post y un método form_valid, el form_valid no lo puedes usar tan fácil porque tienes el formset entonces la parte de validación y guardado la puedes hacer en el método post.

    class LoQueSea(CreateView): def post(self, request, *args, **kwargs): ImageFormSet = modelformset_factory(LodgingOfferImage, form=LodgingOfferImagesForm, extra=3) lodging_offerForm = LodgingOfferForm(self.request.POST) formset = ImageFormSet(self.request.POST, self.request.FILES, queryset=LodgingOfferImage.objects.none()) .....

    Y quitas la parte de validar si el request es post en el get_context_data.

    Puedes ver los métodos que tienen las Class Based Views en http://ccbv.co.uk/

Curso de Python y Django 2016

Curso de Python y Django 2016

Aprende Python desde cero y crea tu primera aplicación web completa en Django. Entiende las bases del lenguaje, sus funciones, conoce cómo conectarte a bases de datos y termina creando una API REST de manera profesional para tu app.

Curso de Python y Django 2016
Curso de Python y Django 2016

Curso de Python y Django 2016

Aprende Python desde cero y crea tu primera aplicación web completa en Django. Entiende las bases del lenguaje, sus funciones, conoce cómo conectarte a bases de datos y termina creando una API REST de manera profesional para tu app.