1

I am trying to change all my class-based views to function-based views and I am having difficulty converting the following class:

class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, SuccessMessageMixin, UpdateView):
    model = Post
    fields = ['image', 'title', 'category', status', 'description']
    template_name = 'blog/post-form.html'
    success_message = 'Your post has been updated.'

    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_context_data(self, **kwargs):
        context = super(PostUpdateView, self).get_context_data(**kwargs)
        context['title'] = 'Update post'
        context['submit'] = 'Update'
        return context

    def get_success_url(self):
        author = self.object.author 
        return reverse_lazy( 'profile', kwargs={'author': author.username})

The function and form should do exactly what this class-based view does, so if anyone can help me out, please let me know.

3
  • 1
    Why do you want to convert these to unction-based views in the first place? The idea of a CBV is to remove boilerplate code, such that one does not have to repeat themselves for standard tasks. Commented Apr 3, 2020 at 10:11
  • If you don't know how to get started, here is a skeleton view that processes a form. Then, if you get stuck on a particular bit (e.g. doing the success message), you can post what you've written so far and get help for that specific part. Commented Apr 3, 2020 at 10:16
  • @WillemVanOnsem I would like to customize the input widget for uploading the image and I can't seem to find a solution to do that when using a class-based view. That's basically the only reason. Commented Apr 3, 2020 at 10:21

1 Answer 1

2

You can specify a .form_class attribute [Django-doc] in an UpdateView (as well as in a CreateView). So we can create a form like:

# app/forms.py

from django import forms

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['image', 'title', 'category', 'status', 'description']
        widgets = {
            'image': …
        }

Where you replace with the widget you want to use for the image field.

Then you can plug in that form:

# app/views.py

from app.forms import PostForm

class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, SuccessMessageMixin, UpdateView):
    model = Post
    form_class = PostForm
    template_name = 'blog/post-form.html'
    success_message = 'Your post has been updated.'

    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_context_data(self, **kwargs):
        context = super(PostUpdateView, self).get_context_data(**kwargs)
        context['title'] = 'Update post'
        context['submit'] = 'Update'
        return context

    def get_success_url(self):
        author = self.object.author 
        return reverse_lazy( 'profile', kwargs={'author': author.username})

Behind the curtains, if you do not specify a form_class, Django will simply make one for you with the modelform_factory [Django-doc], so by using another ModelForm, we do not change the logic of using the form.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.