Django get specific QuerySet with GET ajax Call on button click - django

i have a problem and i dont know if im using the good way to solve it , but their is the problem , i have a client list that i show on the client page , by getting all client with a simple
clients = client.objects.all()
so all client can have a lot of sessions, and session have a lot of clients, its like a ManytoMany relation, so what im trynna do its to show the assigned session of client one by one by clicking on a button (the button open a boostrap modal ) , so i tried to send the id of the the chosen client on click and send it into a django view with ajax GET method, and take this ID directly to find all sessions related with this client and return the query to this page , so the ajax is working correctly and i can send the id , but its like the view its not sending anything . so their is my code hope you can help me :
Html (the div im inserting on the forloop client) :
<div class="list-group list-group-me">
<ul class="list-group list-group-horizontal">
<li class="list-group-item">{{ client.name }}</li>
<li class="list-group-item">{{ client.email }}</li>
<li class="list-group-item">{{ client.created_at | date:" M Y" }}</li>
<li class="list-group-item list-group-item-success">Active</li>
<li class="list-group-item">025f55azg5</li>
<li><div class="btn-group">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" id="AddSession"
data-id="{{ client.id }}">
Add
</button>
<button type="button" class="btn btn-primary" data-id="{{ client.id }}" >View</button>
</div>
</li>
</ul>
</div>
the view (tryin the .all() just to see if its working) :
class show_session(View):
def get(self, request , id):
Sclient = session.objects.all()
#Sclient = session.objects.filter(client__id=id)
context = { 'Sclient': Sclient }
return render(request, 'coach/addclient.html', { 'Sclient': Sclient })
the model.py :
class session(models.Model):
name = models.CharField(max_length=80)
client = models.ManyToManyField(client, blank=True)
coach = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
created_at = models.DateTimeField(auto_now_add=True)
detail = models.CharField(max_length=256)
def __str__(self):
return self.name
the main view of the page :
def addclient(request):
form = ClientForm
clients = client.objects.filter(affiliation=request.user.id)
Csession = session.objects.filter(coach=request.user.id)
context = {'form': form ,'clients': clients , 'Csession' : Csession}
form = ClientForm()
if request.method == 'POST':
form = ClientForm(request.POST)
print(form)
if form.is_valid():
print('adding client 1133', form)
name = request.POST.get('name')
email = request.POST.get('email')
new_client = client.objects.create(name= name, email=email , affiliation=request.user)
new_client.save()
return JsonResponse({'client': model_to_dict(new_client)}, status=200)
else:
print('not adding client to the form 1333')
return redirect('addclient')
return render(request, 'coach/addclient.html', context= context)
and the ajax function :
$("#AddSession").click(function(){
var dataID = $(this).data('id');
console.log(dataID)
$.ajax({
url:'addclient/'+ dataID +'/added',
data: {
csrfmiddlewaretoken: csrfToken,
id: dataID
},
type : "get",
success: function(response) {
console.log("hey hey session over here");
}
})
});
i dont know if can use just the main view to get the data and display it , and when i try to acess the url of show_session.view , the query set is working but im still tryin to display it on the addclient url
thanks for your time and help !

so i have fixed the problem , i have just used a POST method to send the id of current user to the view then i used the action data attribute to handle multiple post on my view and use the id given by ajax to have the correct queryset and serialized the queryset into a JSON object so ajax can add the session assiciated with the choosen client on click their is the code :
View :
if request.method == 'POST' and request.POST['action'] == 'session':
print("session response")
id = request.POST.get('id')
print(id)
#Sclient = list(session.objects.filter(coach=request.user.id))
Sclient = session.objects.filter(client__id=id)
SerializedQuery = serializers.serialize('json', Sclient)
return JsonResponse(SerializedQuery, safe=False)
Ajax :
$("#AddSession").click(function(){
var dataID = $(this).data('id');
$.ajax({
url: $(this).data('url'),
data: {
csrfmiddlewaretoken: csrfToken,
id: dataID,
action: 'session',
//dataType:"json"
},
type : "post",
success: function(response) {
console.log("hey hey session over here");
console.log(response)
var obj = jQuery.parseJSON(response)
//console.log(obj[1].fields.name)
var Sarray = [];
var Selector = $("#assigned");
var count = $("#assigned span")
console.log(count.length)
//used to limit the number of element on div on first click
if(count.length < obj.length)
{
for (i = 0 ; i < obj.length ; i++) {
// console.log(obj[i].fields.name)
Sarray.push(obj[i].fields.name)
Selector.append('<span class="badge badge-success">'+ obj[i].fields.name +' x </span>')
}
console.log("yoow",Sarray.length)
}
}
})
});

