Are you using the django.contrib.auth
module to log users in and out? This has a middleware component that appends the current User
object to the request
parameter and works reasonably well with Ajax. It also provides redirects to log in pages if a user isn't currently logged in. More info here. A possible solution:
views.py:
from django.shortcuts import render_to_response
from django.http import HttpResponse
from django.utils import simplejson
from django.contrib.auth.decorators import login_required
from filetransfers.api import prepare_upload, serve_file
from blog.models import BlogEntry
from blog.forms import BlogEntryForm
@login_required
def createBlogEntry(request):
return render_to_response('blogEdit.html', { 'form' : BlogEntryForm() })
@login_required
def uploadImage(request):
if request.method == 'POST':
form = BlogEntryForm(request.POST, request.FILES)
if form.is_valid():
newEntry = BlogEntry()
newEntry = request.FILES['blogImage']
newEntry.image = request.FILES['file'].name
newEntry.user = request.user
# delete unsaved previous blog post
try:
oldEntry = BlogEntry.objects.get(user=request.user,completed=False)
oldEntry.delete()
except:
pass
newEntry.save()
return HttpResponse(simplejson.dumps({'imageLocation' : '/static/media/blogImgs/%s' % request.FILES['image'].name }), mimetype='application/javascript')
return HttpResponse(simplejson.dumps({"error" : 101, "message" : "Big error!"}}), mimetype="application/json")
@login_required
def uploadText(request):
if request.method == 'POST':
if form.is_valid():
newEntry = BlogEntry()
try:
newEntry = BlogEntry.objects.get(user=request.user,completed=False)
except:
pass
newEntry.blogText = request.POST['blogText']
newEntry.completed = True
newEntry.save()
return HttpResponse(simplejson.dumps({'result' : 'success'});
return HttpResponse(simplejson.dumps({"error" : 102, "message" : "other Big error!"}}), mimetype="application/json")
The first method will display the page and form to create the blog entry and the others handle the 2 ajax calls for uploading the image and text. After the image has been uploaded the temporary BlogEntry
is stored, if a previous entry has not been completed it is deleted now. When the text is uploaded the temporary blog entry is completed and saved.
It would be possible to have multiple temporary blog entries (for multiple tab in the browser - like this site), with perhaps a maximum number of items set. If the django.auth.contrib
package is not being used it should be possible to use the session middleware instead - there are quite a few options here.
A sketch of the rest of the files:
models.py:
from django.db import models
from django.contrib.auth.models import User
class blogEntry(models.Model):
user = models.ForeignKey(User)
created = models.DateField(auto_now_add = True)
completed = models.BooleanField(default = False)
blogText = models.TextField()
image = models.ImageField(upload_to = 'blogImgs/')
def delete(self, *args, **kwargs):
# Delete image file also
storage, path = self.image.storage, self.image.path
super(ImageModel, self).delete(*args, **kwargs)
storage.delete(path)
The delete method has been overridden to delete the image file after the entry file has been removed.
template: blogEdit.html
<html><head><title>New Blog Entry</title></head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script type="text/javascript" src="//cdn.jsdelivr.net/jquery.fileupload/8.9.0/js/jquery.fileupload.js"></script>
<style type="text/css">
form { float: left; }
#textForm {
width: 320px;
padding: 8px;
}
#textForm textarea {
width: 320px;
height: 150px;
margin-bottom: 8px;
}
#imageForm {
width: 100px;
padding-top: 8px;
}
#blogImage {
width: 120px;
height: 120px;
}
#imageForm input[type=file] {
margin: 8px 0 8px 0;
}
</style>
</head>
<body>
<form id="textForm">{% csrf_token %}
<textarea id="blogText" name="blogText"></textarea>
<input type="button" value="upload text" id="textUpload"/>
<img id="blogImage" src="/static/imgs/holdingImage.png" />
<input id="fileupload" type="file" name="blogImage">
</form>
<script>
$(function () {
$('#fileupload').fileupload({
url: '/ajax/uploadImage/',
dataType: 'json',
done: function (e, data) {
blogImage.attr('src', data.result.imageLocation)
}
});
});
$('#textUpload').click(function() {
$.ajax({
url: '/ajax/uploadText/',
dataType: 'json',
data: $('#blogText').val(),
done: function(e, data) {
if(data.result == 'success') {
// display message / redraw edit area with complete blog, etc..
} else if(data.error) {
// error handing code
}
}
});
});
</script>
</body>
</html>
This uses jquery-file-upload to upload the files.
There can be some issues with using Ajax and Django csrf protection see here. It may be required to copy the csrf token into the ajax call, see here. The Ajax done callback for the jquery-file-upload will load the uploaded image into the page, replacing the holding image.
forms.py
from django import forms
class BlogEntryForm(forms.Form):
blogImage = forms.FileField()
blogText = forms.TextField()
urls.py
from django.conf.urls import patterns, include, url
import blog.views
urlpatterns = patterns('',
url(r'^createEntry/$', 'blog.views.createBlogEntry', name='createBlogEntry'),
url(r'^ajax/uploadImage/', 'blog.views.uploadImage'),
url(r'^ajax/uploadText/', 'blog.views.uploadText'),
...additional urls for django.contrib.auth
);