dear colleagues.
In my project I have successfully saved data(image) in mongodb using mongoengine. I have problem with getting image from mongodb and displaying it on the client. I'm not using local storage, so this is causing the problem with loading the page (the page will not be shown until photo_view function has been loaded the file and stored to temp file.
This is a short cut of my saved object in mongodb
{
"_id" : ObjectId("53c123edcb596046fdf6c746"),
"main_photo" : ObjectId("53c123e1cb596046fdf6c6fc"),
"create_date" : ISODate("2014-07-12T12:02:41.036Z")
}
The actual file is saved in db.fs.files using GridFS.
This is the models.py file
class Photo(Document):
def __unicode__(self):
return self.create_date
main_photo = FileField()
create_date = DateTimeField(default=datetime.datetime.now)
The problem is in photo_view function
#login_required
def photo_view(request, id, template_name):
params = {}
obj = Photo.objects.get(id = id)
print obj.main_photo.read()
params['object'] = obj
return render(request, template_name, params)
The obj.main_photo.read() is an actual file. How can I achieve in loading page without storing data in temporary file on my server. Even if I will load the data, the function photo_view will not finish until it is loaded/copied from GridFS .
Related
I have included an excel file in my project directory. I want to created a Django view that allows a user to download that file. Please how best do I handle that?
import csv
from django.http import StreamingHttpResponse
# create an echo handler, returns what is put into for the writer
psuedo_buffer = Echo()
#Build csv writer ontop of echo filelike instance
writer = csv.writer(psuedo_buffer)
#Stream the response row by row using the psuedo_writer
response = StreamingHttpResponse((
writer.writerow(row) for row in query_data),
content_type="text/csv"
)
response['Content-Disposition'] = 'attachment; filename="Something.csv"'
return response
This is a code snippet that I use to return a streaming HTTP response with the data. The data that would be in query_data can either be raw CSV data from a file handler which you can pretty easily find a few ways to open the data and drop it into this function, or you can use arrays of data from query sets to pass in. Just format your data for query_set and return this Response handler in either API views or Template views. Hope this helps!
Data should be formatted in arrays of data, which you can use .dict to get parsable data from most models or simply parsing the csv into memory with the CSV library will accomplish the same thing.
Is your file associated with a Model? I prefer to create a Model to store general resources.
models.py
class Resources(models.Model):
description = models.CharField(max_length=200)
file = models.FileField(upload_to='uploads/resources/')
def __str__(self):
return self.description
views.py
...
some_file = Resources.objects.get(description='Your description')
...
return render(request, "template.html", {
"some_file": some_file,
}
template.html
...
<p>Download file.</p>
...
I use a Minio-backend in the Django app. I have a feature that users can use the object storage(user online gallery), and Also, users can upload a new image from the device to create a post. But when I use the object storage images and create an image, images duplicate in object storage(because each time I create a post, I want to upload new images( images that upload locally) in object storage). What should I do to prevent these duplicates?
It is my model:
class MediaStorage(models.Model):
file = models.FileField(verbose_name="Object Upload",
storage=MinioBackend(bucket_name='django-backend-dev-private'),
upload_to=iso_date_prefix)
this is my create new post :
class CreatePostView(generics.CreateAPIView):
...
def post(self, request, *args, **kwargs):
user = request.user
data = request.data
...
for media_file in post_files:
file_team=post_team
f = MediaStorage.objects.create(team=file_team,owner=user)
f.media=media_file
f.save()
post.multimedia.add(f)
return Response(post_serializer.PostSerializer(post).data, status=status.HTTP_201_CREATED)
Thank you so much.
I think you shouldn't upload directly,u could get image md5 first,and a attr to MediaStorage to save md5 value,before upload check is there same md5 in DB,If has that may you already upload this image before
I am new to django and web programming. Right now, I have created a django project for configuration form generation. It allows the user to input the values and generate a configuration form once the user got the URL.
Project name: portal, App name: home, input_data.txt: a text file stored the values for the corresponding parameter and it will be read for further processing
It works fine for myself, but multiple users use it at the same time. It doesn't work. what can I do in order to allow multiple users use it at the same time?
forms.py
from django import forms
from .models import FormGen
from .models import BB_Data
class FinalForm(forms.ModelForm):
class Meta:
model=FormGen
field=['full_name','backbone_number']
class BBForm(forms.ModelForm):
class Meta:
model=BB_Data
fields=['backbone_name','IP','numbers']
widget={'numbers':forms.TextInput(attrs={'readonly':'readonly'})}
views.py
from django.shortcuts import render,HttpResponse,redirect
from .forms import FinalForm,BBForm
from django.core.files import File
import re
def replacePara(template,para):
for key,val in para.items():
template=template.replace(key,val)
return template
def create(request):
title="Router Generator"
form=FinalForm(request.POST or None)
context={
"template_title":title,
"form":form,
}
if(form.is_valid()):
form_data={
"HNAME":form.cleaned_data.get("Hostname"),
"ROLE":form.cleaned_data.get("Router_Role"),
}
form.save()
f=open('./input_para.txt','r')
a=f.read();
f.close();
tt=replacePara(a,form_data)
b=open('./input_data.txt','w')
b.write(tt)
b.close()
return redirect('/backbone')
return render(request,"home/form.html",context)
def bb(request):
title="Backbone Information"
if request.method=="POST":
form=BBForm(request.POST)
if form.is_valid():
bb_form={
'BBNAME':form.cleaned_data.get('backbone_name'),
'BBIP':form.cleaned_data.get('IP'),
}
a=int(form.cleaned_data.get('numbers')
datainput=''
if a==1:
f=open('./bb_set.txt','w')
f.write(bb_form)
f.close()
else:
f=open('./bb_set.txt','a')
outBB.write(bb_form)
outBB.close()
form.save()
f=open('./input_data.txt','r')
t=f.read()
tt=int(t.split()[7]) #it get the max number of backbones
if(at<tt):
at=at+1;
bb=BBForm(initial={'numbers':str(at)})
context={
"template_title":title,
"form":bb
}
return render(request,"home/bb.html",context)
else:
# generate the configurate text file #
content=final # content store the configurations
filename="ConfigForm.txt"
response=HttpResponse(content,content_type='text/plain')
response['Content-Disposition']='attachment; filename={0}'.format(filename)
return response
else:
return HttpResponse("something wrong")
else:
form=BBForm(initial={'numbers':"1"})
f=open('./input_data.txt','r')
t=f.read()
tt=int(t.split()[7])
context={
'template_title':title,
'form':form,
'max':tt
}
return render(request,"home/bb.html",context)
input_para: it is the text file stored the name of the parameter
input_data: it is the text file stored the values for correspond parameter
bb_set: it is the text file stored all the backbone information
You're saving data to a single file, with no regards as to users. If I go to your website, I'll be writing to the same input_data.txt, input_para.txt, and bb_set.txt files as anyone else also visiting.
This is not the way to persist user data for a website/service. You should be using a database.
Luckily, you're using Django, which has phenomenal database integration, and it's actually really easy. The hardest part, for you, will be designing the database. You'll want a User model, against which you can record input_data, input_para, and bb_set data against, from what I can tell.
I recommend you follow the Django tutorial, specifically this section, and perhaps also read up on database design, (including normalisation of data, which is more interesting than it sounds).
I am leaning how to upload file in Django, and here I encounter a should-be-trivial problem, with the error:
The submitted data was not a file. Check the encoding type on the form.
Below is the detail.
Note: I also looked at Django Rest Framework ImageField, and I tried
serializer = ImageSerializer(data=request.data, files=request.FILES)
but I get
TypeError: __init__() got an unexpected keyword argument 'files'
I have a Image model which I would like to interact with via Django REST framework:
models.py
class Image(models.Model):
image = models.ImageField(upload_to='item_images')
owner = models.ForeignKey(
User, related_name='uploaded_item_images',
blank=False,
)
time_created = models.DateTimeField(auto_now_add=True)
serializers.py
class ImageSerializer(serializers.ModelSerializer):
image = serializers.ImageField(
max_length=None, use_url=True,
)
class Meta:
model = Image
fields = ("id", 'image', 'owner', 'time_created', )
settings.py
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
'rest_framework.parsers.MultiPartParser',
),
The front end (using AngularJS and angular-restmod or $resource) send JSON data with owner and image of the form:
Input:
{"owner": 5, "image": "data:image/jpeg;base64,/9j/4QqdRXhpZgAATU0A..."}
In the backend, request.data shows
{u'owner': 5, u'image': u'data:image/jpeg;base64,/9j/4QqdRXhpZgAATU0AKgAAA..."}
But then ImageSerializer(data=request.data).errors shows the error
ReturnDict([('image', [u'The submitted data was not a file. Check the encoding type on the form.'])])
I wonder what I should do to fix the error?
EDIT: JS part
The related front end codes consists of two parts: a angular-file-dnd directive (available here) to drop the file onto the page and angular-restmod, which provides CRUD operations:
<!-- The template: according to angular-file-dnd, -->
<!-- it will store the dropped image into variable $scope.image -->
<div file-dropzone="[image/png, image/jpeg, image/gif]" file="image" class='method' data-max-file-size="3" file-name="imageFileName">
<div layout='row' layout-align='center'>
<i class="fa fa-upload" style='font-size:50px;'></i>
</div>
<div class='text-large'>Drap & drop your photo here</div>
</div>
# A simple `Image` `model` to perform `POST`
$scope.image_resource = Image.$build();
$scope.upload = function() {
console.log("uploading");
$scope.image_resource.image = $scope.image;
$scope.image_resource.owner = Auth.get_profile().user_id;
return $scope.image_resource.$save();
};
An update concerning the problem: right now I switched to using ng-file-upload, which sends image data in proper format.
The problem that you are hitting is that Django REST framework expects files to be uploaded as multipart form data, through the standard file upload methods. This is typically a file field, but the JavaScript Blob object also works for AJAX.
You are looking to upload the files using a base64 encoded string, instead of the raw file, which is not supported by default. There are implementations of a Base64ImageField out there, but the most promising one came by a pull request.
Since these were mostly designed for Django REST framework 2.x, I've improved upon the one from the pull request and created one that should be compatible with DRF 3.
serializers.py
from rest_framework import serializers
class Base64ImageField(serializers.ImageField):
"""
A Django REST framework field for handling image-uploads through raw post data.
It uses base64 for encoding and decoding the contents of the file.
Heavily based on
https://github.com/tomchristie/django-rest-framework/pull/1268
Updated for Django REST framework 3.
"""
def to_internal_value(self, data):
from django.core.files.base import ContentFile
import base64
import six
import uuid
# Check if this is a base64 string
if isinstance(data, six.string_types):
# Check if the base64 string is in the "data:" format
if 'data:' in data and ';base64,' in data:
# Break out the header from the base64 content
header, data = data.split(';base64,')
# Try to decode the file. Return validation error if it fails.
try:
decoded_file = base64.b64decode(data)
except TypeError:
self.fail('invalid_image')
# Generate file name:
file_name = str(uuid.uuid4())[:12] # 12 characters are more than enough.
# Get the file name extension:
file_extension = self.get_file_extension(file_name, decoded_file)
complete_file_name = "%s.%s" % (file_name, file_extension, )
data = ContentFile(decoded_file, name=complete_file_name)
return super(Base64ImageField, self).to_internal_value(data)
def get_file_extension(self, file_name, decoded_file):
import imghdr
extension = imghdr.what(file_name, decoded_file)
extension = "jpg" if extension == "jpeg" else extension
return extension
This should be used in replacement of the standard ImageField provided by Django REST framework. So your serializer would become
class ImageSerializer(serializers.ModelSerializer):
image = Base64ImageField(
max_length=None, use_url=True,
)
class Meta:
model = Image
fields = ("id", 'image', 'owner', 'time_created', )
This should allow you to either specify a base64-encoded string, or the standard Blob object that Django REST framework typically expects.
I ran in the same problem few days ago. Here is my django rest framework view to handle file uploading
views.py
class PhotoUploadView(APIView):
parser_classes = (FileUploadParser,)
def post(self, request):
user = self.request.user
if not user:
return Response(status=status.HTTP_403_FORBIDDEN)
profile = None
data = None
photo = None
file_form = FileUploadForm(request.POST,request.FILES)
if file_form.is_valid():
photo = request.FILES['file']
else:
return Response(ajax_response(file_form),status=status.HTTP_406_NOT_ACCEPTABLE)
try:
profile = Organizer.objects.get(user=user)
profile.photo = photo
profile.save()
data = OrganizersSerializer(profile).data
except Organizer.DoesNotExist:
profile = Student.objects.get(user=user)
profile.photo = photo
profile.save()
data = StudentsSerializer(profile).data
return Response(data)
In front-end, I used angular-file-upload lib.
Here is my file input
<div ng-file-drop="" ng-file-select="" ng-model="organizer.photo" class="drop-box" drag-over-class="{accept:'dragover', reject:'dragover-err', delay:100}" ng-multiple="false" allow-dir="true" accept="image/*">
Drop Images or PDFs<div>here</div>
</div>
And here is my upload service
main.js
(function () {
'use strict';
angular
.module('trulii.utils.services')
.factory('UploadFile', UploadFile);
UploadFile.$inject = ['$cookies', '$http','$upload','$window','Authentication'];
/**
* #namespace Authentication
* #returns {Factory}
*/
function UploadFile($cookies, $http,$upload,$window,Authentication) {
/**
* #name UploadFile
* #desc The Factory to be returned
*/
var UploadFile = {
upload_file: upload_file,
};
return UploadFile;
function upload_file(file) {
return $upload.upload({
url: '/api/users/upload/photo/', // upload.php script, node.js route, or servlet url
//method: 'POST' or 'PUT',
//headers: {'Authorization': 'xxx'}, // only for html5
//withCredentials: true,
file: file, // single file or a list of files. list is only for html5
//fileName: 'doc.jpg' or ['1.jpg', '2.jpg', ...] // to modify the name of the file(s)
//fileFormDataName: myFile, // file formData name ('Content-Disposition'), server side request form name
// could be a list of names for multiple files (html5). Default is 'file'
//formDataAppender: function(formData, key, val){} // customize how data is added to the formData.
// See #40#issuecomment-28612000 for sample code
})
}
}
})();
i try to upload a csv file into my web application and store it into mysql database but failed.Please can anyone help me?
my user.py script:
def import_contact(request):
if request.method == 'POST':
form = UploadContactForm(request.POST, request.FILES)
if form.is_valid():
csvfile = request.FILES['file']
print csvfile
csvfile.read()
testReader = csv.reader(csvfile,delimiter=' ', quotechar='|')
for row in testReader:
print "|".join(row)
return HttpResponseRedirect('/admin')
else:
form = UploadContactForm()
vars = RequestContext(request, { 'form': form })
return render_to_response('admin/import_contact.html', vars)
my forms.py script:
class UploadContactForm(forms.Form):
file = forms.FileField(label='File:', error_messages = {'required': 'File required'})
Since you haven't provided the code for the getcsv function, I'll have to use my crystal ball here a bit.
One reason why the print in the for row in testReader: loop isn't working is that getcsv may already processes the file. Use the seek method to reset the objects position in the file to zero again. That way the for loop will process it properly.
Another reason why there's nothing stored in the database might be that in the code you've supplied there doesn't seem to be a reference to a model. So how should Django know what it should store and where?