I want to implement dynamic multiple image upload for an application in Django. I got to know that Django doesn't have any in-built support for that and external libraries have to be used.
I followed the blog - https://simpleisbetterthancomplex.com/tutorial/2016/11/22/django-multiple-file-upload-using-ajax.html
But the result I'm getting is nowhere close to what is expected.
Starting with settings.py
import os
SETTINGS_DIR = os.path.dirname(__file__)
PROJECT_PATH = os.path.join(SETTINGS_DIR, os.pardir)
PROJECT_PATH = os.path.abspath(PROJECT_PATH)
MEDIA_ROOT = os.path.join(PROJECT_PATH, 'media')
MEDIA_URL = '/media/'
models.py
class Images(models.Model):
file = models.FileField(upload_to='profile_images')
category = models.CharField(max_length=20, blank=False)
time = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return self.category
forms.py
class ImagesForm(forms.ModelForm):
class Meta:
model = Images
fields = ['file',]
upload.html
<!DOCTYPE html>
<html>
<head>
<title>Upload</title>
</head>
<body>
<form id="category_form" method="post" action="/rango/upload/" enctype="multipart/form-data">
{% csrf_token %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-file-upload/9.22.0/js/vendor/jquery.ui.widget.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-file-upload/9.22.0/js/jquery.iframe-transport.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-file-upload/9.22.0/js/jquery.fileupload.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-file-upload/9.22.0/js/jquery.fileupload.js"></script>
{# 1. BUTTON TO TRIGGER THE ACTION #}
<button type="button" class="btn btn-primary js-upload-photos">
<span class="glyphicon glyphicon-cloud-upload"></span> Upload photos
</button>
{# 2. FILE INPUT TO BE USED BY THE PLUG-IN #}
<input id="fileupload" type="file" name="file" multiple
style="display: none;"
data-url="{% url 'upload' %}"
data-form-data='{"csrfmiddlewaretoken": "{{ csrf_token }}"}'>
{# 3. TABLE TO DISPLAY THE UPLOADED PHOTOS #}
<table id="gallery" class="table table-bordered">
<thead>
<tr>
<th>Photo</th>
</tr>
</thead>
<tbody>
{% for photo in photos %}
<tr>
<td>{{ photo.file.name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="modal fade" id="modal-progress" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Uploading...</h4>
</div>
<div class="modal-body">
<div class="progress">
<div class="progress-bar" role="progressbar" style="width: 0%;">0%</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
views.py
def upload(request):
photos_list = Images.objects.all()
if request.method == 'POST':
form = ImagesForm(request.POST,request.FILES)
if form.is_valid():
photo = form.save()
data = {'is_valid': True, 'name': photo.file.name, 'url': photo.file.url}
else:
data = {'is_valid': False}
return JsonResponse(data)
return render(request, 'rango/upload.html', {'photos': photos_list},)
The output that I get for the /upload/ page is
As you can see, only text is getting display for upload button and uploading progress bar and it's not actually working.
My guess here is that the jQuery libraries aren't getting included or/and JavaScript code isn't working. I am a backend engineer, so please excuse this might be silly question about frontend.
Shall be thankful if someone helps with code specificities.
Related
Doubt:
Here I have mentioned Html and output Image.
If I click select all option (checkbox) it will select all image but my doubt was how to delete all images once I click delete button.
Html
{% for j in img %}
<h4>
Select All
<input type="checkbox" onclick="$('input[name*=\'selected\']').prop('checked', this.checked);" />
</h4>
<button class="btn btn-danger" action=" ">Delete</button>
<div class="col">
{% if i.placename == j.gallery_place %}
<div class="show-image">
<img src="{{j.gallery_image.url}}" style="height:130px; width:130px;" />
<tag class="one" style="margin:8%">
<input type="checkbox" name="selected[]" value="{{j.id}}" />
</tag>
</div>
{% endif %}
</div>
{% endfor %}
image
enter image description here
You can use a FormView in Django and process them as follows. You need to create a form with the checkboxes first:
# forms.py
class CheckboxesForm(forms.Form):
checkboxes = forms.ModelMultipleChoiceField(
MyModel.objects.all(),
widget=forms.CheckboxSelectMultiple)
Then you need to write your own FormView and override the form_valid() method to perform the deletion of the selected objects. If you want to define objects for which you have checkboxes, you can override the get_form() method.
# views.py
class MyListView(ListView):
"""
View displaying a list of objects, you will redirect here after successfully deleting the objects you want
"""
model = MyModel
class MyView(FormView):
"""
Class based view taking care of rendering the form and processing it after posting. Finally, redirects you to your list view defined above.
"""
form_class = MyForm
def get_context_data(self, **kwargs):
context = super(MyView, self).get_context_data(**kwargs)
context['objects'] = MyModel.objects.all() # Customize this queryset to your liking
return context
def get_form(self, form_class=None):
form = super().get_form(form_class)
form.fields['checkboxes'].queryset =
MyModel.objects.all() # Customize this queryset to determine for which objects you want to display checkboxes
return form
def form_valid(self, form):
qs = myModel.objects.filter(
pk__in=list(map(int, self.request.POST.getlist('checkboxes'))))
qs.delete()
return HttpResponseRedirect(reverse_lazy('someurl'))
Your template will look like this (adapted from what you posted)
# template.html
{% for j in objects %}
<h4>
Select All
<input type="checkbox" onclick="$('input[name*=\'selected\']').prop('checked', this.checked);" />
</h4>
<button class="btn btn-danger" action=" ">Delete</button>
<div class="col">
{% if i.placename == j.gallery_place %}
<div class="show-image">
<img src="{{j.gallery_image.url}}" style="height:130px;
width:130px;" />
<tag class="one" style="margin:8%">
<div class="form-checkbox"><input type="checkbox" name="checkboxes" value="{{ j.pk }}">
</tag>
</div>
{% endif %}
</div>
{% endfor %}
Finally, hook up the urls.
# urls.py
from django.conf.urls import include, url
from.views import MyView, MyListView
urlpatterns = [
url(r'^listdelete/$', MyView.as_view(), name="delete-list"),
url(r'^mylist/$, MyListView.as_view(), name="someurl"),
]
i am trying to implement the datepicker using the django bootstrap datepicker widget, but the datepicker is not showing on the webpage ("welcome.html)
i have passed the form to the views and called the form in the webpage
any help will be appreciated
forms.py
class DateForm(forms.Form):
todo = forms.CharField(
widget=forms.TextInput(attrs={"class":"form-control"}))
date_1=forms.DateField(widget=DatePicker(
options={"format": "mm/dd/yyyy",
"autoclose": True }))
def cleandate(self):
c_date=self.cleaned_data['date_1']
if c_date < datetime.date.today():
raise ValidationError(_('date entered has passed'))
elif c_date > datetime.date.today():
return date_1
def itamdate(self):
date_check=calendar.setfirstweekday(calendar.SUNDAY)
if c_date:
if date_1==date_check:
pass
elif date_1!=date_check:
raise ValidationError('The Market will not hold today')
for days in list(range(0,32)):
for months in list(range(0,13)):
for years in list(range(2005,2108)):
continue
views.py
def imarket(request):
#CREATES A FORM INSTANCE AND POPULATES USING DATE ENTERED BY THE USER
if request.method=='POST':
form = DateForm(request.POST or None)
#checks validity of the form
if form.is_valid():
itamdate=form.cleaned_data['date_1']
return HttpResponseRedirect(reverse('welcome.html'))
return render(request, 'welcome.html', {'form':form})
welcome.html
{% extends 'base.html' %}
{% load bootstrap %}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script src="//cdn.bootcss.com/bootstrap-datetimepicker/4.17.44/js/bootstrap-datetimepicker.min.js"></script>
{% block content %}
<title>welcome</title>
<form action = "{% url "imarket"}" method = "POST" role="form">
{% csrf_token %}
<table>
{{form|bootstrap_horizontal}}
</table>
<div class = "form-group">
<input type ="submit" value= "CHECK" class="form control"/>
</div>
</form>
{% endblock %}
The bootstrap datepicker wasn't working , so i added the jquery datepicker to directly to my forms. py using this answer
my updated forms.py
class DateForm(forms.Form):
todo = forms.CharField(
widget=forms.TextInput(attrs={"class":"form-control"}))
date_1=forms.DateField(widget=forms.DateInput(attrs={'class':'datepicker'}))
my updated welcome.html
{% extends 'base.html' %}
{% load bootstrap %}
{% block content %}
<title>welcome</title>
<form action = "{% url "imarket"}" method = "POST" role="form">
{% csrf_token %}
<table>
{{form|bootstrap}}
<script>
$(document).ready(function() {
$('.datepicker').datepicker();
});
</script>
</table>
<div class = "form-group">
<input type ="submit" value= "CHECK" class="form control"/>
</div>
</form>
{% endblock %}
datepicker should be initialized in the html page.
if you are using bootstrap download datepicker from Datetimepicker for Bootstrap 4
then
in the head section include
font awesome css
boostrap4 css
bootstrap-datetimepicker.min.css
in the body section include
moment.min.js
bootstrap.min.js
bootstrap-datetimepicker.min.js
define your form
from django import forms
class DateRangeForm(forms.Form):
start_date = forms.DateTimeField(required=True)
end_date = forms.DateTimeField(required=True)
in the template render the form
<form action="/your-name/" method="post">
{% csrf_token %}
{{ dt_range_form }}
<input class="btn btn-primary btn-sm" type="submit" value="Refresh">
</form>
in the script section add
$("#id_start_date").datetimepicker();
And here you have your datetimepicker! For me Time icon is still not showing up! Need to debug it.
I'm making a workout calendar website where a user can add workouts with varying amounts of lift, sets and reps, etc. Thus, I need a form that adds a field when a user clicks a button. I've made a template and some javascript to describe what it is I want to achieve exactly:
url:
url(r'^add/(?P<year>[0-9]+)/(?P<month>[0-9]+)/(?P<day>[0-9]+)/$', views.add_workout, name = 'add_workout')
template:
{% block hidden %}
{% include "workoutcal/liftrow.html" %} {# To be used by Javascript #}
{% include "workoutcal/cardiorow.html" %}
{% endblock %}
<form action="{% url 'add_workout' date.year date.month date.day %}" method="post">
<div class="row">
<div class="col-xs-2">
<p id="date">{{ date.year }}-{{ date.month }}-{{ date.day }}</p>
<input type="hidden" name="date" value="{{ date }}">
</div>
</div>
<h2 class="col-xs-12">Lifts</h2>
<div id="liftrows">
{% for i in range %}
{% include "workoutcal/liftrow.html" %}
{% endblock %}
</div>
<div class="row">
<div class="col-xs-0"></div>
<label class="col-xs-2"><button type="button" id="addliftbutton">One more lift</button></label>
</div>
<h2 class="col-xs-12">Cardio</h2>
<div id="cardiorows">
{% include "workoutcal/cardiorow.html" %}
</div>
<div class="row">
<label class="col-xs-2"><button type="button" id="addcardiobutton">One more cardio</button></label>
</div>
<div class="row">
<div class="col-xs-10"></div>
<label class="col-xs-2"><input type="submit" id="submitbutton" value="Save Workout"></label>
</div>
</form>
javascript:
//Adding onclick to buttons
document.getElementById('addliftbutton').onclick = addLiftRow;
document.getElementById('addcardiobutton').onclick = addCardioRow;
for (var i=0; i<setsBoxes.length; i++){
setsBox = setsBoxes[i];
setsBox.onchange = insertRepFields;
}
function addLiftRow(){
var liftRowElements = document.getElementById('liftrows');
var hidden_liftrow = document.getElementById('hidden').getElementsByClassName('lift')[0];
var new_liftrow = hidden_liftrow.cloneNode(true);
liftRowElements.appendChild(new_liftrow);
}
function addCardioRow(){
var cardiorows = document.getElementById('cardiorows');
var hidden_cardiorow = document.getElementById('hidden').getElementsByClassName('cardio')[0];
var new_cardiorow = hidden_cardiorow.cloneNode(true);
cardiorows.appendChild(new_cardiorow);
}
function insertRepFields(){} // big function that inserts as many input fields as the number inside the box whose event called the function.
2 questions:
1. Is there a better way to do this in Django?
2. If this is the best way, how do I go about sending the data of my massive form back to django? Since I don't know exactly how many fields there will be, I don't know how to create a form that accepts a variable amount of fields, and fields within fields.
Here's how a filled-in form could look:
The best way to accomplish that is inserting inputs with the same name and then in Django get all those inputs as a list like:
def view(request):
inputs = request.POST.getlist('your_input_name')
for i in inputs:
Model.objects.create() # Save your model
I've built dynamic forms using django formsets and javascript, but unfortunately on submitting the form only the first form is submitted. I'd like all dynamically added forms to be submitted also. Any help would be appreciated.
Views:
def routestepinfo(request):
class RequiredFormSet(BaseFormSet):
def __init__(self, *args, **kwargs):
super(RequiredFormSet, self).__init__(*args, **kwargs)
for form in self.forms:
form.empty_permitted = False
RouteStepFormSet = formset_factory(RouteStepForm, formset=RequiredFormSet, extra=1, can_order=False, can_delete=True)
if request.method == 'POST':
formset = RouteStepFormSet(request.POST)
if formset.is_valid():
for form in formset.forms:
form.save()
print 'apple'
return redirect("/buildpage/")
else:
formset = RouteStepFormSet()
return render(request, "buildpage/routestepinfo.html", {'formset' :formset})
HTML
<form id= "myForm" method = 'POST' action="{% url 'buildpage:routestepinfo' %}" enctype="multipart/form-data">{% csrf_token %}
{{ formset.management_form }}
<div id="form_set">
{% for form in formset %}
<table class='no_error'>
<tbody>.
{{form.as_table}}
</tbody>
</table>
{% endfor %}
</div>
<p><input type = "button" value = "Add another step" id = "add_more" ></p>
<div id="empty_form" style="display:none">
<table class='no_error'>
{{ formset.empty_form.as_table }}
</table>
</div>
<div id="forms"></div>
<p> </p>
<p> </p>
<input type = "submit" name = "Submit Steps">
</form>
JS Clone:
<script>
$('#add_more').click(function() {
var form_idx = $('#id_form-TOTAL_FORMS').val();
$('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
$('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1);
});
</script>
Fixed it ! Only took a week. Here's how it worked eventually. Views are largely unmodified, just added commit=False to save the list.
def routestepinfo(request, slug=None):
RouteStepFormSet = formset_factory(RouteStepForm, formset = RequiredFormSet, extra=1)
if request.method == 'POST':
formset = RouteStepFormSet(request.POST)
print formset
if formset.is_valid():
for form in formset.forms:
form_item = form.save(commit=False)
print form
form_item.save()
messages.success(request, "Record created")
return redirect ("/buildpage/")
else:
formset = RouteStepFormSet()
return render(request, "buildpage/routestepinfo.html",{'formset':formset})
Javascript was the main thing that changed, with quite a few additions and quite a bit of SO help. The prefix was the first issue, and that was fixed by using formset.empty_form and modifying it from there. Another vital part was updating the total forms, which fixed the saving issue.
<script>
$(document).ready(function() {
$('.add-item').click(function(ev) {
ev.preventDefault();
var count = $('#items-form-container').children().length;
var tmplMarkup = $('#item-template').html();
var compiledTmpl = tmplMarkup.replace(/__prefix__/g, count);
$('div#items-form-container').append(compiledTmpl);
// update form count
$('#id_form-TOTAL_FORMS').attr('value', count+1);
$('html, body').animate({
scrollTop: $("#add-item-button").position().top-200
}, 800);
});
});
</script>
Finally the html. This combined some of my own stuff with a very helpful SO post(forgot the question it came from), where formset is generated as an empty form and cloned from there.:
<div type="text/html" id="item-template">
<table>
{{ formset.empty_form.as_table }}
</table>
</div>
<font face = Flexo>
<form id= "myForm" method = 'POST' action="{% url 'buildpage:routestepinfo' %}" enctype="multipart/form-data">{% csrf_token %}
{{ formset.management_form }}
<div id="items-form-container">
{% for form in formset.forms %}
<div id="item-{{ forloop.counter0 }}">
<table>
{{form.as_table}}
<table>
</div>
{% endfor %}
</div>
Add Step
<input type = "submit" name = "Submit Steps">
</form>
Hope this helps some people. Cheers
This question already has answers here:
django MultiValueDictKeyError error, how do I deal with it
(9 answers)
Closed 8 years ago.
After trawling the internet for hours trying to no avail, I've come here in hope that maybe somebody can steer me in the correct direction.
So I'm new to django and stuck trying to use ajax in a template to pass data to a view. I have drop down menus that are populated from a database and when the user selects the type of result and model, I'm just trying to get it to pass these values to the view method. The reason why I'm doing this is because the view page populates the template (using extends), by generating an html page via a perl script that accepts these variables (result, model).
view.py
def platform_pass_rate(request):
#some other stuff
#This is currently always true
if request.method == 'GET':
#It is an issue however, because this never gets anything, just as request.GET.items() returns nothing
resultVar = request.GET['resultValue']
# modelVar = request.POST['selectedModelValue']
subprocess.call(["perl", "static/static/perl/passRateByPlatform.pl", resultVar, "Ahmed_00"])
#This calls the perl script. Currently set up so that just a default result is entered - so I now GET is working
else:
subprocess.call(["perl", "static/static/perl/passRateByPlatform.pl", "liftforce", "Ahmed_25"])
#Default html page created by script when user does not select anything
current_url = get_full_path(request)
return render_to_response("data_form_platform.html", {'our_url': current_url, 'study_models': study_models,'study_results': study_results})
urls.py
from django.conf.urls import patterns, include, url
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('AppFalconV1.views',
# Examples:
url(r'^$', 'home'),
url(r'^Pass_Rate_by_Build/$', 'build_pass_rate'),
url(r'^Pass_Rate_by_Platform/$', 'platform_pass_rate'),
url(r'^Platform_Coverage/$', 'platform_coverage'),
url(r'^Regression_Coverage/$', 'regression_coverage'),
url(r'^Coverage_All_Builds/$', 'coverage_all_builds'),
# url(r'^test/$', 'get_current_url'),
url(r'^time/$', 'current_datetime'),
#url(r'^time/plus/(\d{1,2})/$', 'hours_ahead'),
url(r'^admin/', include(admin.site.urls)),
)
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL,
document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
Revised script in base.html
<script type="text/javascript">
$(document).ready(function () {
{# $.ajaxSetup({ cache: false });#}
var current_url = $('#current_url').text();
var id = current_url.trim();
$('#' + id).addClass('active');
$('#platform_data_form_button').click(function () {
var selectedResultValue = $('#platform_type_of_result :selected').text();
console.log(selectedResultValue);
var selectedModelValue = $('#platform_models :selected').text();
console.log(selectedModelValue);
$('#platform_type_of_result').change(function () {
var selectedResultValue = $('#platform_type_of_result :selected').text();
console.log(selectedResultValue);
});
$('#platform_models').change(function () {
var selectedModelValue = $('#platform_models :selected').text();
console.log(selectedModelValue);
});
$.get("/Pass_Rate_by_Platform/", { resultValue: selectedResultValue, modelValue: selectedModelValue}, function (response) {
console.log("workinggggggg");
//alert(response);
});
});
});
</script>
Location of dropdown buttons - data_form_platform.html
{% extends 'platform_pass_rate.html' %}
{% block data_form_platform_content %}
<form class="form-horizontal">
<fieldset>
<div class="form-group">
<label class="col-md-2 control-label" for="type_of_result">Type of result</label>
<div class="col-md-3">
<select id="platform_type_of_result" name="type_of_result" class="form-control">
{% for result in study_results %}
{% if result != "testid" and result != "studyid"%}
<option value="{{ result }}">{{ result }}</option>
{% endif %}
{% endfor %}
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="model">Model</label>
<div class="col-md-3">
<select id="platform_models" name="model" class="form-control">
{% for model in study_models %}
<option value="{{ model }}">{{ model }}</option>
{% endfor %}
</select>
</div>
<label class=" control-label" for="model"></label>
<div class="col-md-1" style="margin-left: -20px" id="platform_data_form_button">
<a href="" class="btn btn-primary btn-success" ></span> Confirm</a>
</div>
</div>
</fieldset>
</form>
{% endblock %}
This just seems to be a problem with your Javascript. You're getting the value for selectedResultValue when the page is first loaded, presumably when no value is selected. The Ajax request is made when the button is clicked, but you don't fetch the new value inside that click function: so you still use the old, empty value. Just move that line inside the function.