I am working on a platform where I need to allow users to upload multiple images in one post.
I want to keep it as simple as possible, so that a person wouldn't have to refresh the page to upload each image, or create and save a post before adding images.
If a user could delete or reorder images it would be nice
Can you give me advice on how to do it properly?
I am using django , postgres and here's what I have done so far .
On my models.py -
class ImagePost(models.Model):
user = models.ForeignKey("profiles.HNUsers", on_delete=models.DO_NOTHING)
image = OptimizedImageField("Post Image", blank=True, null=True)
timestamp = models.DateTimeField("Timestamp", blank=True, null=True, auto_now_add=True)
text = models.TextField("Description text", blank=True)
class Meta:
verbose_name_plural = "Image Posts"
It can take one image just fine . what should I change to make it multi upload post
On my views.py this is what I have done so far -
#api_view(['POST'])
#permission_classes((permissions.AllowAny,))
def image_post(request):
if request.method == 'POST':
data = request.data
print(data)
serializer = ImagePostSerializer(data=data)
if serializer.is_valid():
serializer.save()
print("image object saved")
try:
image_post_object = ImagePost.objects.filter(user__id=data['user']).order_by('-timestamp')[0]
print(image_post_object)
try:
post = Posts()
post.user = HNUsers.objects.get(id=data['user'])
post.image_url = image_post_object.image.url
post.type = 'I'
post.category = data['category']
post.created_on = image_post_object.timestamp
post.text = image_post_object.text
save_post = post.save()
post_id = post.pk
try:
user = HNUsers.objects.get(pk=data['user'])
if user.user_type == 'HN':
payload = {
"user_name": user.full_name,
"image_url": user.profile_img_url,
"post_id": post_id,
"notification_type": "hn"
}
print(payload)
broadcast_notification('all', payload, 1)
except HNUsers.DoesNotExist:
print("user_id_does_not_exist")
print("post object created")
except Posts.DoesNotExist:
print("Failed - post creation failed")
except HNUsers.DoesNotExist:
print("Failed - user object not found")
except ImagePost.DoesNotExist:
print("Failed - image object not found")
return Response(serializer.data, status=status.HTTP_200_OK)
Any advice is really appreciated.
I am not sure if this can help, but why you dont use more than one table to store images in DB:
class Images(models.Model):
user = models.ForeignKey("profiles.HNUsers",
on_delete=models.DO_NOTHING)
image_post = models.ForeignKey(ImagePost, on_delete=models.CASCADE)
image = OptimizedImageField("Post Image", blank=True, null=True)
Now you have conected multiples images to a post and a user.
Hope this helps a bit...
Check this excellent django version of jQuery-File-Upload :
https://github.com/sigurdga/django-jquery-file-upload
Some features:
Drag and drop files
Select multiple files
Cancel upload
Delete uploaded file
You can avoid a lot of code repetition and add multiple images for a model by creating an intermediate model which will handle mapping between your image and the model. Create proper binding like one to one , you can look at this tutorial
Related
Currently working on a django social media application where next to posting every post to the feed, the information of each upload should create a pdf document, containing caption, image, created_at and image_id.
I´ve put the canvas into the upload functions, so that both will be created on the same click. So far, i get a pdf (can't get the attributes from the post into the pdf tho) and the post is uploaded just fine.
How do I get the posted data into the pdf?
And how do save that pdf to a folder within the project instead of starting an automatic download? The user should not be able to notice the pdf converting. It is just for back office - but very necessary due to the social media website being a part of a big installation. So how do I get these pdfs?
Here is the code:
views.py
def upload(request):
if request.method == 'POST':
#user = request.user.username
image = request.FILES.get('image_upload')
caption = request.POST['caption']
new_post = Post.objects.create( image=image, caption=caption)
new_post.save()
#create pdf
buffer = io.BytesIO()
p = canvas.Canvas(buffer)
p.drawString(100, 100, "Hello world.")
p = request.FILES.get('post_pdf')
p.drawText('caption')
p.drawImage('image')
p.showPage()
p.save()
buffer.seek(0)
return FileResponse(buffer, as_attachment=True, filename='hello.pdf')
return redirect('/')
else:
return redirect('/')
models.py
class Post(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
image = models.ImageField(upload_to='post_images')
caption = models.TextField(max_length=300)
created_at = models.DateTimeField(auto_now_add=True)
number_of_likes = models.IntegerField(default=0)
number_of_dislikes = models.IntegerField(default=0)
#interaction_count = models.IntegerField(default=0)
#engagement_count = models.IntegerField(null=True)#number_of_dislikes + number_of_likes
def __str__(self):
return self.caption
To add the value of Post.caption into the pdf, use the value of new_post.caption, change this:
p.drawText('caption')
for this:
p.drawText(new_post.caption)
Same for other fields.
This is not as hard as it seems,
so Let's see if you are successful in creating a pdf and now you have to store it in background instead of downloading.
file_name = request.FILES["file_name"]. #suppose file_name is file name
file_name = default_storage.save(rf"{basePath}/media/whatsapp/file_name.pdf", file_name) #{basePath}/media/whatsapp/ is the path name where we want it to be stored
I've got problem with saving data to non-default database.
In models.py I've got:
grid_fs_storage = GridFSStorage(collection='tab_userinquiries', base_url='mydomain.com/userinquiries/',database='mongo_instance')
class DocsUserInquiry(models.Model):
query_pk = models.CharField(blank=False, null=False, unique=True, max_length=150, primary_key=True) # auto - calculated
query_file_md5 = models.CharField(blank=False, null=True, unique=False, max_length=200) # auto - calculated
query_file = models.FileField(upload_to='userinquiries',storage=grid_fs_storage,null=True) # auto from form
In views.py:
class UploadInquiryFileView(CreateView,LoginRequiredMixin):
model=DocsUserInquiry
template_name ='new_inquiry.html'
success_message = "You've added your new Token successfully"
form_class = UploadInquiryFileForm
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request.FILES)
if form.is_valid():
file_name = request.FILES['query_file'].name
print(f'file...{file_name}')
q_pk = random_id()
file_in = self.request.FILES.get('query_file')
f_md5 = calculate_md5(file_in)
form.instance.query_pk = q_pk
form.instance.query_file_md5 = f_md5
form.save()
return HttpResponse(self.success_message)
The problem is every time when I submit form I've got
Exception Type: TypeError
Exception Value: database must be an instance of Database
I've tried added this to post method:
instance = form.save(commit=False)
instance.save(using='mongo_instance')
but the error is the same.
Any ideas how to resolve this issue?
NOTE:
This issue is related only with modelform or when I use custom list of fields in view. When I'm using CreateView without ModelForm but with fields = 'all' and additionally with the logic passed to form_valid method of the view instead of post everything works fine. Then files are added to my mongo db.
After some tests I've figured out the problem is in gridfs. After making small change in FileField I got expected result.
I had to delete upload_to and storage from this field in models.py. This saves data from my form into mongo but without the file itself. To do that I had to add in post method of my CreateView connection to mongo via MongoClient and save file in such separate way.
Completely don't know what's the issue with gridfs storage pointed directly in the model's FileField.
models.py
class FileUpload(models.Model):
File_Name = models.CharField(max_length=255, blank=True)
File_path = models.FileField(upload_to='')
Description = models.CharField(max_length=255, blank=True)
Upload_Date = models.DateTimeField(auto_now_add=True)
forms.py
class FileUploadForm(forms.Form):
class Meta:
model = FileUpload
File_Name = forms.CharField(label="File Name",max_length=255)
Description = forms.CharField(label="Description", max_length=255)
I'm new in Django.I need help. How to upload images in the database and view those images? Thanks in advance!
here paths are stored in database and images are stored in a folder. But I don't need that. I want to save images and path to the database and I need to view that image. Please help!
views.py:
def uploadfile(request):
print('inside upload logic')
if request.method == 'POST':
form = FileUploadForm(request.POST, request.FILES)
if form.is_valid():
# ImageUpload(request.FILES['File_Name'])
myfile = request.FILES['File_Name']
fs = FileSystemStorage()
filename = fs.save(myfile.name, myfile)
uploaded_file_url = fs.url(filename)
newdoc = FileUpload(File_Name=myfile.name, File_path=uploaded_file_url, Description=request.POST['Description'])
newdoc.save()
#return HttpResponse("File uploaded successfuly")
return render(request, 'Login/fileupload.html')
else:
form = FileUploadForm()
return render(request, 'Login/fileupload.html', {
'form': form
})
You normally shouldn't store the image data in your database. If you need to upload and store images, use the ImageField or FileField and follow the instructions from the docs to save the image. The only thing you need to do is:
form = FileUploadForm(request.POST, request.FILES)
if form.is_valid():
uploaded_file = FileUpload(
File_path=request.FILES['File_path'], # or whatever you've called the file input
File_name=form.cleaned_data['File_Name'],
Description=form.cleaned_data['Description'])
uploaded_file.save()
It would be easier to use a ModelForm in your case, then you only need to save the form:
if form.is_valid():
form.save()
This will automatically save the file in the correct way. No need to do the saving manually like you are doing.
To view the image is as simple as this:
file_upload = FileUpload.objects.get(id=34)
file_url = file_upload.File_path.url # url relative to `MEDIA_ROOT`
# or in a template
{% load static %}
{% get_media_prefix %}{{ file_upload.File_path.url }}
If you really need to store the images as binary blobs to your database (but beware that it almost never makes sense to do so), use Django's BinaryField, as described here.
This also means you will have to handle transforming the image back and forth from a binary blob to a proper image file. Consider also storing the content type (image/jpg or image/png or image/webp) since you will need that to properly re-create the file.
with django 1.5.1 I try to use the django form for one of my models.
I dont want to add the "user" field (Foreignkey) somewhere in the code instead of letting the user deceide whoes new character it is.
My Code:
Model:
class Character(models.Model):
user = models.ForeignKey(User)
creation = models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')
name = models.CharField(max_length=32)
portrait = models.ForeignKey(Portrait)
faction = models.ForeignKey(Faction)
origin = models.ForeignKey(Origin)
The form:
class CreateCharacterForm(forms.ModelForm):
class Meta:
model = Character
fields = ['name', 'portrait', 'faction', 'origin']
The view:
def create_character(request, user_id):
user = User.objects.get(id=user_id)
if request.POST:
new_char_form = CreateCharacterForm(request.POST)
if new_char_form.is_valid():
new_char_form.save()
return HttpResponseRedirect('%s/characters/' % user_id)
else:
return render_to_response('create.html',
{'user': user, 'create_char':new_char_form},
context_instance=RequestContext(request))
else:
create_char = CreateCharacterForm
return render_to_response('create.html',
{'user': user, 'create_char': create_char},
context_instance=RequestContext(request))
I have tried to use a instance to incluse the userid already. i've tried to save the userid to the form before saving it, or changing the save() from my form.
I keep getting the error that character.user cant be null
I have to tell that im pretty new to django and im sure one way or another it should be possible
Can someone please help me out?
Its explained well in document model form selecting fields to use
You have to do something like this in your view
...
if request.POST:
new_char_form = CreateCharacterForm(request.POST)
if new_char_form.is_valid():
#save form with commit=False
new_char_obj = new_char_form.save(commit=False)
#set user and save
new_char_obj.user = user
new_char_obj.save()
return HttpResponseRedirect('%s/characters/' % user_id)
else:
...
I am writing my first django app that uses the ImageField and I am having
difficulty. The problem is that my images are not uploading. I have looked at
as many examples that I can find. And I'm not sure what's going wrong here.
I am trying to verify that my photos are uploading by looking in the location
of the upload_to directory. When the form is displayed in the web page the
correct upload file button is displayed. When I hit submit, the code below executes,
but no images are ever uploaded.
Based on the upload_to, I am expecting to see images uploaded to see images under either:
myproject/photos or myproject/media/photos correct?
Am I doing anything obvious wrong here? How do I get my images to upload?
--------------settings.py-------------
MEDIA_ROOT = '/home/me/django_projects/myproject/media/'
MEDIA_URL = '/media/'
--------------model.py-------------
class Person(models.Model):
lastName = models.CharField(max_length=20)
firstName = models.CharField(max_length=20)
image = models.ImageField(upload_to='photos', blank=True, null=True)
# save executes but no image is saved.
# Because images are uploaded along with a new entry, I needed a special
# work around to get the self.id
def save(self):
for field in self._meta.fields:
if field.name == 'image':
if self.id is not None:
#save image now
field.upload_to = 'photos/%d' % self.id
else:
#Save image later
saveImageLast = True
super(Customer, self).save() # should create self.id if not already
if saveImageLast == True:
field.upload_to = 'photos/%d' % self.id
super(Customer, self).save()
print "save complete" #prints, but no image ...?
--------------forms.py-------------
class PersonForm(ModelForm):
class Meta:
model = Person
fields = ( 'lastName', 'firstName', 'image' )
from django documentation, i think this can help (in the past this helped me):
Firstly, in order to upload files, you'll need to make sure that your
element correctly defines the enctype as "multipart/form-data"
<form enctype="multipart/form-data" method="post" action="/foo/">
In your view where you create an instance of the form with post data, ensure you have provided request.FILES
form = PersonForm(request.POST, request.FILES)
This is a bit late, but 'upload_to' is not a method. It's an attribute that represents the relative path from your MEDIA_ROOT. If you want to save an image in the folder 'photos' with the filename self.id, you need to create a function at the top of your model class. For instance:
class Person(models.Model):
def file_path(instance):
return '/'.join(['photos', instance.id])
image = models.ImageField(upload_to=file_path)
Then when you are actually saving your image you would call:
person = Person(firstName='hey', lasteName='joe')
person.image.save(ImageObject.name, ImageObject)
More on the image file objects here.
More on upload_to here.