1

Database: Document has many Sections, Sections has many Comments

On each document page, there is a comment form that lets you pick the section (using a ModelChoiceField). The problem is that the ModelChoiceField will contain ALL sections for all documents.

So to limit them I do this:

class CommentForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(CommentForm, self).__init__(*args, **kwargs)
        if self.instance:
            logger.debug(self.instance.document_id) # Prints "None"
            self.fields['section'].queryset = Section.objects.filter(document=self.instance.document)
            # ^^^ Throws DoesNotExist as self.instance.document is None

and my view is just:

form = CommentForm()

How do I pass CommentForm a document id?

Edit: Tried in my view:

d = Document.objects.get(id=id)
c = Comment(d)
form = CommentForm(c)

but document_id is still None in CommentForm

bcoughlan
  • 25,987
  • 18
  • 90
  • 141

1 Answers1

5

You can pass the document id when initialising the form:

class CommentForm(ModelForm):
    def __init__(self, doc_id=None, *args, **kwargs):
        if doc_id:
            self.fields['section'].queryset = Section.objects.filter(document__id=doc_id)

and in the view

def my_view(request):
    ...
    doc = Document.objects(...)
    form = CommentForm(doc_id = doc.id)

EDIT

I edited the second line of the view, which I think deals with your comment? (make doc.id) a keyword arguement

Timmy O'Mahony
  • 53,000
  • 18
  • 155
  • 177
  • The latter would be for editing an existing object unless I'm way off? Kicking myself now, so obvious! Thank you – bcoughlan Jun 01 '11 at 19:06
  • 2
    Just my additional 2 cents... I think it's a bit better to change the queryset like this: `self.fields['section'].queryset = self.fields['section'].queryset.filter(document__id=doc_id)` – Botond Béres Jun 01 '11 at 19:32
  • @Beres Thanks, that worked well. @pastylegs - This method actually runs into a problem, because when Django calls CommentForm when using .save(), *args will be missing its first argument. I know there are hacks around this, but surely this is a really common task in Django that shouldn't need hacks... – bcoughlan Jun 01 '11 at 21:07
  • 1
    Are you sure? *args are positional arguments while **doc_id=None** is a keyword argument so it doesn't matter where you put it, the positional arguments shouldn't be affected – Timmy O'Mahony Jun 01 '11 at 21:09
  • Hmmm, yep, seems to be a different problem :/ – bcoughlan Jun 01 '11 at 21:25