views:

24

answers:

0

I have a ManyToMany field with a relationship model. I want a formset, filtered on one of the keys, which shows a form for each of the other keys.

My guess is that a custom manager on the relationship model is the key to solving this problem. The manager would return "phantom" instances initialized with the appropriate ForeignKey when no real instance was in the database. I'm just don't know how to make a manager add "phantom" instances when it seems designed to filter out existing ones.

I'm hoping an example is worth 1K words.

Say I want my users to be able to rate albums. I would like to display a formset with a form for all albums by the selected band. Example models & view

from django.contrib.auth.models import User
from django.db import models

class Band(models.Model):
    name = models.CharField(max_length=30)

    def __unicode__(self):
        return self.name

class Album(models.Model):
    name = models.CharField(max_length=30)
    band = models.ForeignKey(Band)
    ratings = models.ManyToManyField(User, through="Rating")

    def __unicode__(self):
        return self.name


class Rating(models.Model):
    user = models.ForeignKey(User)
    album = models.ForeignKey(Album)
    rating = models.IntegerField()

    def __unicode__(self):
        return "%s: %s" % (self.user, self.album)

# views.py
from django.forms.models import modelformset_factory
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template.context import RequestContext
from models import Band, Rating


RatingFormSet = modelformset_factory(Rating, exclude=('user',), extra=1)

def update(request):
    user = request.user
    band = Band.objects.all()[0]
    formset = RatingFormSet(request.POST or None,
                      queryset=Rating.objects.filter(album__band=band, 
                                                     user=user))

    if formset.is_valid():
        objects = formset.save(commit=False)
        print "saving %d objects" % len(objects)

        for obj in objects:
            obj.user = user
            obj.save()    
        return HttpResponseRedirect("/update/")

    return render_to_response("rating/update.html", 
                              {'formset': formset, 'band':band},
                              context_instance=RequestContext(request))

The problem is it only shows forms for existing relationship instances. How can I get an entry for all albums.

Thanks.