Home > Software design >  How to pass a URL value from a template to a form_valid method inside a Class Based View in Django
How to pass a URL value from a template to a form_valid method inside a Class Based View in Django

Time:09-30

I started working with django and I have come across a problem that I am not able to solve. I believe this should be easy but I cannot figure it out.

I am getting an Id from a template which I pass through a URL.

data.html

...
    <div class="container">

      <form method="GET" action="{% url 'data:next' %}">

          <input type="hidden" required name='job_id'>
          <button type="submit" class="btn btn-primary">Run Next</button>
          {% csrf_token %}

      </form>

    </div>
...

url.py

app_name = "data"

urlpatterns = [
    ...
    ...
    path('next/', RunNextView.as_view(), name='next'),
]

This seems to pass the job_id value to the URL as after selecting a checkbox (in this case with job_id pointing at 44) and clicking on the Run Next button I get to a url such as:

http://localhost:8000/data/next/?job_id=44&Some-token

which I think is good. Now I want to pass the number 44 to a class based view which is the problem and I was not able to do it.

As shown below I need the job_id in order to run the run_next_task task. How do i grab that 44 and pass it to the form_valid method inside the CBV ?

views.py

class RunNextView(FormView):
    template_name = 'next.html'
    form_class = RunForm
    success_url = reverse_lazy('data:list')

    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return redirect(reverse_lazy('account:login'))
        else:        
            return super(RunNextView, self).dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        cal = form.save(False)
        cal.user = self.request.user
        cal.save()
        cal.send_update()

        job_id = self.request.GET.get('job_id') //this way doesn't work

        run_next_task.delay(pk=cal.pk, dir=job_id)
        return redirect(self.success_url)

    def form_invalid(self, form):
        for field in form.errors:
            form[field].field.widget.attrs['class']  = F" {form.error_css_class}"
        return self.render_to_response(self.get_context_data(form=form))

I did countless experiments.

job_id = self.request.GET.get('job_id') inside the form_valid and pretty much every other combination. I tried using session and global variables. I tried using kwargs in many different ways such as job_id=self.kwargs['job_id'].

Non of them worked. There must be something basic and fundamental that I am missing.

Any help is appreciated. Thank you ;]

CodePudding user response:

I haven't tried this on my own but just give it a try ;)

I added a new attribute in __init__
Then use it in form_valid.

class RunNextView(FormView):
    template_name = 'next.html'
    form_class = RunForm
    success_url = reverse_lazy('data:list')

    # Add this ↓
    def __init__(self, **kwargs):
        self.job_id = ""
        super().__init__(self, **kwargs)

    # Add this as well ↓
    def get(self, request, *args, **kwargs):
        self.job_id = request.GET.get('job_id')
        super().get(self, request, *args, **kwargs)

    # some code...

    def form_valid(self, form):
        # some code...
        job_id = self.job_id #      <- Change here
        # some code...
    
    # some code...

CodePudding user response:

If you want to send data with a form, you have to choose POST method not GET. add the "job_id" (or job.id. what ever u passed) to the value of the input as follow:

  <form method="POST" action="{% url 'data:next' %}">

      <input type="hidden" value="{{job_id}}" required name='job_id'>
      <button type="submit" class="btn btn-primary">Run Next</button>
      {% csrf_token %}

  </form>

then in view, define a post method:

class RunNextView(FormView):
     def post(self,request):
         # Since name='job_id'
         posted_id=request.POST["job_id"]
  • Related