Upload multiple images at once django - django

How can I submit 3 images at once with a single input.
class Image(models.Model):
imageuploader_profile = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, null=True, blank=True)
image = models.FileField(upload_to ='pictsagram/')

I do not think this is too complicated. You just need a form with a file input having the multiple attribute and then save all the files in your view.
E.g. a very basic example
#forms.py
class ImageForm(forms.Form):
images = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
Your html form
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
<button type="submit">Upload</button>
</form>
And then create your images in your view, using getlist on the field
# views.py
def images_upload(request):
if request.method == 'POST':
form = ImageForm(request.POST, request.FILES)
if form.is_valid():
for img in request.FILES.getlist('images'):
Image.objects.create(imageuploader_profile=request.user, image=img)
return redirect('images_upload')
form = ImageForm()
context = {'form': form}
return render(request, 'images.html', context)

So, I think this is an instance of where you need to make use of the ManyToMany relationship field, creating a new model instance which stores one image, e.g., (and this is a simplistic version of something like what you would need).
from django.db import models
class ImageAttachment(models.Model):
file = models.FileField(upload_to ='pictsagram/')
Then, in your Image model:
class Image(models.Model):
imageuploader_profile = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, null=True, blank=True)
images = models.ManyToManyField(ImageAttachment)
The user will then pass up X number of images to the server, at which point you will create multiple images, and append them to the images field for the Image model.
As code organisation goes, I would also consider renaming you Image model, as it is actually storing multiple images ...

Related

Django - User can upload an image, but the image does not display - HTML issue? (Beginner help)

I'm new to Django and creating a way for users to upload an image onto a post. Then the image should be visible on each individual post's page.
So far in my 'create' function users can successfully create a post and upload a photo. The photo is uploaded into my project but it is still not displaying at all. Any help is greatly appreciated.
I think the issue is how the class in views.py, and the html in index.html is written. Just not sure how to fix.
views.py to create the post:
def create(request):
if request.method == 'GET':
context = {
'form': CreateForm(),
'form1': CategoryForm(),
'img_form': ImgForm(),
}
return render(request, "auctions/create.html", context)
else:
form = CreateForm(request.POST, request.FILES)
form1 = CategoryForm(request.POST, request.FILES)
img_form = ImgForm(request.POST, request.FILES)
if form.is_valid():
title = form.cleaned_data['title']
description = form.cleaned_data['description']
starting_bid = form.cleaned_data['starting_bid']
if form1.is_valid():
category = form1.cleaned_data['category']
if img_form.is_valid():
image = img_form.cleaned_data['image']
auctionCreated = Listings.objects.create(
title=title,
description=description,
starting_bid=starting_bid,
)
categoryCreated = Categories.objects.create(
category=category,
)
ImageCreated = Img.objects.create(
image=image,
)
return redirect('index')
views.py - this should show a list of each post (on the homepage) and each image should be visible but the image is not appearing:
def index(request):
items = Listings.objects.all()
images = Img.objects.all()
return render(request, "auctions/index.html", {
'items': items,
'images': images,
})
views.py to display image:
class ImgDisplay(DetailView):
model = Img
template_name = 'listing.html', 'index'
context_img_name = 'pic'
models.py
class Img(models.Model):
image = models.ImageField(upload_to='images/')
forms.py
class ImgForm(ModelForm):
class Meta:
model = Img
fields = '__all__'
index.html
{% for i in items %}
{% for photo in images %}
<img src="{{pic.image.url}}" class="card-img" alt="...">
{% endfor %}
<a href="{% url 'listingpage' i.id %}"><button class="btn btn-primary">Bid Now!
</button></a>
{% endfor %}
your index.html parameters are not correct. you are passing images as context parameter from index view. But when you are using for-loop in index.html you are using pic.image.url as a image source which should be photo.image.url.
if you want to show images by using ImgDisplay(DetailView) then you can use pic.image.url and also need to correct the template_name.
`template_name` = 'listing.html', 'index.html'

Gallery in Django

