Ross Symonds
Ross Symonds

Reputation: 710

Standardising get_success_url

For my classes PostCreateView and PostUpdateView I have the same get_success_url. Is there a way of standardising your get_success_url, I want to avoid writing the code twice?

def get_success_url(self):
      return reverse('post-detail', args=[self.object.pk])

I was working through a tutorial. A limitation of the tutorial though was you were only shown how to load posts by using the posts primary key (https://rossdjangoawesomeapp2.herokuapp.com/post/6/). I modified the code in the tutorial so you could access posts using their title (https://rossdjangoawesomeapp2.herokuapp.com/post/another-test-please-let-it-work/). Which has resulted in me having duplicate code.

models.py

class Post(models.Model):
    title = models.CharField(max_length=100)
    content =  models.TextField()
    date_posted = models.DateTimeField(default=timezone.now())
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    url = models.SlugField(max_length=500, blank=True)


    def save(self, *args, **kwargs):
        self.url= slugify(self.title)
        super().save(*args, **kwargs)

    def __str__(self):
        return self.title 

    def get_absolute_url(self):
        return reverse('post-detail', kwargs={'pk': self.pk})

views.py

 class PostCreateView(LoginRequiredMixin, CreateView):
    model = Post
    fields = ['title', 'content']

    def get_success_url(self):
      return reverse('post-detail', args=[self.object.pk])

    def form_valid(self, form):
        form.instance.author = self.request.user
        # will save the form and redirect to the success_url
        return super().form_valid(form)


class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    model = Post
    fields = ['title', 'content']

    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)


    def test_func(self):
        post = self.get_object()
        if self.request.user == post.author:
            return True
        return False

    def get_success_url(self):
      return reverse('post-detail', args=[self.object.pk])

Upvotes: 1

Views: 556

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477190

For my classes PostCreateView and PostUpdateView I have the same get_success_url. Is there a way of standardising your get_success_url, I want to avoid writing the code twice?

Yes, not writing it at all. If you do not specify a get_success_url, or success_url, Django will take the get_absolute_url of the object (so here the Post object). Hence if you do not specify it, then it will already redirect to the correct url, this is specified in the documentation for the get_success_url method [Django-doc]:

Determine the URL to redirect to when the form is successfully validated. Returns django.views.generic.edit.ModelFormMixin.success_url if it is provided; otherwise, attempts to use the get_absolute_url() of the object.

So we can remove the get_success_url methods:

class PostCreateView(LoginRequiredMixin, CreateView):
    model = Post
    fields = ['title', 'content']

    # no get_success_url

    def form_valid(self, form):
        form.instance.author = self.request.user

class PostUpdateView(LoginRequiredMixin, UpdateView):
    model = Post
    fields = ['title', 'content']

    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)


    def get_queryset(self, *args, **kwargs):
        return super().get_queryset(*args, **kwargs).filter(
            author=self.request.user
        )

    # no get_success_url

Upvotes: 1

Related Questions