Take a parameter in a url and send it to the model when a form is sent

3

I have a CreateView view to which I am passing a PK by the URL, what I want to do basically is to take that station and send it to a field of the model with which this view works (the form does not contain the model field to which I want to pass the PK, because I want to take it from the URL and send it to the model without entering the value for form ).

This is the view:

class EventTrackingCreateView(CreateView):
    model = EventTracking
    template_name = 'tracking/form/form.html'
    form_class = EventTrackingForm

    def get_context_data(self, **kwargs):
        context = super(EventTrackingCreateView, self).get_context_data(**kwargs)
        context['current_date'] = datetime.datetime.now()
        return context

    def get_success_url(self):
        return reverse('events.list')

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(EventTrackingCreateView, self).dispatch(*args, **kwargs)

The URL of the view:

url(r'^tracking/create/(?P<pk>\d+)/$', login_required(views.EventTrackingCreateView.as_view()), name='events.tracking.create'),

The model: (the station must be saved in the event field)

class EventTracking(TimeStampedModel):
    type = models.ForeignKey(TypeEventTracking, null=True, blank=True, verbose_name=_('tipo de seguimiento'))
    event = models.ForeignKey(Event, null=True, blank=True, verbose_name=_('evento'))
    description = models.TextField(max_length=250, verbose_name=_('Descripcion'), validators=[MinLengthValidator(20)])
    created_by = models.ForeignKey(User, null=True, blank=True, related_name="user_profile_created", verbose_name="_('creado_por)", on_delete=models.PROTECT)
    updated_by = models.ForeignKey(User, null=True, blank=True, related_name="user_profile_updated", verbose_name="_('actualizado_por)", on_delete=models.PROTECT)

    class Meta:
        verbose_name = _('Seguimiento de Evento')
        verbose_name_plural = _('Seguimiento de Eventos')

    def save(self, *args, **kwargs):
        return super(EventTracking, self).save(*args, **kwargs)

This view is being entered by means of a link in this way:

<a href="{% url 'events.tracking.create' event.id %}">Crear seguimiento</a>

It should be noted that I have a model called Event as you have already seen, to which I want to associate a tracking, in the form I only render the fields type and description .

I was reading a bit about the method get_object that I thought is the closest to solving the problem I have, I do not know if I'm right.

    
asked by Mauricio Villa 18.07.2017 в 06:45
source

3 answers

0

It's simple, I'll recommend a page for you to look for information about the CBV (Class Based Views).

In your view, when you send parameters by url, and the captures with the regular expression, you can get them from the view with self.kwargs , and if you want to send it to your form, I recommend using the get_form_kwargs method % to send it, like this:

def get_form_kwargs(self):
    kwargs = super().get_form_kwargs()
    # ahora puedes recuperar tu pk o id
    pk = self.kwargs.get('pk')
    # y lo envias al formulario, no se como esperas recibirlo en el formulario, pero si en el init aceptas un pk, lo envias así.
    kwargs['pk'] = pk
    return kwargs

I would recommend you send it by form, so that it is a single blow to the database, and it would be safer, but since you want to save it directly, the solution would be this:

def form_valid(self, form):
    success = super().form_valid(form)
    # aqui asignas
    self.object.campo_asignar = self.kwargs.get('pk')
    self.object.save()
    return success

Any question, comment

    
answered by 18.07.2017 / 17:12
source
0

Class CreateView inherits from several classes including the mixin ProcessFormView . What you can try is to overwrite the post method of this last class:

class EventTrackingCreateView(CreateView):

    # ...

    @property
    def event_id(self):
        return self.kwargs.get('pk') # El que estás pasando en tu URL

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            event_tracking = form.save(commit=False)
            event_tracking.event_id = self.event_id
            event_tracking.save()
            return HttpResponseRedirect(self.get_success_url())

        return render(request, self.template_name, {'form': form}) 

I'm using a event_id property that simply returns the PK you're passing from your URL. By passing the commit=False parameter to the save method of the form you are telling it not to save the object in the database. Taking advantage of this, we save the event's PK and finally save it explicitly by calling the method save of the object.

    
answered by 18.07.2017 в 17:03
0

implement the get_initial method as follows:

def get_initial(self):
    return {
        'event': Event.objects.get(pk=self.kwargs["pk"])
    }

and in the form.py hide the field:

class Meta:
    model = EventTracking
    exclude = ['created_by', 'updated_by']
    widgets = {
        'event': forms.HiddenInput
    }

was not what I wanted to do because the user could change the value by inspecting the item, but for now I have to implement it, anyway here I put the method as implemented to know if I did something wrong and explain, you I appreciate

    @property
    def event_id(self):
        return self.kwargs.get('pk')

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            event_tracking = form.save(commit=False)
            event_tracking.event = self.event_id
            event_tracking.save()
            return HttpResponseRedirect(self.get_success_url())
        return render(request, self.template_name, {'form': form})

when I saw that the post () method did not work with the example of German Alzate, so I coded it:

    def form_valid(self, form):
        success = super().form_valid(form)
        self.object.event = self.kwargs.get('pk')
        self.object.save()
        return success

also try it this way:

   def form_valid(self, form):
       form.instance.event = self.kwargs.get('pk')
       return super(EventTrackingCreateView, self).form_valid(form)

but none of them worked and I had to implement the get_initial method

    
answered by 18.07.2017 в 22:37