def test_transmute(self):
     
     doctype = DocumentType.objects.create(name='transmuted')
     doc = Document(
         document_type = doctype,
     )
     doc.save()
     uf = UploadedFile.transmute_document(
         doc,
         uploader=self.test_user,
     )
     uf.save()
     self.assertEqual(uf.document_ptr_id, doc.id)
     self.assertEqual(uf.document_ptr, doc)
     self.assertEqual(uf.document_type, doc.document_type)
     self.assertEqual(doc.uploadedfile, uf)
     
     self.assertRaises(ValueError, UploadedFile.transmute_document, doc, uploader=self.test_user)
def add_document(request, documentable_id):
    
    obj = Documentable.objects.get(id=documentable_id).specific_instance()
    
    # even though only one subclass of Document is listed here, this view is
    # written with adding new ones in mind
    form_classes = {
        'document': NewDocumentForm,
        'uploaded_file': NewUploadedFileForm,
    }

    form_kwargs = {}
    for name in form_classes.keys():
        form_kwargs[name] = {
            'prefix': name,
        }
    
    forms = {}
    
    if request.method == 'POST':
        # we have to instantiate the 'document' form in order to know which other
        # forms to bind
        form_kwargs['document']['data'] = request.POST
        forms['document'] = form_classes['document'](**form_kwargs['document'])
        # we only want to bind the forms the user acutally filled in
        if forms['document'].is_valid():
            is_upload = forms['document'].cleaned_data['is_uploadedfile']
            if is_upload:
                form_kwargs['uploaded_file']['data'] = request.POST
                form_kwargs['uploaded_file']['files'] = request.FILES
        
        
        # now instantiate the forms besides the 'document' form
        for name in filter(lambda fn: fn != 'document', form_classes.keys()):
            forms[name] = form_classes[name](**form_kwargs[name])
        
        if forms['document'].is_valid() and (not is_upload or (is_upload and forms['uploaded_file'].is_valid())):
            
            document = forms['document'].save(commit=False)
            document.attached_to = obj
            document.save()
            forms['document'].save_m2m()

            if is_upload:
                uploaded_file = UploadedFile.transmute_document(document, **forms['uploaded_file'].cleaned_data)
                uploaded_file.uploader = request.user
                uploaded_file.clean()
                uploaded_file.save()
                
            return redirect(obj)
    else: # request.method != 'POST'
        for name in form_classes.keys():
            forms[name] = form_classes[name](**form_kwargs[name])
    
    # the default template uses the radiohider script with forms['models']
    # select widget. TODO currently no way to pass in a custom Media to go with 
    # a custom template.
    template_media = Media(
        js= (settings.JQUERY_FILE, 'checkboxhider.js'),
    )
    media = reduce( lambda m, f: m + f.media, forms.values(), template_media)

    return render_to_response(
        'documents/add_attachment.html',
        {
            'object': obj,
            'forms': forms,
            'media': media,
        },
        context_instance= RequestContext(request),
    )