Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Generic View UpdateView redirect URL with updated slug

This is my updateview which is called by a URL with slug field, e.g.

/mymodel/update/<model_name_slug>/

MyModel have two fields, name and slug. The slug field <model_name_slug> is automatically generated from MyModel.name. If the user update it, a new slug field will be automatically generated. Then, I want to redirect to this new URL with the newly generated slug field.

The slug field auto-generation is working. It is implemented in the MyModelEditForm. However, the code below won't work. The reason is:

1) User typed this URL to update the existing model

/mymodel/update/example-model

2) User changes the Name attribute to "example model changed". Then slug field will be generated as "example-model-changed" in MyModel.

3) But the URL is not redirected to the "/mymodel/update/example-model-changed", as get_object() will return None. get() will not be able to compare the newly generated URL "example-model-changed" with original "example-model"

What am I missing in below code? I tried to access the newly update object using self.object, but have following error:

 MyModelUpdateView object has no attribute 'object'

Here is the code snippet:

class MyModelUpdateView(LoginRequiredMixin, UpdateView):
    model = MyModel
    form_class = MyModelUpdateForm
    template_name = 'mymodel/update_mymodel.html'

    def get_success_url(self):
        view_name = 'update_mymodel'
        return reverse_lazy(view_name, kwargs={'model_name_slug': self.kwargs.get('model_name_slug','')})

    def get_form_kwargs(self):
        '''
        This injects form with keyword arguments.
        '''
        kwargs = super(MyModelUpdateView, self).get_form_kwargs()
        #Update the kwargs with the user_id
        kwargs['user'] = self.request.user
        return kwargs

    def get(self, request, *args, **kwargs):
        # self.object = self.get_object()
        if self.request.path != self.object.get_absolute_url():
            return HttpResponseRedirect(self.object.get_absolute_url())
        else:
            return super(MyModelUpdateView, self).get(request,*args, **kwargs)
            # context = self.get_context_data(object=self.object)
            # return self.render_to_response(context)

    def get_object(self, queryset=None):
        instance = MyModel.objects.get(slug=self.kwargs.get('model_name_slug',''))
        return instance

Even if the get_success_url() is correctly updated, the get_object() seems to have two conflicting requirements: 1) Be able to fetch the correct object using existing "example-model" slug field; 2) Be able to fetch the updated object using newly generated "example-model-changed" before the existing URL is not redirected.

like image 643
thinkdeep Avatar asked Oct 14 '15 02:10

thinkdeep


1 Answers

You don't have to use self.get_object in the get_success_url method. The form_valid() sets self.object when saving the form, so you can use self.object.slug to get the new url.

def get_success_url(self):
    view_name = 'update_mymodel'
    # No need for reverse_lazy here, because it's called inside the method
    return reverse(view_name, kwargs={'model_name_slug': self.object.slug})
like image 127
Alasdair Avatar answered Sep 30 '22 16:09

Alasdair