I have a "Category" model. I want to have it so every time I create a category it creates a directory in my media folder. From there I want to be able to upload images to the relevant folders and have a gallery in my category view that loops through every image in said categories directory.
category.html
<div class="container">
<div class="row">
{% for image in images %}
<div class="col-md-4">
<a href="/media/{{ image }}"> <img src="/media/{{ image }}" class="img-responsive img-thumbnail" width="304" height="236"/>
</a>
</div>
{% endfor %}
</div>
</div>
views.py
def category_detail_view(request, slug):
try:
category = Category.objects.get(slug=slug)
images = os.listdir(settings.MEDIA_ROOT)
context = {
"images": images,
}
except Category.DoesNotExist:
return HttpResponseNotFound()
return render(request, 'main/category_detail.html', context)
models.py
class Category(models.Model):
category_title = models.CharField(max_length=200)
category_image = models.ImageField(upload_to="category")
category_description = models.TextField()
slug = models.SlugField(max_length=200, unique=True, default=1)
class Meta:
verbose_name_plural = "Categories"
unique_together = ("category_title", "slug")
def __str__(self):
return self.category_title
This code seems to work but only for the MEDIA_ROOT. I want to loop through the current category
Ok, let's do it in your view
def category_detail_view(request, slug):
category = get_object_or_404(Category, slug=slug)
# Get the absolute path where the category images should be
category_imgs_path = os.path.abspath(os.path.join(
settings.MEDIA_ROOT,
category.slug))
# Check if the path exists, if not, create it
if not os.path.isdir(category_imgs_path):
os.mkdir(category_imgs_path)
images = os.listdir(category_imgs_path)
context = {
"images": images,
}
return render(request, 'main/category_detail.html', context)
Maybe it should be better to create the category images path when de Category itself it's created instead of viewed, You've not published the code where you create de Category instance, so, I've did it in your view, it should work anyway.
Note that I've added the usage of get_object_or_404 django shortcut to avoid the try/except, docs here -> https://docs.djangoproject.com/en/2.2/topics/http/shortcuts/#get-object-or-404
You should consider filtering the contents listed in images to ensure only images are in that variable using os.walk, glob or something similar.
Hopes this accomplish your needs, if not, don't hesitate to ask for it.
If you are creating your instance from the Admin interface
Since you are creating your instance from the admin interface, you can create the path overriding the save_model method in your ModelAdmin as follows:
class CategoryAdmin(ModelAdmin):
(...)
def save_model(self, request, obj, form, change):
category_imgs_path = os.path.abspath(os.path.join(
settings.MEDIA_ROOT,
obj.slug))
# Check if the path exists, if not, create it
if not os.path.isdir(category_imgs_path):
os.mkdir(category_imgs_path)
super().save_model(request, obj, form, change)

quick fill forms in django

Sorry I have a really basic question while learning Django and could not find an easy answer.
My model is :
class Entry(models.Model):
name = models.CharField(max_length=200)
type = models.CharField(max_length= 200)
date = models.DateTimeField(auto_now= False, auto_now_add=True)
updated = models.DateTimeField(auto_now= True, auto_now_add= False)
description = models.TextField()
And so my general form implementation is :
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ['name','type', 'description']
views:
def add(request):
if request.method == 'POST':
form = EntryForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return HttpResponseRedirect('/')
else:
form = EntryForm()
return render(request, "form.html", {'form': form})
I want to add a quick fill button next to add button (that calls above view ) where the name and type is statically filled in the object and only textbox appears for description field.
I could not find a way to statically assign the values to my field in Django.
I had tried creating a different HTML file ( quickform.html) but {{form.as_p}} will put all the fields.
my forms.html is
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<button class="btn btn-success" type='submit'>Submit</button>
</form>
what would be the best way to add a quick link to my index page where the name ( is auto-filled to the "general"+str(id)) and type is auto-filled to "general") is auto-filled and does not appear in the form page
In my opinion the easiest way to do such a thing is to add on click event to your second button then write a simple javascript function the fills the elements you want with static values.

Dropzone with django image upload

