Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django forms: most DRY way to organize create / update forms for inherited models

I have 2 multi-table inherited models like these:

class Post(models.Model):
    title = models.CharField(max_length=100, blank=True, null=True)
    text = models.TextField(blank=True, null=True)
    location = models.PointField()
    ...

class BlogPost(Post):
    blog = models.ForeignKey(Blog)

Similarly, form class for BlogPost also inherits from PostForm class:

class PostForm(MapModelForm):
    ...
    class Meta:
        model = Post

    def clean(self):
        ...

class BlogPostForm(PostForm):
    class Meta:
        model = BlogPost

I used to handle create / update for both models in 2 non-class-based views. To make things DRY, I decided to give Django's class-based generic views a try. But due to the lack of examples and user unfriendliness of the related documents and variety of approaches, I am confused.

The idea is to have class based form views for the Post model and inherit them for the BlogPost. How should I tailor the view classes?

Should I have separate PostCreate and PostUpdate views? Then the two classes are almost identical and not DRY at all.

Should I have a single FormView for both update / create of a post? It works for creation but I couldn't figure out how to do this for for update.

Should I build custom view (or two views for create / update) using provided mixin classes instead of inheriting from the views directly?

like image 937
onurmatik Avatar asked Apr 27 '12 10:04

onurmatik


1 Answers

You're right that the class-based view documentation is rather primitive. No doubt it will improve, but for the moment you need to be prepared to experiment and to read the source.

You are trying to do two things:

  1. Find a good way to organize your views using classes.
  2. Refactor your code to avoid repetition.

It's important to tackle these one at a time. Figure out the right class hierarchy first, and only then figure out how to factor out the repetition.

Let's have a go. Your class hierarchy is going to look something like this:

from django.views import generic

class PostCreateView(generic.CreateView):
    form_class = PostForm
    model = Post

class PostUpdateView(generic.UpdateView):
    form_class = PostForm
    model = Post

class BlogPostCreateView(generic.CreateView):
    form_class = BlogPostForm
    model = BlogPost

class BlogPostUpdateView(generic.UpdateView):
    form_class = BlogPostForm
    model = BlogPost

This involves a lot of repetition, but it's clear now how to factor out some of it:

from django.views import generic

class PostView(generic.FormView):
    form_class = PostForm
    model = Post

class PostCreateView(PostView, generic.CreateView): pass
class PostUpdateView(PostView, generic.UpdateView): pass

class BlogPostView(PostView):
    form_class = BlogPostForm
    model = BlogPost

class BlogPostCreateView(BlogPostView, generic.CreateView): pass
class BlogPostUpdateView(BlogPostView, generic.UpdateView): pass

And if you're still unhappy with the amount of repetition here, you can further automate the construction of these classes (using type to create classes at runtime). That's probably a step too far, though, until you're completely comfortable with the use of class-based views.

like image 106
Gareth Rees Avatar answered Sep 19 '22 14:09

Gareth Rees