Django multiple models, one form

2020-03-04 07:49发布

I have a model that looks like this:

class Movie(models.Model):
    title = models.CharField(max_length=200)
    slug = models.SlugField(max_length=200)
    user = models.ForeignKey(User)
    created_on = models.DateTimeField(default=datetime.datetime.now())

    class Meta:
        ordering = ['-title']

    def __unicode__(self):
        return self.title

class MovieScreener(models.Model):
    screener_asset = models.FileField(upload_to='movies/screeners/')
    movie = models.ForeignKey(Movie)

class MovieTrailer(models.Model):
    trailer_asset = models.FileField(upload_to='movies/trailers/', blank=True, null=True)
    description = models.TextField()
    movie = models.ForeignKey(Movie)

class MoviePoster(models.Model):
    poster_asset = models.FileField(upload_to='movies/posters/', blank=True, null=True)
    movie = models.ForeignKey(Movie)

And my forms look like this:

class MovieForm(forms.ModelForm):
    class Meta:
        model = Movie
        exclude = ('user','created_on')

class MovieScreenerForm(forms.ModelForm): 
    class Meta:
        model = MovieScreener
        exclude = ('movie',)

class MovieTrailerForm(forms.ModelForm):
    class Meta:
        model = MovieTrailer
        exclude = ('movie',)

class MoviePosterForm(forms.ModelForm): 
     class Meta:
        model = MoviePoster
        exclude = ('movie',)

And here is my views.py (this is where it looks ugly)

@login_required
def create_movie(request, template_name="explore/create_movie.html"):
    if request.method == 'POST':
        movie_form = MovieForm(data=request.POST)
        movie_screener_form = MovieScreenerForm(data=request.POST, files=request.FILES, prefix="a")
        movie_trailer_form = MovieTrailerForm(data=request.POST, files=request.FILES, prefix="b")
        movie_poster_form = MoviePosterForm(data=request.POST, files=request.FILES, prefix="c")

        if movie_form.is_valid() and movie_screener_form.is_valid() and movie_trailer_form.is_valid():
            movie_form.instance.user = request.user
            movie = movie_form.save()

            movie_screener_form.save(commit=False)
            movie_screener_form.instance.movie = movie
            movie_screener_form.save()

            movie_trailer_form.save(commit=False)
            movie_trailer_form.instance.movie = movie
            movie_trailer_form.save()

            movie_poster_form.save(commit=False)
            movie_poster_form.instance.movie = movie
           movie_poster_form.save()

            url = urlresolvers.reverse('explore')
            return redirect(url)
    else:
        movie_form = MovieForm(instance=request.user, label_suffix='')
        movie_screener_form = MovieScreenerForm(prefix="a", label_suffix='')
        movie_trailer_form = MovieTrailerForm(prefix="b", label_suffix='')
        movie_poster_form = MoviePosterForm(prefix="c", label_suffix='')

context = RequestContext(request, locals())
return render_to_response(template_name, context)

My views.py seems very repetitive, is this the right way to do this or is there a better way to do this?

Thanks

J

标签: django
3条回答
够拽才男人
2楼-- · 2020-03-04 08:24

One thing you could do is move the setting of the movie instance on model forms that require it from the view to the form itself by passing it in as an argument when initializing the form. Here's an example of one implementation, but this can probably be made into a base form class that others can inherit from, saving you from having to do the override in each one individually. None of this code has been tested, I'm just thinking out loud...

class MovieScreenerForm(forms.ModelForm): 
    class Meta:
        model = MovieScreener
        exclude = ('movie',)

    def __init__(self, movie, *args, **kwargs):
        super(MovieScreen, self).__init__(*args, **kwargs)
        self.movie = movie

    def save(self, commit=True):
        instance = super(MovieScreenerForm, self).save(commit=False)
        instance.move = self.movie
        instance.save()
查看更多
够拽才男人
3楼-- · 2020-03-04 08:39

If I've understood your design correctly, then:

  • Every movie has a screener
  • Movies never have more than one screener
  • A movie might have a trailer
  • Movies never have more than one trailer
  • A movie might have a poster
  • Movies never have more than one poster

Is this right?

If my assumptions are right, then you can just have all the fields on the Movie model. (The trailer and poster are already nullable, so they are optional). So you only need one model and one form.

查看更多
走好不送
4楼-- · 2020-03-04 08:46

Can't really think of a way in terms of defining the models or forms, but you can cut down on some lines with the following.

mfs = [movie_screener_form, movie_trailer_form, movie_poster_form]

for mf in mfs:
    mf.save(commit=False)
    mf.instance.movie = movie
    mf.save()
查看更多
登录 后发表回答