Im trying to upload images using Dropzone.js .
There doesnt seem to be any current tutorials for Dropzone although i used this link: https://amatellanes.wordpress.com/2013/11/05/dropzonejs-django-how-to-build-a-file-upload-form/
Essentially what i want to do is , The user uploads multiple images . a hotel_id is attached to the images and stored in the hotelphotos table as a url which is unique each time .
MY code
Models.py
class Photo(models.Model):
hotel = models.ForeignKey(Hotels,on_delete=models.CASCADE)
path = models.FileField(upload_to='files/%Y/%M/%d)
forms.py
class PhotosForm(forms.ModelForm):
class Meta:
model = Photo
fields = ['path']
views.py
def uploadPhoto(request,hotelid):
if request.method == 'POST':
form = PhotosForm(request.POST,request.FILES)
if form.is_valid():
new_file = Photo(path = request.FILES['file'] , hotel_id = hotelid)
new_file.save()
else:
form = PhotosForm()
hotelid = hotelid
data = {'form': form, 'hotelid':hotelid}
return render(request, template , data)
The form
<form class="dropzone" action="{% url 'ManageHotels:uploadPhoto' hotelid %} method = "POST">
</form>
Files uploaded dont get created and the url also doesnt add to the database.
Hope someone can help!

Django and users entering data

I am building a webapp which will be used by a company to carry out their daily operations. Things like sending invoices, tracking accounts receivable, tracking inventory (and therefore products). I have several models set up in my various apps to handle the different parts of the web-app. I will also be setting up permissions so that managers can edit more fields than, say, an office assistant.
This brings me to my question. How can I show all fields of a model and have some that can be edited and some that cannot be edited, and still save the model instance?
For example, I have a systems model for tracking systems (we install irrigation systems). The system ID is the primary key, and it is important for the user to see. However, they cannot change that ID since it would mess things up. Now, I have a view for displaying my models via a form using the "form.as_table". This is efficient, but merely spits out all the model fields with input fields filling in the values stored for that model instance. This includes the systemID field which should not be editable.
Because I don't want the user to edit the systemID field, I tried making it just a label within the html form, but django complains. Here's some code:
my model (not all of it, but some of it):
class System(models.Model):
systemID = models.CharField(max_length=10, primary_key=True, verbose_name = 'System ID')
systemOwner = models.ForeignKey (System_Owner)
installDate = models.DateField()
projectManager = models.ForeignKey(Employee, blank=True, null=True)
#more fields....
Then, my view for a specific model instance:
def system_details(request, systemID):
if request.method == 'POST':
sysEdit = System.objects.get(pk=systemID)
form = System_Form(request.POST, instance=sysEdit)
if form.is_valid():
form.save()
return HttpResponseRedirect('/systems/')
else:
sysView = System.objects.get(pk=systemID)
form = System_Form(instance=sysView)
return render_to_response('pages/systems/system_details.html', {'form': form}, context_instance=RequestContext(request))
Now the html page which displays the form:
<form action="" method="POST">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Save Changes">
<input type="button" value="Cancel Changes" onclick="window.location.href='/systems/'">
</form>
So, what I am thinking of doing is having two functions for the html. One is a form for displaying only those fields the user can edit, and the other is for just displaying the content of the field (the systemID). Then, in the view, when I want to save the changes the user made, I would do:
sysValues = System.objects.get(pk=SystemID)
form.save(commit = false)
form.pk = sysValues.sysValues.pk (or whatever the code is to assign the sysValues.pk to form.pk)
Is there an easier way to do this or would this be the best?
Thanks
One thing you can do is exclude the field you don't need in your form:
class System_Form(forms.ModelForm):
class Meta:
exclude = ('systemID',)
The other is to use read-only fields: http://docs.djangoproject.com/en/1.3/ref/contrib/admin/#django.contrib.admin.ModelAdmin.readonly_fields as #DTing suggessted
To make a field read only you can set the widget readonly attribute to True.
using your example:
class System_Form(ModelForm):
def __init__(self, *args, **kwargs):
super(System_Form, self).__init__(*args, **kwargs)
self.fields['systemID'].widget.attrs['readonly'] = True
class Meta:
model = System
or exclude the fields using exclude or fields in the class Meta of your form and display it in your template if desired like so:
forms.py
class System_Form(ModelForms):
class Meta:
model = System
exclude = ('systemID',)
views.py
def some_view(request, system_id):
system = System.objects.get(pk=system_id)
if request.method == 'POST':
form = System_Form(request.POST, instance=system)
if form.is_valid():
form.save()
return HttpResponse('Success')
else:
form = System_Form(instance=system)
context = { 'system':system,
'form':form, }
return render_to_response('some_template.html', context,
context_instance=RequestContext(request))
some_template.html
<p>make changes for {{ system }} with ID {{ system.systemID }}</p>
<form method='post'>
{{ form.as_p }}
<input type='submit' value='Submit'>
</form>