wiki:FileUploadTutorial
Warning: Can't synchronize with repository "(default)" (Unsupported version control system "svn": No module named svn). Look in the Trac log for more information.

Version 1 (modified by GreenTea <tgreenwoodgeer@…>, 14 years ago) (diff)

initial add...

File Upload Tutorial

TurboGears 0.8a3

This is a follow up to the existing 20 minute wiki:  http://turbogears.org/docs/wiki20/index.html. Note, I am writing this after creating this, and looking at my code and the email thread. Please make changes at will if I have slipped up.

I'll add a zip of the full project directory, so don't feel like you have to copy and paste from this page...just grab the real thing, amigo.

TODO: template replace (see below)

-Todd

Update the DB Tables

  1. stop the server
  2. drop the existing tables
    • tg-admin sql drop page
    • tg-admin sql drop uploadedfile
  3. your new model.py
    from sqlobject import *
    from turbogears.database import PackageHub
    
    hub = PackageHub("toddswiki")
    __connection__ = hub
    
    # class YourDataClass(SQLObject):
    #     pass
    
    class Page(SQLObject):
            pagename = StringCol(alternateID=True, length=30)
            data = StringCol()
            attached_files = RelatedJoin('UploadedFile')
    
    class UploadedFile(SQLObject):
            filename = StringCol(alternateID=True)
            abspath = StringCol()
            size = IntCol()
            referenced_in_pages = RelatedJoin('Page')
    
  4. create the new tables
    • tg-admin sql create

Add the 'upload' Method

  1. Add upload directory to the cfg file #def.cfg
    [global]
    
    # Upload dir
    wiki.uploads="./uploads"
    
  2. Add upload dir check to controller, create it if nec. #controller.py
    #default upload dir to ./uploads
    UPLOAD_DIR = cherrypy.config.get("wiki.uploads", os.path.join(os.getcwd(),"uploads"))
    if not os.path.exists(UPLOAD_DIR):
        os.makedirs(UPLOAD_DIR) 
    
  3. Add the 'upload' method #controller.py
    	@turbogears.expose()
    	def upload(self, upload_file, pagename, new, **keywords):
    		try:
    			p = Page.byPagename(pagename)
    		except SQLObjectNotFound:
    			turbogears.flash("Must save page first")
    			raise cherrypy.HTTPRedirect(turbogears.url("/%s" % pagename))
    		
    		total_data=''
    		while True:
    			data = upload_file.file.read(8192)
    			if not data:
    				break
    			total_data += data
    		target_file_name = os.path.join(os.getcwd(),UPLOAD_DIR,upload_file.filename)
    		try:
    			u =  UploadedFile.byFilename(upload_file.filename)
    			turbogears.flash("File already uploaded: %s is already at %s" %  (upload_file.filename, target_file_name))
    		except SQLObjectNotFound:
    			f = open(target_file_name, 'w')
    			f.write(total_data)
    			f.close
    			turbogears.flash("File uploaded successfully: %s saved as : %s" % (upload_file.filename, target_file_name))
    			u = UploadedFile(filename=upload_file.filename, abspath=target_file_name, size=0)
    			
    		Page.byPagename(pagename).addUploadedFile(u)
    		raise cherrypy.HTTPRedirect(turbogears.url("/%s" % pagename))
    
  4. Note: the above uses the db to determine the page state (e.g. can we upload a page yet? no, not if the page doesn't exist yet)
    		try:
    			p = Page.byPagename(pagename)
    		except SQLObjectNotFound:
    			turbogears.flash("Must save page first")
    			raise cherrypy.HTTPRedirect(turbogears.url("/%s" % pagename))
    

Add 'upload' to the page.kid

  1. Initially, I was going to follow the footsteps of the previous tutorial, and use the hidden page variable 'new' to determine if the page had been created yet...but i had problems with this. Anyway, I think that state info is best queried from the db, anyway. Keep things simple. #page.kid
    	<form action="upload" method="post" enctype="multipart/form-data">
    		<input type="hidden" name="pagename" py:attrs="value=pagename"/>
    		<input type="hidden" name="new" value="${new}"/>
    		filename: <input type="file" name="upload_file"/><br/>
    		<input type="submit" name="submit_upload" value="Upload"/>
    	</form>
    

Add the goo to display the file listings

  1. Here is the code:
    	<ul>
    		Attached Files:
    		<li py:for="filename in uploads"><a href="/download?filename=${filename}" py:content="filename">Filenamehere.</a></li>
    	</ul>
    
  2. Add this code to page.kid and edit.kid
  3. TODO: someone can help me with the template/replace stuff here

Add the 'download' method

  1. cherrypy.lib.cptools.serveFile : this is pretty cool! #controller.py
    	@turbogears.expose()
    	def download(self, filename):
    		uf = UploadedFile.byFilename(filename)
    		return cherrypy.lib.cptools.serveFile(uf.abspath, "application/x-download", "attachment", uf.filename)
    

Add error handling to the index method, just in case publish parts barfs

#controller.py

	@turbogears.expose(html="toddswiki.templates.page")
	def index(self, pagename="FrontPage"):
		try:
			page = Page.byPagename(pagename)
			uploads = [item.filename for item in page.attached_files]
		except SQLObjectNotFound:
			raise cherrypy.HTTPRedirect(turbogears.url("/notfound",pagename=pagename))
		try:
			content = publish_parts(page.data, writer_name="html")["html_body"]
		except:
			content = page.data

		root = str(turbogears.url("/"))
		content = wikiwords.sub(r'<a href="%s\1">\1</a>' % root, content)
		content = content.encode("utf8")
		return dict(data=content, pagename=page.pagename, uploads=uploads)

Attachments