How to receive and save data via ajax in django? - html

through ajax I am sending the data correctly, because the data I see through wireshak and they are correct. On the django server, he sends me the correct request "POST / solit / HTTP / 1.1" 200 52. But the value sent does not receive it, it does not reach the Mysql database and I do not understand why, if the traffic sends well the data.
In wireshak I see the data of the post request, they are the correct ones, but they are not saved in the database, when I want them to be added as if I were to update the record of such database fields and it does not , I do not understand why
this is my views.py
def solit(request):
if request.method == 'POST' and request.is_ajax():
form = addiForm(request.POST)
if form.is_valid():
peticion = form.save(commit=False)
peticion.usuario = request.user
peticion.save()
peticion.usuario.d_pendientes = form.cleaned_data.POST.get('d_pendientes')
peticion.usuario.h_pendientes = form.cleaned_data.POST.get('h_pendientes')
peticion.usuario.save()
return JsonResponse({'status': 'true', 'msg': 'Procesado Correctamente'})
form = addiForm()
return render(request, 'plantillas/adicionar.html', {'form':form})
This is my models.py------------------------------
class Usuarios(AbstractUser):
numero_empleado = models.IntegerField(null= True, blank= True)
area = models.CharField(max_length = 200, null= True, blank= True)
d_pendientes = models.IntegerField(null= True, blank= False)
h_pendientes = models.IntegerField(null= True, blank= False)
f_init = models.DateField(max_length = 200,null= True, blank= True)
init_vac = models.DateField(max_length = 200, null= True, blank= True)
fin_vac = models.DateField(max_length = 200, null= True, blank= True)
ul_vac_tomadas = models.IntegerField(null= True, blank= True)
class Peticion(models.Model):
solit_choices = (
('Adicionar','Adicionar'),
)
solicitudes_id = models.AutoField(primary_key=True)
usuario = models.ForeignKey(Usuarios, on_delete=models.CASCADE, null=True, blank=True)
petit = models.CharField(max_length = 255, choices=solit_choices, null=True, blank=False)
fec = models.DateTimeField(auto_now=True)
razon = models.TextField(max_length=255, null=True, blank=True)
periodo_init = models.DateField(max_length = 200, null=True, blank=True)
periodo_fin = models.DateField(max_length = 200, null=True, blank=True)
dias_adicion = models.IntegerField(null=True, blank=False)
horas_adicion = models.FloatField(null=True, blank=False)
this is my forms.py
class addiForm(forms.ModelForm):
class Meta:
"""Formulario de solicitud"""
model = Peticion
fields = [
'solicitudes_id',
'petit',
'razon',
'periodo_init',
'periodo_fin',
'dias_adicion',
'horas_adicion',
]
labels = {
'solicitud_id':'Solicitud',
'petit':'Tipo de PeticiĆ³n',
'razon':'Razon',
'periodo_init':'Rango de fecha inicial',
'periodo_fin':'Fecha final',
'dias_adicion':'Dias a adicionar, si es mas de 8 horas',
'horas_adicion':'Horas a adiciona, si es menos de 1 dia',
html file
{% extends "plantillas/base.html" %}
{% block content %}
{% load staticfiles %}
{% now "Y-m-d H:i:s" %} <br>
{{ user.Peti}}
{{ user.numero_empleado}}
<script src="{% static 'js/int.js'%}"></script>
<script
src="https://code.jquery.com/jquery-3.4.1.js"
integrity="sha256-WpOohJOqMqqyKL9FccASB9O0KwACQJpFTUBLTYOVvVU="
crossorigin="anonymous"></script>
<div><form method="POST" id="demo" class="form-data" action="{% url 'solit' %}">
{% csrf_token %}
<h6>Tipo de peticion:{{form.petit}}</h6>
<h6>Razon:{{form.razon}}</h6>
<h6>{{form.solicitudes_id}}</h6>
<h6>Fecha inicio:{{form.periodo_init}}</h6>
<h6>Fecha fin:{{form.periodo_fin}}</h6>
<h6>Introduzca dias a tomar<input id="dias" type="number" name="dias_adicion"></h6>
<h6>Introduzca horas a tomar<input id="horas" type="number" name="horas_adicion"></h6>
<input type="hidden" id="const_dias" name="d_pendientes" value="{{ user.d_pendientes }}">
<input type="hidden" id="const_horas" name="h_pendientes" value="{{ user.h_pendientes }}">
<button type="submit" onclick="calculo()">Guardar</button>
</div></form></span>
<h6>Recuerde, que usted dispone de {{ user.d_pendientes }} dias y {{ user.h_pendientes }} horas</h6>
js file---------------------
function calculo()
{
var dias = parseInt(document.getElementById('dias').value);
var horas = parseFloat(document.getElementById('horas').value);
var dias_base = parseInt(document.getElementById('const_dias').value);
var horas_base = parseFloat(document.getElementById('const_horas').value);
dias_base -= dias;
horas_base -= horas;
document.getElementById('const_dias').value = dias_base;
document.getElementById('const_horas').value = horas_base;
} console.log(calculo);
server django console [24/Jul/2019 15:30:47] "POST /solit/ HTTP/1.1" 200 52 and the js console msg: "Procesado Correctamente"
status: "true"
ajax script--------------------------------------------
$(document).ready(function(calculo){
var productForm = $("#demo")
productForm.submit(function(event){
event.preventDefault();
var thisForm = $(this)
var actionEndpoint = thisForm.attr("action");
var httpMethod = thisForm.attr("method");
var formData = thisForm.serialize();
$.ajax({
url: actionEndpoint,
method: httpMethod,
data: formData,
success: function(data){
console.log("success")
console.log(data)
},
error: function(erroData){
console.log("error")
console.log(erroData)
}
})
})
})

You still haven't really explained where you want the value for "usario" to come from. I'm going to assume that you want it to be the currently logged-in user. In which case, you can do this:
form = addiForm(request.POST)
if form.is_valid():
peticion = form.save(commit=False)
peticion.usuario = request.user
peticion.save()
peticion.usuario.d_pendientes = form.cleaned_data.get('d_pendientes')
peticion.usuario.h_pendientes = form.cleaned_data.get('h_pendientes')
peticion.usuario.save()
return JsonResponse({'status': 'true', 'msg': 'Procesado Correctamente'})
(Note, .get is a method, it needs parentheses not square brackets. And None is the default, you don't need to specify it explicitly.)
Edit
I'm finding it really hard to understand what you are asking, but I think your problem is that you simply don't have anything in the form called dias_adicionar or horas_adicionar; they are called d_pendientes and h_pendientes in line with your actual field names.

There isn't anything in your JavaScript code which makes an AJAX request - it's just a normal form POST request. This means request.is_ajax() will be false, and the form saving code doesn't execute.

Related

Passing a variable from python to HTML page

I have a long python function and within the function I am generating a voucher which I would want to autofill in my HTML page. Kindly assist
The full function:
def confirmation(request):
print("Start MpesaCallback")
global profile
mpesa_body = request.body.decode('utf-8')
mpesa_body = json.loads(mpesa_body)
print(mpesa_body)
print("Mpesa Body")
merchant_requestID = mpesa_body["Body"]["stkCallback"]["MerchantRequestID"]
print('merchant_requestID: ', merchant_requestID)
checkout_requestID = mpesa_body["Body"]["stkCallback"]["CheckoutRequestID"]
print('checkout_requestID: ', checkout_requestID)
result_code = mpesa_body["Body"]["stkCallback"]["ResultCode"]
print('result_code: ', result_code)
result_desc = mpesa_body["Body"]["stkCallback"]["ResultDesc"]
print('result_desc: ', result_desc)
metadata = mpesa_body["Body"]["stkCallback"]["CallbackMetadata"]["Item"]
for item in metadata:
title = item["Name"]
if title == "Amount":
amount = item["Value"]
print('Amount: ', amount)
elif title == "MpesaReceiptNumber":
mpesa_receipt_number = item["Value"]
print('Mpesa Reference No: ', mpesa_receipt_number)
elif title == "TransactionDate":
transaction_date = item["Value"]
print('Transaction date: ', transaction_date)
elif title == "PhoneNumber":
phone_number = item["Value"]
print('Phone Number: ', phone_number)
str_transaction_date = str(transaction_date)
trans_datetime = datetime.strptime(str_transaction_date, "%Y%m%d%H%M%S")
tz_trans_datetime = pytz.utc.localize(trans_datetime)
payment = MpesaPayment.objects.create(
MerchantRequestID=merchant_requestID,
CheckoutRequestID=checkout_requestID,
ResultCode=result_code,
ResultDesc=result_desc,
Amount=amount,
MpesaReceiptNumber=mpesa_receipt_number,
TransactionDate=tz_trans_datetime,
PhoneNumber=phone_number,
)
if result_code == 0:
payment.save()
print("Successfully saved")
password_length = 5
voucher = secrets.token_urlsafe(password_length)
print(voucher)
headers = {
'Content-Type': 'application/json',
'h_api_key': os.getenv("SMS_Token"),
'Accept': 'application/json'
}
payload = {
"mobile": phone_number,
"response_type": "json",
"sender_name": "23107",
"service_id": 0,
"message": "Your WiFi Voucher is " + voucher + ".\nAirRumi."
}
response = requests.request("POST", 'https://smsdomain.com/sms/sendsms', headers=headers,
json=payload)
r = response.json()
print(r)
print("SMS Sent")
print(amount)
if amount == 1:
profile = 'one_hour'
elif amount == 50:
profile = 'one_day'
elif amount == 300:
profile = 'one_week'
elif amount == 1000:
profile = 'one_month'
else:
print('Incorrect Amount')
print(profile)
connection = routeros_api.RouterOsApiPool(
host=os.getenv("ip"),
username=os.getenv("usernamee"),
password=os.getenv("password"),
port=8728,
use_ssl=False,
ssl_verify=False,
ssl_verify_hostname=True,
ssl_context=None,
plaintext_login=True
)
api = connection.get_api()
user = api.get_resource('/ip/hotspot/user')
user.add(name=voucher, server="hotspot1", password='1234', profile=profile)
print("User " + voucher + " created.")
else:
print("Payment was not successful")
context = {
"resultcode": result_code,
"resultdesc": result_desc
}
if context['resultcode'] == 0:
return JsonResponse(dict(context))
My HTML page that I want auto filled:
<form name="login" action="http://mydomain/login" method="post">
{% csrf_token %}
<input type="hidden" name="dst" value="https://www.google.com"/>
<input type="hidden" name="popup" value="true"/>
<label>
<input type="text" name="username" value="{{ voucher }}" placeholder="Enter your Voucher" required>
</label>
<label>
<input type="hidden" name="password" value="1234">
</label><br><br>
<div id="login-button"><input type="submit" value="CONNECT"/></div>
</form>
How do I get the voucher generated and auto fill it in the HTML? I have used the {{ voucher }} and its not working.
I have updated the whole function but not the whole view.py
You can use render for django.shortcuts module:
from django.shortcuts import render
def confirmation(request):
# Your code here
...
context = {
"resultcode": result_code,
"resultdesc": result_desc,
"voucher": voucher, # <- HERE
}
# Comment
# if context['resultcode'] == 0:
# return JsonResponse(dict(context))
return render(request, 'your_template.html', context=context)

Django pass data from HTML table to database model

I am creating a student attendance system using django. I am fetching all student's names from the student database into an HTML table and updating information about students to django model.
This is my view.py to get data
def attendanceFill (request, subject):
context = ''
ad_standard = request.session.get('standardO')
subjects = CustomStudent.objects.filter(className__name__contains = ad_standard, subjectName__subjects__contains = subject)
# attendanceForm = Attendance(request.POST or None, instance=subjects)
print(ad_standard)
print(subject)
print(subjects)
context = {'subjects' : subjects}
if request.method == 'POST':
student = request.POST
print(student)
return render(request, 'teacher/attendance_fill.html', context)
This is my HTML template for data handling.
<div class="container">
<div class= "row mt-4">
<form action="" method="POST">
{% csrf_token %}
<table>
{% for student in subjects %}
<tr>
<td name= 'student'><p class="student-name" id="student-name">{{ student.sname }}</p></td>
<td>
<input type="checkbox" name="attendance" id="attendance">
</td>
</tr>
{% endfor %}
<tr>
<td>
<button type="button" name="checked" id = "checked" class="btn btn-outline-dark mb-4 shadow" style="border-radius:25px;">Submit</button>
</td>
<td></td>
</tr>
</table>
</form>
</div>
</div>
This is jquery function I am using to capture data.
var formData = new FormData()
$(document).ready(function(){
$("#checked").click('click', function(){
$students = document.getElementsByClassName('student-name').textContent;
$attendance = $('#attendance').val()
console.log($students)
console.log($attendance)
})
})
I have tried $('student-name').val() to get value for all students but it returns blank. Nothing is captured with this method.
I wish capture all data and update it into attendance model.
This are my models:
# Custom Student Table
class CustomStudent(models.Model):
_id = models.AutoField
sname = models.CharField(max_length = 50)
slname = models.CharField(max_length = 50)
admissionNo = models.CharField(default= "", max_length=50)
parentName = models.CharField(default= "", max_length=100)
emerContact = models.CharField(default= "", max_length=50)
contactNo = models.CharField(default= "", max_length=50)
className = models.ForeignKey(Standard, on_delete=models.DO_NOTHING)
subjectName = models.ManyToManyField(Subject)
Year = models.CharField(default="", max_length=5)
email = models.CharField(default="", max_length=60)
address = models.CharField(default="", max_length=250)
def __str__(self):
# return str(self.slname)
return str(self.sname)
AttendenceChioces = [
('Y', 'Yes'),
('N', 'No')
]
# Student Attendance Table
cla
AttendanceStudent(models.Model):
attendace_id = models.AutoField(primary_key= True)
student = models.ForeignKey(CustomStudent, on_delete=CASCADE)
attendace = models.CharField(max_length = 50, choices=AttendenceChioces)
date = models.DateField(auto_now= True)
teacher = models.CharField(max_length=255)
def __str__(self):
return str(self.sname)
Is there any other efficient way to submit attendance data into database. I have tried capturing all data using jquery but it returns blank.
UPDATE:
I have figured out proper way to send data but issue is django is not receiving any data in view funtion. I have created a view function to process data as my current view function attendancefill cannot process url without subject value.
def attendanceFilled(request):
print(request.POST)
if request.method == 'POST':
print (request.POST)
return JsonResponse({'data' : request.POST}, status=200)
return render(request, 'teacher/attendance_st.html')
I have verified via console.log and chrome DevTools tat ajax is sending data. But in django there is no data. I have tried printing new data at all points in new view function. It always returns a empty dict.
This is my updated jquery:
var value = []
$(document).ready(function(){
$("#checked").click('click', function(){
csrf = $("input[name=csrfmiddlewaretoken]").val();
value.push({'csrfmiddlewaretoken' : '{{ csrf_token }}'})
$('#attendance_table tr').each(function(a,b){
$student = $('.student-name', b).text();
$present = $('#attendance', b).prop('checked');
value.push({Student : $student, Present : $present})
})
var datatoadd = JSON.stringify(value);
document.getElementById("demo").innerHTML = datatoadd;
console.log(datatoadd)
$.ajax({
type: "POST",
url: '{% url "attendanceFilled" %}',
data: datatoadd,
cache: false,
processData: false,
contentType: false,
success: function(){
alert('Attendance submitted')
},
error: function(xhr, errmsg, err){
console.log(xhr.status + ":" + xhr.responseText)
alert('Attendance Failed to Submit! Please contact adminitstrator with your issue!')
}
})
})
})
my path in urls:
path('subject/<slug:subject>/', views.attendanceFill, name="subject"),
path('attendanceFilled', views.attendanceFilled, name="attendanceFilled"),
I am only posting required URLs here my URL file is too big.
#Sahil Mohile- Your model needs some clean-up.
class StudentAttendance(models.Model):
attendance_id = models.AutoField(primary_key= True)
student = models.ForeignKey(CustomStudent, on_delete=CASCADE,db_index=True)
attendace = models.CharField(max_length = 20, choices=AttendenceChioces)
date = models.DateField(auto_now= True)
teacher = models.ForeignKey(settings.AUTH_USER_MODEL)#Dont call it #tname, explicit is better than implicit.
def __str__(self):
return str(self.sname)
Now. my main point. Attendance record is tied to a Term/Semester. How about you
create a Semester Table. Tie the student attendance with a specific semester/term
import datetime
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
def current_year():
return datetime.date.today().year
def max_value_current_year(value):
return MaxValueValidator(current_year())(value)
class Semester(models.Model):
name = models.CharField(max_length=50)
year = models.PositiveIntegerField(
default=current_year(), validators=[MinValueValidator(1984), max_value_current_year])
.........
e.g Fall 2020
class StudentAttendance(models.Model):
attendance_id = models.AutoField(primary_key= True)
semester = models.ForeignKey(Semester,db_index=True)
student = models.ForeignKey(CustomStudent, on_delete=CASCADE,db_index=True)
attendace = models.CharField(max_length = 20, choices=AttendenceChioces)
date = models.DateField(auto_now= True)
teacher = models.ForeignKey(settings.AUTH_USER_MODEL)#Dont call it #tname, explicit is better than implicit.
Also, I predict that there might be a situation where you will be asked to present the number of present days for a specific student in a specific semester. Something to think about.
I am a bit confused. You are capturing the data but where are you making the ajax POST? You need to share the POST request
var formData = new FormData()
$(document).ready(function(){
$("#checked").click('click', function(){
$students = document.getElementsByClassName('student-name').textContent;
$attendance = $('#attendance').val()
console.log($students)
console.log($attendance)
})
})
Shouldn't you be doing the following too
$.ajax({
type: "POST",
url: 'your url',
data: {
#your data
csrfmiddlewaretoken: csrf_token
},
success:function(response){
},
error:function(error){
}
});

Conditionally showing a button with DJANGO template language

I have a page that should show a button if the user is marked as "facturable" (billable), otherwise, the button should not appear. I tried the following code:
{% if form_experfil.facturable %}
<a href="{% url 'incid:xtodo' %}?pagref=factdatshow" type="button"
class="btn btn-primary waves-effect"> Consultar datos de facturaciĆ³n</a>
{% endif %}
But it keeps showing. This and other fails make me think that the {% if %} tag behaviour isnh't as straightforward as I thought, and it does not just clip the html code down to the endif tag, but something gets rendered first. Is there somewhere where this is formally documented without mystical references?. Is there a way to just show this button when the customer has this data and not show it otherwise?.
This is the view:
def perfil_view(request):
perfil = ExUserProfile.objects.get(user=request.user)
facturar = perfil.facturable
if facturar:
factdat = Factdat.objects.get(cliente=request.user)
if request.method == 'POST':
form_perfil = perfilEditForm(data=request.POST, instance=request.user)
form_experfil = experfilEditForm(data=request.POST, instance=perfil)
if facturar:
form_factdat = factdatEditForm(data=request.Post, instance=perfil)
if all([form_perfil.is_valid(), form_experfil.is_valid(), form_factdat.is_valid()]):
form_perfil.save()
form_experfil.save()
form_factdat.save(commit=facturar)
return HttpResponseRedirect('incid/perfil')
else:
form_perfil = perfilEditForm(instance=request.user)
form_experfil = experfilEditForm(instance=perfil)
if facturar:
form_factdat = factdatEditForm(instance=factdat)
template = "incid/perfil.html"
if facturar:
return render(request, template, {
'form_perfil': form_perfil,
'form_experfil': form_experfil,
'form_factdat': form_factdat
})
else:
return render(request, template, {
'form_perfil': form_perfil,
'form_experfil': form_experfil
})
and these are the models:
eclass ExUserProfile(models.Model):
user = models.OneToOneField(User,
primary_key=True,
on_delete=models.DO_NOTHING)
logo = ResizedImageField(size=[200, 200],
crop=['middle', 'center'],
quality=75, upload_to='static/logos/',
default='logos/no-img.jpg')
facturable = models.BooleanField(default=False)
def __str__(self):
return str(self.user)
class Factdat(models.Model):
cliente = models.OneToOneField(User,
verbose_name='cliente_fact',
primary_key=True,
default='',
on_delete=models.DO_NOTHING)
nomfact = models.CharField(max_length=240,
verbose_name='nomfact')
niffact = models.CharField(max_length=16,
verbose_name='niffact')
mailfact = models.EmailField(max_length=254,
verbose_name='mailfact')
telfact = models.CharField(max_length=24,
verbose_name='telfact')
persfact = models.CharField(max_length=128,
verbose_name='persfact')
class Meta:
verbose_name = "Fact_dat"
verbose_name_plural = "Fact_datos"
def __str__(self):
return str(self.cliente)
and just in case, here is the full page:
def perfil_view(request):
perfil = ExUserProfile.objects.get(user=request.user)
facturar = perfil.facturable
if facturar:
factdat = Factdat.objects.get(cliente=request.user)
if request.method == 'POST':
form_perfil = perfilEditForm(data=request.POST, instance=request.user)
form_experfil = experfilEditForm(data=request.POST, instance=perfil)
if facturar:
form_factdat = factdatEditForm(data=request.Post, instance=perfil)
if all([form_perfil.is_valid(), form_experfil.is_valid(), form_factdat.is_valid()]):
form_perfil.save()
form_experfil.save()
form_factdat.save(commit=facturar)
return HttpResponseRedirect('incid/perfil')
else:
form_perfil = perfilEditForm(instance=request.user)
form_experfil = experfilEditForm(instance=perfil)
if facturar:
form_factdat = factdatEditForm(instance=factdat)
template = "incid/perfil.html"
if facturar:
return render(request, template, {
'form_perfil': form_perfil,
'form_experfil': form_experfil,
'form_factdat': form_factdat
})
else:
return render(request, template, {
'form_perfil': form_perfil,
'form_experfil': form_experfil
})

How to Pass an Image File to a API Endpoint

I have a web services with DRF, I have POSTMAN passing the right all fields right with success including the image file ['avatar']
[]1
Now how do i pass the image file from a Django Form, but i keep getting Error 400, Bad request. Please how do i encode the image file to be passed into the API endpoint .
html
<form method="post" action="#" enctype="multipart/form-data">
{% csrf_token %}
<label for="phone">Enter Phone</label>
{{ form.phone }} <br />
<label for="bvn">Enter BVN</label>
{{ form.bvn }} <br />
<label for="avatar">Upload Avatar</label>
{{ form.avatar }} <br />
<button type="submit" class="btn btn-primary" >Submit</button>
</form>
views.py
def form_valid(self, form):
token = self.request.session['session_token']
headers = {"Content-Type": 'application/json', "Authorization": "Token " + token}
parameters = {
'bvn': form.cleaned_data['bvn'],
'phone': form.cleaned_data['phone'],
'avatar': self.request.FILES['avatar']
}
response = requests.put(str(settings.API_END_POINT + '/customer_profile_api/'), data=parameters,
headers=headers)
if response.status_code in settings.SUCCESS_CODES:
messages.success(self.request, 'Successfully updated profile')
else:
messages.error(self.request, 'API Error %s' % response.status_code)
return super(CustomerDashboard, self).form_valid(form)
form.py
class ProfileUpdateForm(forms.Form):
"""customer profile update form"""
phone = forms.CharField(required=False, widget=NumberInput(attrs={'class': 'form-control',
'type': 'number', 'id': 'phone',
'placeholder': 'Enter Phone Number'}))
bvn = forms.CharField(required=False, widget=NumberInput(attrs={'class': 'form-control',
'type': 'number', 'id': 'bvn',
'placeholder': 'Enter BVN'}))
avatar = forms.ImageField(required=False, widget=ClearableFileInput(attrs={'class': 'form-control',
'type': 'file', 'id': 'avatar',
'placeholder': 'Upload Avatar'}))
Yours headers is wrong.
headers = {"Content-Type": 'application/json', "Authorization": "Token " + token}
change to:
headers = {"Content-Type": 'multipart/form-data', "Authorization": "Token " + token}
When you upload some file you should use multipart/form-data instead of application/json
(If you certainly do not send the file as base64)
Should someone else run into the same issue, The only way i was able to solve it is to have separate views to handle image and other text fields. What i did so far that worked.
If you noticed, the content-type header for the view that handles the image wasnt inserted, Just remove it and let it your API handle it by itself, several times i set it as multipart/form-data, i will hit response code 200/201, but file never get saved.
my API views.py
class CustomerApiView(generics.UpdateAPIView, generics.ListAPIView):
"""Customer Api View to update customer profile"""
http_method_names = ['put', 'get']
renderer_classes = [renderers.JSONRenderer]
authentication_classes = [authentication.TokenAuthentication]
serializer_class = CustomerSerializer
queryset = Profile.objects.all()
permission_classes = [IsAuthenticated]
def get_queryset(self):
user = self.request.user
return self.queryset.filter(user=user)
def get_object(self):
queryset = self.filter_queryset(self.get_queryset())
# make sure to catch 404's below
obj = queryset.get(user_id=self.request.user.id)
self.check_object_permissions(self.request, obj)
return obj
class CustomerAvatarApiView(generics.UpdateAPIView):
"""Customer Avatar/DP API View"""
serializer_class = CustomerAvatarSerializer
queryset = Profile.objects.all()
authentication_classes = [authentication.TokenAuthentication]
permission_classes = [IsAuthenticated]
renderer_classes = [renderers.JSONRenderer]
http_method_names = ['put', 'get']
def get_object(self):
queryset = self.filter_queryset(self.get_queryset())
# make sure to catch 404's below
obj = queryset.get(user_id=self.request.user.id)
self.check_object_permissions(self.request, obj)
return obj
serializer.py
class CustomerSerializer(serializers.ModelSerializer):
"""Customer Profile Serializer"""
class Meta:
"""Class Meta"""
model = Profile
fields = ('pk', 'phone', 'bvn', 'avatar')
extra_kwargs = {'pk': {'read_only': True}, }
class CustomerAvatarSerializer(serializers.ModelSerializer):
"""Separate Serializer to handle upload of file"""
class Meta:
"""Class Meta"""
model = Profile
fields = ('avatar', )
my view.py
class CustomerDashboard(LoginRequiredMixin, generic.FormView):
"""customer dashboard view"""
template_name = 'customer/dashboard.html'
form_class = ProfileUpdateForm
raise_exception = False
success_url = reverse_lazy('customer_dashboard')
def get_profile_api(self):
"""get profile api call to fetch profile; passing in the token from session"""
token = self.request.session['session_token']
headers = {"Content-Type": 'application/json', "Authorization": "Token " + token}
response = requests.get(str(settings.API_END_POINT + '/customer_profile_api/'), headers=headers)
json_response = response.json()
return json_response
def get_initial(self):
initial = ''
try:
initial = super(CustomerDashboard, self).get_initial()
initial['phone'] = self.get_profile_api()[0]['phone']
initial['bvn'] = self.get_profile_api()[0]['bvn']
except:
pass
return initial
def get_context_data(self, **kwargs):
"""overriding get_context_data to pass data to template"""
context = super(CustomerDashboard, self).get_context_data()
if self.get_profile_api()[0]['bvn'] != '': # if BVN has been filled before pass True or False to template
context['bvn_initial'] = True # Todo Validate BVN from API Before calling save method on it
else:
context['bvn_initial'] = False
return context
def form_valid(self, form):
token = self.request.session['session_token']
if 'updateAvatar' in self.request.POST:
headers = {"Authorization": "Token " + token}
avatar = form.cleaned_data['avatar']
file = {'avatar': (str(avatar), avatar)}
response = requests.put(str(settings.API_END_POINT + '/customer_profile_avi_api/'), files=file,
headers=headers)
message = 'Avatar changes successfully'
if response.status_code in settings.SUCCESS_CODES:
messages.success(self.request, message)
else:
messages.error(self.request, 'API Error %s' % response)
elif 'updateProfile' in self.request.POST:
headers = {"Content-Type": "application/json", "Authorization": "Token " + token}
parameters = {
'bvn': form.cleaned_data['bvn'],
'phone': form.cleaned_data['phone'],
}
response = requests.put(str(settings.API_END_POINT + '/customer_profile_api/'), json=parameters,
headers=headers)
message = 'Profile changes successfully'
if response.status_code in settings.SUCCESS_CODES:
messages.success(self.request, message)
else:
messages.error(self.request, 'API Error %s' % response)
return super(CustomerDashboard, self).form_valid(form)

Easiest way to update model values using Django with an AJAX form

I have a django model which contains some fields with associated choices:
class Product(models.Model):
CONDITION_CHOICES = (
("GOOD", "Good"),
("BAD", "Bad"),
("UNKNOWN", "Unknown"),
)
name = models.CharField(max_length=200, blank=True, null=True)
colour = models.CharField(max_length=200, blank=True, null=True)
condition = models.CharField(max_length=20, choices=CONDITION_CHOICES, blank=True, null=True)
condition_source = models.CharField(max_length=20, blank=True, null=True)
condition_last_updated = models.DateTimeField(blank=True, null=True)
I also have a bootstrap driven form that looks like:
<div class="form-group">
<label class="control-label"><strong>Condition</strong></label>
<br/>
<div class="btn-group btn-group-toggle" data-toggle="buttons">
<label class="btn btn-outline-primary">
<input type="radio" name="condition" value="GOOD" autocomplete="off">
Good
</label>
<label class="btn btn-outline-primary">
<input type="radio" name="condition" value="BAD" autocomplete="off">
Bad
</label>
<label class="btn btn-outline-primary">
<input type="radio" name="condition" value="UNKNOWN" autocomplete="off">
Unknown
</label>
</div>
</div>
I am trying to make it so that when a user clicks on one of the buttons in the UI, the Product model is updated (specifically the condition, condition_source and condition_last_updated fields). The actual model has multiple fields with associated with choice options so I'd like the model to get updated in real time without a page reload as a user works through the form.
Any guidance would be appreciated here - I have looked at intercooler.js but unsure if this is the right tool for the job.
As you have not specified what condition_source should include I have set it to string some_source
Ajax:
$('.btn').on('click', function(){
$.post(
'/your_vew/',
{
'source': "some_source",
'condition': $(this).find('input').val(),
'csrfmiddlewaretoken': '{{csrf_token}}'
},
function(data){
console.log(data.response);
}
);
});
urls.py:
urlpatterns = [
...
path('your_vew/', views.your_view),
...
]
views.py:
from django.http import JsonResponse
from datetime import datetime
def your_view(request):
data = {'response': ''}
if request.method == 'POST':
p1 = Product.objects.filter(pk=1).update(
condition_source=request.POST.get('source'),
condition=request.POST.get('condition'),
condition_last_updated=datetime.now()
)
if p1:
data['response'] = 'Record updated!'
return JsonResponse(data)
Now, you have a few options. What I did is that i used the Jquery ajax method in form of a class and set up my functions for my applications inside this class. Django requires the csrf token in order to process incomming requests. So i found these two functions which retreives the cookie csrf token from the client.
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
Once the csrf token has been stored in a variable you need to pass this to the ajax beforeSend function for example like this:
ajax_setup(enable_async){
enable_async = true;
$.ajaxSetup({
async: enable_async,
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
}
}
The full ajax request would be something like
update_user_language(user_id, lang, callback){
this.ajax_setup(true);
$.ajax({
url: this.url,
type: "POST",
data: {
'user_id':user_id,
'lang':lang,
},
dataType: 'json',
success: function(data){
db_request_after();
if(callback !== undefined) callback(data);
},
error: function(){
db_request_error();
},
});
}
Note the callback variable. This allows ajax to call a function passing the data retreived from the webservice.
Once you sent the request you need to setup your view.py to accept the request and process the POST variables.
def sample_view(request):
if request.method == "POST"
user_id = request.POST.get('user_id')
lang = request.POST.get('lang')
#update the model value
user = User.objects.get(pk=user_id)
user.language = lang
user.save()
return JsonResponse({'message':'user updated'})
else:
return render(...)