Related

Add new object to list without refreshing with Django & Ajax

I'm searching for someone who helps me in a Django project with JS, Ajax and jquery.
I'm trying to create something like adding objects on the django-admin page. I used https://www.pluralsight.com/guides/work-with-ajax-django, and almost everything is working fine but...
On my form, I have multiple choice field with authors, when I pressed the button to add a new author, the object is properly saving in DB, but on the form, I can't see a new object. When I reload the page, the new object is on this multiple choice field.
I thought I should refresh the field to see a new object on the list, but I don't know it's the proper way to meet this goal.
[edit]
models.py
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
book_author = models.ManyToManyField(Author,blank=True,)
...
form.py
class AuthorForm(forms.ModelForm):
class Meta:
model = Author
fields = ['name', ]
widgets = {
'name': forms.TextInput(),
}
views.py
I added class SaveAutor
def author_add_view(request):
form = AuthorForm()
return render(request,
"author/custom_create_author.html",
{"form": form})
class SaveAuthor(View):
template_name = "author/custom_create_author.html"
def get(self, request):
author_form = AuthorForm(request)
return render(request,
self.template_name,
{'form': author_form})
def post(self, request):
#assume authorForm has author_name defined
author_form = AuthorForm(data=request.POST)
if author_form.is_valid():
author = Author() #here is class name or form name?
author.name = author_form.cleaned_data['name']
author.save()
return JsonResponse({'author_id': author.id,
'author_name': author.name})
# error response or whatever you want to return
return JsonResponse({'error': 'author form is not valid'})
I had these views registered in urls.py
urls.py
# add an author
path('author/add/', views.author_add_view,
name='author_add'),
# not sure if I should add as_view() at the end
path('author/new-add/', views.SaveAuthor.as_view(),
name='new_author_add'),
When I try check if page with form is displaying properly using the SaveAuthor class based view I get error 'WSGIRequest' object has no attribute 'get', but when I use the author_add_view I got the template.
custom_create_author.html
$("#author-form").submit(function (e) {
// preventing from page reload and default actions
e.preventDefault();
// serialize the data for sending the form data.
var serializedData = $(this).serialize();
// make POST ajax call
$.ajax({
type: 'POST',
url: "{% url '.' %}", //serializer_ajax_mehit_from_vies
data: serializedData,
success: function (response) {
// on successfull creating object
// 1. clear the form.
$("#author-form").trigger('reset');
// 2. focus to nickname input
$("#id_author_name").focus();
},
error: function (response) {
// alert the error if any error occured
alert(response["responseJSON"]["error"]);
}
})
})
{% load static %}
{% load widget_tweaks %}
{% block content %}
<h4>
My author
</h4>
<form id="author-form">
{% csrf_token %}
<p>{{ form.as_p }}</p>
<button class="btn btn-outline-success" type="submit">save</button>
</form>
<br>
{% endblock %}
Here is another page where I'm trying to connect the book with multiple-choice-field author (it's typical form, but I'm enclosing only the button to pop-up the form, where I can add the new author)
add_book.html js code open pop-up windows to create new author
<script type="text/javascript">
$(function () {
$("#create-author").modalForm({
formURL: "{% url 'author_add' %}"
});
})
</script>
<button id="create-author" class="btn btn-primary" type="button" name="button">
<span class="fa fa-plus"/>
</button>
And on this page, I tried to paste your JS code
<script type="text/javascript">
// assume the add author button has an id of add_author_button
$('#create-author').click(function(event){
event.preventDefault();
// assume the text field has an id of author_name
author_name= $('#author_name').val();
create_post(event, author_name);
}
) //<-------- this closing bracket was missing?
function create_post(event, author_name) {
$.ajax({
url: "{% url '.' %}", // the endpoint I'll precise that in comment
type: "POST", // http method
data: {
author_name: author_name,
csrfmiddlewaretoken: $('[name="csrfmiddlewaretoken"]').val()
},
// handle a successful response - data will be a json object returned from your view method
success: function (data) {
if (data.error === null) {
// assume your author multiple choice select has an id of author_sel
// this will append the new author name to the list and will also
// set the value for this author to be the newly created id so you can
// perform other functions on the author like update and/or delete
$('#author_id').append($('<option/>', {
value: data.author_id,
text: data.author_name,
}));
} else {
// display the error on the page
// and/or write it to the console log
console.log(data.error);
}
},
// handle a non-successful http response
error: function (xhr, errmsg, err) {
// display the error on the page
// and/or write it to the console log
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
}
</script>
One closing bracket was missing, so I added in on the JS script.
I had a problem with the endpoint, when I pass the class-based view SaveAuthor(View) (new_author_add by url name) I got the message: the author form is not valid, but when I used author_add_view (author_add by url name) undefined.
The issue is that while you are using AJAX to submit your new author, the author isn't being added to the author's multiple choice field in the current HTML page. Refreshing the page will retrieve the new value but that also does an entire post/refresh loop. Since you are submitting the post using AJAX, you can return the new author's id and name via a JsonResponse and use jQuery to add it to the author's multiple choice field.
views.py
from MyApp.forms import AuthorForm
from MyApp.models import Author
from django.shortcuts import render
from django.views import View
from django.http.response import JsonResponse
class SaveAuthor(View):
template_name = "author/author.html"
def get(self, request):
author_form = AuthorForm()
return render(request,
self.template_name,
{"form": author_form,
"authors":Author.objects.all()})
def post(self, request):
#assume authorForm has author_name defined
author_form = AuthorForm(data=request.POST)
if author_form.is_valid():
author = Author() #here is class name or form name?
author.name = author_form.cleaned_data['name']
author.save()
return JsonResponse({'author_id': author.id,
'author_name': author.name})
# error response or whatever you want to return
return JsonResponse({'error': 'author form is not valid'})Your AJAX
author.html
<!DOCTYPE html>
{% load static %}
<script src="{% static "jquery-3.4.1.min.js" %}"></script>
{% block content %}
<h4>
My author
</h4>
<select id="author_sel" name="author_sel" size="5" class="selectbox">
{% for author in authors %}
<option value="{{author.id}}">{{author.name|capfirst}}</option>
{% endfor %}
</select>
<form id="author-form">
{% csrf_token %}
<p>{{ form.as_p }}</p>
<input type="button" name="button" class="submit_button" id="add_author_button" value="Save">
</form>
<br>
{% endblock %}
<script type="text/javascript">
// assume the add author button has an id of add_author_button
$('#add_author_button').click(function(event){
event.preventDefault();
// assume the text field has an id of author_name
author_name= $('#id_name').val();
create_post(event, author_name);
}) //<-------- this closing bracket was missing?
function create_post(event, author_name) {
$.ajax({
url: ".", // the endpoint I'll precise that in comment
type: "POST", // http method
data: {
name: author_name,
csrfmiddlewaretoken: $('[name="csrfmiddlewaretoken"]').val()
},
// handle a successful response - data will be a json object returned from your view method
success: function (data) {
if (data.error === undefined) {
// assume your author multiple choice select has an id of author_sel
// this will append the new author name to the list and will also
// set the value for this author to be the newly created id so you can
// perform other functions on the author like update and/or delete
$('#author_sel').append($('<option/>', {
value: data.author_id,
text: data.author_name,
}));
} else {
// display the error on the page
// and/or write it to the console log
console.log(data.error);
}
},
// handle a non-successful http response
error: function (xhr, errmsg, err) {
// display the error on the page
// and/or write it to the console log
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
}
</script>
urls.py
from django.urls import path
from . import views
app_name = 'myapp'
urlpatterns = [
# add an author
path('add/', views.SaveAuthor.as_view(), name='author_add'),
]
forms.py
from django import forms
from MyApp.models import Author
class AuthorForm(forms.ModelForm):
class Meta:
model = Author
fields = ['name', ]
widgets = {
'name': forms.TextInput(),
}
models.py
from django.db import models
# Create your models here.
class Author(models.Model):
name = models.CharField(max_length=100)
This is now a complete working example.

Djnago post "like" functionality issue

I built posts "like" functionality in posts list page (where posts of a single user are displayed). Using examples form the book "Django by examples", I did ajax like button bellow every post. But it works incorrectly. In that example like button was made for single post page, and I tried to fit it for posts list page (many post in one page). When push the like button in the database everything is fine - I got plus one like for particular post. But in the front end stange things happen - likes number for all the posts is changing, as if all the posts are connected. And when I do Like and unlike, numbers of likes for all the post are changing to some big values. I think that happens becouse in this case Ajax uses the same class selector (instead of id) for all posts. I'm still not so good at Django and Ajax and can't find a way to make this work correctly. A spent long time of triying to fix this and in googling with no result. Any help appriciated.
Bellow is the code.
The post's model with the likes fields:
class Posts(models.Model):
author = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True, blank=True)
content = models.TextField()
image = models.ImageField(upload_to="posts/%Y/%m/%d", null=True,blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
users_like = models.ManyToManyField(settings.AUTH_USER_MODEL,
related_name='images_liked',
blank=True)
total_likes = models.PositiveIntegerField(db_index=True,
default=0)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("post_detail", kwargs={"slug": self.slug})
def slug_generator(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
pre_save.connect(slug_generator, sender=Posts)
The post_like function in user's view.py:
#ajax_required
#login_required
#require_POST
def post_like(request):
post_id = request.POST.get('id')
action = request.POST.get('action')
if post_id and action:
try:
post = Posts.objects.get(id=post_id)
if action == 'like':
post.users_like.add(request.user)
create_action(request.user, 'likes', post)
else:
post.users_like.remove(request.user)
return JsonResponse({'status':'ok'})
except:
pass
return JsonResponse({'status':'ok'})
The code in urls.py for this:
urlpatterns = [
path('like/', views.post_like, name='like'),
...another urls...
]
The html for like button and counting likes:
{% with total_likes=post.users_like.count users_like=post.users_like.all %}
<div class="image-info">
<div>
<span class="count">
<span class="total">{{ total_likes }}</span>
like{{ total_likes|pluralize }}
</span>
<a href="#" data-id="{{ post.id }}" data-action="{% if request.user in users_like %}un{% endif %}like" class="like button">
{% if request.user not in users_like %}
Like
{% else %}
Unlike
{% endif %}
</a>
</div>
</div>
<div class="image-likes">
</div>
{% endwith %}
And in the same html file, where button is, in the bottom of it is the ajax code for likes functionality:
{% block domready %}
$('a.like').click(function(e){
e.preventDefault();
$.post('/like/',
{
id: $(this).data('id'),
action: $(this).data('action')
},
function(data){
if (data['status'] == 'ok')
{
var previous_action = $('a.like').data('action');
// toggle data-action
$('a.like').data('action', previous_action == 'like' ? 'unlike' : 'like');
// toggle link text
$('a.like').text(previous_action == 'like' ? 'Unlike' : 'Like');
// update total likes
var previous_likes = parseInt($('span.count .total').text());
$('span.count .total').text(previous_action == 'like' ? previous_likes + 2 : previous_likes - 2);
}
}
);
});
{% endblock %}
You'll only want to modify the like button that has been clicked by getting it inside your click function. You could tidy up your code a bit, but to keep it similar you could do something like:
$('a.like').click(function(e){
e.preventDefault();
// Get the clicked button.
const $clickedButton = $( this );
$.post('/like/',
{
id: $clickedButton.data('id'),
action: $clickedButton.data('action')
},
function(data) {
if (data['status'] == 'ok') {
// Update the clicked button only.
var previous_action = $clickedButton.data('action');
// toggle data-action
$clickedButton.data('action', previous_action == 'like' ? 'unlike' : 'like');
// toggle link text
$clickedButton.text(previous_action == 'like' ? 'Unlike' : 'Like');
// update total likes
const $total = $clickedButton.prev('span.count').children('.total');
var previous_likes = parseInt($total.text());
$total.text(previous_action == 'like' ? previous_likes + 2 : previous_likes - 2);
}
}
);
});
I'm not 100% sure why you're adding/subtracting 2 from the total rather than 1, but I don't have enough context.

How to use Ajax "like" button on Django posts list

I created my first site with Django and I'm trying to make the Ajax "like" button work on the listing posts page, but I have to reload the page to have +1.
My views:
def likes_post(request):
post_id = None
if request.method == 'GET':
post_id = request.GET['post_id']
like = 0
if post_id:
post = Post.objects.get(id = int(post_id))
if post:
like = post.likes + 1
post.likes = like
post.save()
return HttpResponse(like)
My HTML template:
{% for post in posts %}
<div class="post-favourite">
J'aime <i class="fa fa-heart-o likes_count"aria-hidden="true"> {{ post.likes }}</i>
</div>
{% endfor %}
and the Ajax function:
<script type="text/javascript">
$('.like').click(function(){
var ps_id;
ps_id = $(this).attr("data-posts-id");
$.get('/likes_post/', {post_id: ps_id}, function(data){
$(this).prev().find('.like_count').html(data);
});
});
</script>
The Ajax button for the post detail page works by simply replacing the last line with
$('.like_count').html(data);
in your views.py, you should send back data to jquery with JsonResponse
from django.http import JsonResponse
def likes_post(request):
post_id = None
if request.method == 'GET':
post_id = request.GET['post_id']
like = 0
if post_id:
post = Post.objects.get(id = int(post_id))
if post:
like = post.likes + 1
post.likes = like
post.save()
return JsonResponse({'like':like})
and then in your jquery:
<script type="text/javascript">
$('.like').click(function(){
var ps_id;
ps_id = $(this).attr("data-posts-id");
$.ajax({
url: '/likes_post/',
method: 'GET',
data: {
'post_id': ps_id,
},
success: function(data){
$(this).prev().find('.like_count').html(data);
$(this).html(data);
}
});
});
</script>
whatever you send with JsonResponse is accessible in success part of jquery. in this example the like we send is data in success part.
in success part you can write data in your html code

Django form saving in database and send email with formspree.io

I'm looking for set up a ticket service for my company and I am getting a little problem between my Django form and Formspree.io.
Users create a ticket with my Django form. Then, their tickets are storaged in my database and my application send an email to support#mycompany.fr with Formspree.
When I click on submit button, the mail is well send to my email address but data are not saved in my database. Up to now I don't find a way to do this process ...
My models looks like :
class Ticket(models.Model):
Etat = models.CharField(max_length = 30, choices = CHOIX_ETAT_TICKET, verbose_name="Etat du ticket")
Nom = models.CharField(max_length=40, verbose_name="Nom du createur")
Prenom = models.CharField(max_length=40, verbose_name="Prenom du createur")
Telephone = models.CharField(max_length=20, verbose_name='Téléphone')
Mail = models.CharField(max_length=40, verbose_name='Email')
Objet = models.CharField(max_length=60, verbose_name='Objet du ticket')
Description = models.CharField(max_length=250, verbose_name='Description du ticket')
Creation = models.DateTimeField(auto_now_add=True)
Utilisateur = models.CharField(max_length=100, verbose_name="Utilisateur")
My form looks like this :
class TicketFormulaire(forms.ModelForm):
Utilisateur = forms.CharField(widget=forms.HiddenInput())
Etat = forms.CharField(widget=forms.HiddenInput())
class Meta :
model = Ticket
fields = ["Etat", "Nom", "Prenom", "Telephone", "Mail", "Objet", "Description", "Utilisateur"]
My view looks like this :
#login_required
def Identity_Ticket(request) :
if request.method == 'POST':
form = TicketFormulaire(request.POST or None)
if form.is_valid() : # Vérification sur la validité des données
post = form.save()
messages.success(request, 'Le formulaire a été enregistré !')
#return HttpResponseRedirect(reverse('Home'))
else:
messages.error(request, "Le formulaire est invalide !")
else:
form = TicketFormulaire()
form.fields['Utilisateur'].initial = request.user.last_name + " " + request.user.first_name
form.fields['Etat'].initial = 'En attente'
return render(request, 'Identity_Societe_Ticket.html', {"form" : form, })
And finally my html template :
<h4 class="subtitle"><b> <span class="glyphicon glyphicon-user"></span></span> Création d'un nouveau ticket</b></h4>
<form autocomplete="off" class = "form" method='POST' action='https://formspree.io/support#mycompany.fr'> {% csrf_token %} <br></br>
{{ form.as_p}}
<br></br>
<input type="submit" value="Enregistrer le ticket" onclick="return confirm('Valider le formulaire ?')" />
</form>
Do you have a solution in order to save data in my database in first time, then send the email ?
Any help could be appreciate ;)
______________
UPDATE :
______________
My HTML file looks like :
<h4 class="subtitle"><b> <span class="glyphicon glyphicon-user"></span></span> New ticket</b></h4>
<form autocomplete="off" class = "form" method='POST' action='' enctype="multipart/form-data"> {% csrf_token %} <br></br>
{{ form.as_p}}
<br></br>
<input type="submit" onclick="return confirm('Confirm the ticket ?')" />
</form>
<script>
var $TicketForm = $('#someid');
$TicketForm.submit(function(e) {
e.preventDefault();
$.ajax({
url: '//formspree.io/support#mycompany.fr',
method: 'POST',
data: $(this).serialize(),
dataType: 'json',
beforeSend: function() {
$TicketForm.append('<div class="alert alert--loading">Envoi du ticket en cours</div>');
},
success: function(data) {
$TicketForm.find('.alert--loading').hide();
$TicketForm.append('<div class="alert alert--success">Le ticket a été envoyé ! </div>');
},
error: function(err) {
$TicketForm.find('.alert--loading').hide();
$TicketForm.append('<div class="alert alert--error">Il semble y avoir une erreur</div>');
}
});
});
</script>
If I don't add id="someid" in <form>, data are saved in my DB and email is not send, but if I write id="someid", email is send but none data is saved in my database ... The issue is there ...
Well you have given the action='https://formspree.io/support#mycompany.fr'
parameter in form, so that your form is submitting to formspree.io site. Rather than doing that submit your form with your app function URL and do the formspree.io processing in django views after the form is saved.
Edit:
I do not know about the formspee.io but i understood your query,
one way you can do it by using ajax,
change to
<button type="button" id="someid">
instead of
<input type="submit" />
$("#someid").on("click", function() {
$.ajax({
url: "//formspree.io/youremail#gmail.com",
method: "POST",
data: {message: "hello!","extradatagoeshere":""},
dataType: "json",
success:function(data)
{
// now submit your actual form to db by form.submit();
}
});
});
Or use python request library to post data after the view function logic of form save ,
import requests
url = 'https://formspree.io/support#mycompany.fr'
data = {"yourdata":"data"} # pass a whole bunch of dict which needed to be send in data
requests.post(url, data=data)
your action is posting the data to formspree website and not to the view of your site, so you can never get the data and save it to database.
if you really want to do this, one way is use ajax to post the data to your django view on click of submit button, you can put an id in the button and check onclick an ajax will be called.
and the form will stay as it is.
hope this helps you

Django: How to upload a file using ajax

I am using django 1.5, python 2.7 and jquery 1.9. I have a form which has precisely 2 fields i.e. title and document. When I press submit I want the users chosen document to be present in the request.FILES as shown in the view.
When I submit the regular form (without ajax), this works fine, but with ajax I do not get the file field in my request. Any suggestions on how to upload a file using ajax.
HTML:
<form enctype="multipart/form-data" action="{% url 'upload_document' %}" method="post" id="uploadForm">
{% csrf_token %}
<ul>
<li>
<div>Title</div>
<input id="title" type="text" maxlength="200"/>
<div class="error"></div>
</li>
<li>
<div>Upload File</div>
<input id="document" type="file" size="15" />
<div class="error"></div>
</li>
</ul>
<input type="submit" value="submit"/></p>
</form>
FORMS.PY:
class UploadForm( forms.Form ):
document = forms.FileField()
title = forms.CharField(max_length = 200)
def clean(self):
cleaned_data = super(UploadForm, self).clean()
return cleaned_data
def save(self, *args, **kwargs):
title = self.cleaned_data['title']
doc = self.cleaned_data['document']
document = Document(title = title, document = doc)
document.save()
return document
SCRIPT:
<script type="text/javascript">
$("#uploadForm").submit(function(event){
event.preventDefault();
$.ajax({
url : "{% url 'upload_document' %}",
type: "POST",
data : {csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].value,
title: document.getElementById('title').value,
//document: document: document.getElementById('document'),
},
dataType : "json",
success: function( response ){
if(response == "True"){
// success
}
else {
//append errors
}
}
});
});
</script>
VIEWs.PY
def upload_document(request):
print request.POST
print request.FILES
if request.is_ajax():
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES, user = request.user)
if form.is_valid():
form.save()
return HttpResponse(simplejson.dumps('True'), mimetype = 'application/json' )
else:
errors = form.errors
return HttpResponse(simplejson.dumps(errors), mimetype = 'application/json' )
The answer to that question is not that simple. First of all if you intend to support old browsers then indeed it gets nasty. You have to deal with hidden iframes and some JavaScript tricks. I do advice using some well-known scripts for that like jQuery-File-Upload.
But the world is evolving and new technologies arise including HTML5. There's a new File API which is available in most modern browsers ( IE10+, FireFox3.6+, Chrome13+, see: http://caniuse.com/fileapi ) which can be used for that. First you need some HTML:
<input type="file" id="file-select" />
Then you can bind to (for example) change event:
$('#file-select').change( handleFileSelect );
and finally the handler itself:
var data = {};
function createReaderHandler(name) {
return function(ev) {
data[name] = ev.target.result;
};
}
function handleFileSelect(ev) {
var files = ev.target.files; // FileList object
// Loop through the FileList
for (var i = 0; i < files.length; i++) {
var file = files[i],
name = file.name || file.fileName,
reader = new FileReader();
reader.onload = createReaderHandler(name);
reader.readAsText(file);
}
}
Once the data is loaded into JavaScript memory (note that the operation is asynchronous) you can send it via AJAX like any other data. There are more options: depending on your file you can read it as a binary data using .readAsBinaryString and so on. Google is your friend. :)
Also I think there already are good scripts for uploading files with a fallback to old methods. This one can be interesting (haven't tried it):
http://www.plupload.com/
I think the issue is in the submit button, change it into normal button
ie, <button type='button' id='submit'>submit</button>(by default all buttons in form are submit)
and the ajax as
$('#submit').on('click',function(){
frm = $(this).parents('form')
$.ajax({
type: frm.attr('method'),
dataType:'json',
url: frm.attr('action'),
data: frm.serialize(),
async: false,
success: function (data) {
console.log('success')
},
error: function(data) {
console.log("Something went wrong!");
}
})
All others will be same
Just try it will work