Jeroen van der Merwe
Jeroen van der Merwe

Reputation: 406

How can I convert my class-based view to function-based views? - Django

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.

Upvotes: 1

Views: 1166

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477853

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.

Upvotes: 2

Related Questions