Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add image into a post in django

I'm building an blog system, which allow user add image to their blog.

when user add image, the image will be upload automatically, this happened before the blog is posted, so how should I handle the uploaded image, these image is kind of like temporary image, because if the user post the blog, these images will have an foreign key to this blog , and saved into some folder,but if the user discard the blog , these temporary images should be deleted.

the problem is how to get the firstly uploaded images,when the blog is actually posted? where should I store these temporary images? and how can I tell if the user discard the blog?

like image 282
paynestrike Avatar asked Oct 23 '13 08:10

paynestrike


2 Answers

I would suggest the following:

  1. Modify the Post model to add a datetime field called published which allows NULL.
  2. Use the field published to determine if the post is published yet or not. A post will be considered as a draft if the published field has NULL, published otherwise.
  3. Create the post as soon as you hit the create post button. This will give you a Post object with the id which you can bind to a ModelForm and display to the user for editing. So when they add a picture, you can upload it and bind it to the id of the post in whatever way you want.
  4. Change the published to the datetime.now() only when you hit the publish button.
  5. Deleting a published or draft post should delete all of the linked resources like images.

Hope it helps.

like image 170
Imran S. Avatar answered Sep 21 '22 02:09

Imran S.


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
);
like image 27
Henry Florence Avatar answered Sep 21 '22 02:09

Henry Florence