I can use json format to upload images with Base64ImageField (by POST), but now I want to download images in the same way (by POST). When I POST a image to "driver_photo", for example:
"R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
,the image would save as "driver_photo":"driver_photos/2016/05/20/d2821170-662.gif".
My question is how could I open the file , encode it for convenient transmition by Base64ImageField and POST them.
Below is my serializer.py
class PassengerDataSerializer(serializers.ModelSerializer):
passenger_photo = Base64ImageField(
max_length=None, use_url=True,
)
class Meta:
model = PassengerData
fields = ("passenger_name","passenger_phone", "passenger_photo")
class TaxiDriverDataSerializer(serializers.ModelSerializer):
PassengerDatas = PassengerDataSerializer( many=True )
driver_photo = Base64ImageField(
max_length=None, use_url=True,
)
class Meta:
model = TaxiDriverData
fields = ("pk","fingerprint","driver_name","driver_photo","PassengerDatas")
def create(self, validated_data):
taxiDriverData = TaxiDriverData.objects.create(fingerprint = validated_data['fingerprint'],
driver_name = validated_data['driver_name'],
driver_photo = validated_data['driver_photo'],
)
taxiDriverData.save()
Passenger_Datas = validated_data.pop('PassengerDatas')
for passenger in Passenger_Datas:
passengerdata = PassengerData.objects.create(passenger_name = passenger.get('passenger_name'),
passenger_phone = passenger.get('passenger_phone'),
passenger_photo = passenger.get('passenger_photo'), )
passengerdata.taxi_driver_data_id = taxiDriverData
passengerdata.save()
return taxiDriverData
def update(self, instance, validated_data):
instance.fingerprint = validated_data['fingerprint']
instance.driver_name = validated_data['driver_name']
instance.driver_photo = validated_data['driver_photo']
instance.save()
return instance
views.py
#api_view(['GET','POST'])
def taxi_driver_list(request, format=None):
if request.method=="GET":
TaxiDriverDatas =list(TaxiDriverData.objects.all())
serializer = TaxiDriverDataSerializer(TaxiDriverDatas,many=True)
return Response(serializer.data)
elif request.method == 'POST':
#print (request.body)
serializer = TaxiDriverDataSerializer(data=request.data)
#, files=request.FILES
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#api_view(['GET', 'PUT', 'DELETE'])
def taxi_driver_detial(request,pk, format=None):
try:
Taxi_Driver_Data = TaxiDriverData.objects.get(pk=pk)
except TaxiDriverData.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == "GET":
serializer = TaxiDriverDataSerializer(Taxi_Driver_Data)
return Response(serializer.data)
elif request.method == "PUT":
serializer = TaxiDriverDataSerializer(Taxi_Driver_Data,data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
elif request.method == "DELETE":
Taxi_Driver_Data.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
models.py
class TaxiDriverData(models.Model):
fingerprint = models.CharField(max_length=30, default="")
driver_name = models.CharField(max_length=30, default="")
driver_photo = models.ImageField(upload_to ="driver_photos/%Y/%m/%d/", null=True ,blank=True)
class PassengerData(models.Model):
taxi_driver_data_id = models.ForeignKey(TaxiDriverData, related_name='PassengerDatas', null=True)
passenger_name = models.CharField(max_length=100, default="")
passenger_phone = models.CharField(validators=[phone_regex], blank=True, max_length=16)
passenger_photo = models.ImageField(upload_to ="passenger_photos/%Y/%m/%d/", null=True ,blank=True )
Thanks for help.
It is highly recommended to use POST instead of GET to send/receive Base64 images, since Base64 images are converted to String with length of string varying upto 15000 characters. If you are using the GET method, you are limited to a maximum of 2,048 characters.
Save the image
import base64
imgdata = base64.b64decode(imgstring)
filename = 'some_image.jpg' # I assume you have a way of picking unique filenames
with open(filename, 'wb') as f:
f.write(imgdata)
Edit1
You could do something like this to save the image
import base64
import datetime
def save_image(request):
b64_image = request.POST['driver_photo'] #key that is being used to send the data
imgdata = base64.b64decode(b64_image)
var = datetime.datetime.now().strftime("%d%m%Y%H%M%S") #This will give unique values everytime. Values are based on current datetime
filename = "PATH_TO_SAVE_FILE" + var +'.jpg'
with open(filename, 'wb') as f:
f.write(imgdata)
Edit 2
POST Request in Android
HttpClient httpclient = new DefaultHttpClient();
String responseStr="";
String URL=Constants.API_URL;#URL where request needs to be sent
HttpPost httppost = new HttpPost(URL);
try {
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("id", pick_up_id));
nameValuePairs.add(new BasicNameValuePair("driver_photo", strPhoto));#image in form of Base64 String which you need to send
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
int responseCode = response.getStatusLine().getStatusCode();
switch(responseCode) {
case 200:
HttpEntity entity = response.getEntity();
if(entity != null) {
String responseBody = EntityUtils.toString(entity);
responseStr=responseBody;
}
break;
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
} catch (IOException e) {
// TODO Auto-generated catch block
}
System.out.println("this is response "+responseStr);
Related
So i was following this tutorial https://youtu.be/hISSGMafzvU, with different approach of mine ( instead of being a to do app, I'm trying to make it a clinic management system ).
So the problem I'm facing is that my api is receiving data, and there is no errors plus I'm getting 200 status code from the local server which means everything is okay, but its not hence the data isn't being stored in the DB for some reason.
this is the code:
models.py
class Employee(models.Model):
fullname = models.CharField(max_length = 250)
age = models.DateField(null=True, blank=True)
gender = models.CharField(max_length=10,
choices=(('Male', 'Male'), ('Female', 'Female')), default='Male')
usertype = models.CharField(max_length = 50, choices=
(('Admin','Admin'),('Doctor','Doctor'),('Receptionist','Receptionist')),
default='Receptionist')
def __str__(self):
return self.fullname
class Patient(models.Model):
fullname = models.CharField(max_length = 250)
def __str__(self):
return self.fullname
class Appointments(models.Model):
Paitent_Attending = models.ForeignKey(Patient, on_delete= models.CASCADE)
Doctor_Attending = models.ForeignKey(Employee, on_delete= models.CASCADE)
appointment_date = models.DateField()
def __str__(self):
return self.Paitent_Attending.fullname
serializers.py
from rest_framework import serializers
from .models import Employee,Patient,Appointments
class PatientSerializers(serializers.ModelSerializer):
class Meta:
model = Patient
fields = '__all__'
class EmployeeSerializers(serializers.ModelSerializer):
class Meta:
model = Employee
fields = '__all__'
class AppointmentsSerializers(serializers.ModelSerializer):
class Meta:
model = Appointments
fields = '__all__'
views.py
from django.shortcuts import render
from rest_framework import generics
from .models import *
from .serializers import *
from django.http import JsonResponse
from rest_framework.decorators import api_view
from rest_framework.response import Response
#api_view(['GET'])
def apiView(request):
api_urls = {
'Patient List':'/patient-list/',
'Employee List':'/employee-list/',
'Appointments List':'/appointments-list/',
'Patient View':'/patient-detail/<str:pk>/',
'Employee View':'/employee-detail/<str:pk>/',
'Appointments View':'/appointments-detail/<str:pk>/',
'Add Patient':'/add-patient/',
'Edit Patient':'/patient-edit/<str:pk>/',
'Delete Patient':'/patient-delete/<str:pk>/',
'Add Employee':'/add-employee/',
'Edit Employee':'/employee-edit/<str:pk>/',
'Delete Employee':'/employee-delete/<str:pk>/',
'Add Appointments':'/add-appointments/',
'Edit Appointments':'/appointments-edit/<str:pk>/',
'Delete Appointments':'/appointments-delete/<str:pk>/',
}
return Response(api_urls)
#views for listing All
#api_view(['GET'])
def patientList(request):
patient = Patient.objects.all()
serializer = PatientSerializers(patient, many=True)
return Response(serializer.data)
#api_view(['GET'])
def employeesList(request):
employee = Employee.objects.all()
serializer = EmployeeSerializers(employee, many=True)
return Response(serializer.data)
#api_view(['GET'])
def appointmentsList(request):
appointments = Appointments.objects.all()
serializer = AppointmentsSerializers(appointments, many=True)
return Response(serializer.data)
#Views for Details
#api_view(['GET'])
def patientDetails(request,pk):
patient = Patient.objects.get(id=pk)
serializer = PatientSerializers(patient, many=False)
return Response(serializer.data)
#api_view(['GET'])
def employeeDetails(request,pk):
employee = Employee.objects.get(id=pk)
serializer = EmployeeSerializers(employee, many=False)
return Response(serializer.data)
#api_view(['GET'])
def appointmentsDetails(request,pk):
appointments = Appointments.objects.get(id=pk)
serializer = AppointmentsSerializers(appointments, many=False)
return Response(serializer.data)
#Views for Create New
#api_view(['POST'])
def addPatient(request):
serializer = PatientSerializers(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
#api_view(['POST'])
def addEmployee(request):
serializer = EmployeeSerializers(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
#api_view(['POST'])
def addAppointment(request):
serializer = AppointmentsSerializers(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
#Views for updating & editing
#api_view(['POST'])
def editPatient(request,pk):
patient = Patient.objects.get(id=pk)
serializer = PatientSerializers(instance=patient, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
#api_view(['POST'])
def editEmployee(request,pk):
employee = Employee.objects.get(id=pk)
serializer = EmployeeSerializers(instance=employee, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
#api_view(['POST'])
def editAppointment(request,pk):
appointment = Appointments.objects.get(id=pk)
serializer = AppointmentsSerializers(instance=appointment, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
#Views for updating & editing
#api_view(['DELETE'])
def deletePatient(request,pk):
patient = Patient.objects.get(id=pk)
patient.delete()
return Response("Patient was successfully deleted")
#api_view(['DELETE'])
def deleteEmployee(request,pk):
employee = Employee.objects.get(id=pk)
employee.delete()
return Response("Employee was successfully deleted")
#api_view(['DELETE'])
def deleteAppointment(request,pk):
appointment = Appointments.objects.get(id=pk)
appointment.delete()
return Response("Appointment was successfully deleted")
the JS that sends data via fetch api.
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// 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;
}
const csrftoken = getCookie('csrftoken');
var form = document.getElementById('newPatient');
form.addEventListener('submit', function(e) {
e.preventDefault()
console.log('form submited');
var url = 'http://127.0.0.1:8000/api/add-patient/'
var Fullname = document.getElementById('Fullname').value
fetch(url, {
method: 'POST',
headers:{
'Content-Type': 'application/json',
'X-CSRFToken' : csrftoken,
},
body: JSON.stringify({'Fullname':Fullname})
}
)
})
I'm still a newbie to the api world, I'm confused here, help!
Its one of those stupid mistakes that when you don't focus on the names lol.
The name of the addPatient property
fullname
, the fetch api was trying to send the data to
Fullname
capital F which doesn't exist, in which resulted in data not being saved because of this code in views.py
def addPatient(request):
serializer = PatientSerializers(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
serializer was receiving data, but because of the capital F it didn't match the addPatient attribute which is fullname not Fullname which resulted in serializer not being valid thus not fulfilling the if statement condition thus not saving the data xD, sigh
I am trying to pass a list of student IDs but it is not working.
from angular I am passing data as follows
let noticeData = this.announceForm.value;
if (noticeData.students.includes('all')){
noticeData.students = noticeData.students.filter((s) => s != 'all')
}
noticeData.students = JSON.stringify(noticeData.students);
rest call
var formData = new FormData();
for (var key in noticeData) {
formData.set(key, noticeData[key]);
}
this._rest.one("/classwork/notices/")
.post('', formData)
.toPromise()
.then((classworks) => {
}, (error) => {
console.log("ERROR SENDING ANNOUNCEMENT ", error);
this.alert = {
type : "error",
message: "Something went wrong, please try again."
}
});
}
from django i am reading and trying to store data as
Below is the to_internal_value method which I have overridden.
def to_internal_value(self, data):
tempdict = data.copy()
tempdict['students'] = json.loads(data['students'])
data = tempdict
return super(NoticesSerializer, self).to_internal_value(data)
views.py
class ClassworkView(APIView):
def get(self, request, format=None):
notices = ClassworksFilter(request.query_params, queryset=Notice.objects.all()).qs
materials = ClassworksFilter(request.query_params, queryset=Material.objects.all()).qs
assignments = ClassworksFilter(request.query_params, queryset=Assignment.objects.all()).qs
queryset = sorted(
chain(notices, materials, assignments),
key=lambda instance: instance.create_date
)
model_serializers = {
'notice': NoticesSerializer,
}
classworks = []
for instance in queryset:
serializer = model_serializers[instance._meta.model_name]
data = serializer(instance).data
data['classwork_type'] = instance._meta.model_name
classworks.append(data)
page_number = request.query_params.get('page', 1)
page_size = request.query_params.get('page_size', 20)
page = Paginator(classworks, per_page=page_size).get_page(page_number)
base_url = f'{request.scheme}://{request.get_host()}{reverse("classworks")}'
params = [f'{k}={v}' if k!='page' else None for k,v in request.query_params.items()]
indx = 0
for param in params:
if param==None:
params.pop(indx)
indx+=1
params = '&'.join(params)
next = f'{base_url}?page={page.next_page_number()}&{params}' if page.has_next() else None
prev = f'{base_url}?page={page.previous_page_number()}&{params}' if page.has_previous() else None
response = {
'count': len(classworks),
'next': next,
'previous': prev,
'results': page.object_list
}
return Response(response)
here is serializer.py
class NoticesSerializer(serializers.ModelSerializer):
class Meta:
model = Notice
fields = '__all__'
def to_representation(self, instance):
representation = super(NoticesSerializer, self).to_representation(instance)
try:
representation['classroom'] = ClassroomsSerializer(instance.classroom, context=self.context).data
students = StudentsSerializer(instance.students, many=True, context=self.context).data
for student in students:
student['classroom'] = student['classroom']['id']
representation['students'] = students
except Exception as error:
print("ERROR SETTING REPRESENTATION FOR NOTICE SERIALIZER", error)
return representation
here is the models.py
class Notice(Classwork):
file = models.FileField(upload_to='classworks/attachments', blank=True, null=True)
link = models.URLField(blank=True, null=True)
description = models.TextField()
class Meta(BaseModel.Meta):
db_table = 'ec_notice'
but it always returns the same error
{students: [“Incorrect type. Expected pk value, received list.”]}
here the data I am posting by form data
I'm trying to upload a photo along with other data for my CustomerDetails model via an api endpoint. The data seems to save but, when I check my table, there is no data present.
Here is my model:
class CustomerDetails(models.Model):
Sizes = (
('Sizes', (
('small', 'small'),
('medium', 'medium'),
('large', 'large'),
)),
)
CATEGORIES = (
('Usage', (
('Headache', 'Headache'),
('Backaches', 'Insomnia'),
('Menstrual Cramps & Pains','Menstrual Cramps
)),
)
CUSTYPE = (
('Customer Type',(
('Athlete', 'Athlete'),
('Non-Athlete', 'Non-Athlete'),
)),
)
age = models.IntegerField(default="21", blank=True)
nick_name = models.CharField(max_length=500, blank=True)
average_order = models.FloatField(default = "0.0", blank=True)
completed_orders = models.IntegerField(default = "0", blank=True)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='customer')
customer_type = MultiSelectField(choices=CUSTYPE, default = CUSTYPE, max_length=100)
current_selfie = models.ImageField(upload_to= 'sefies/', blank=True, default='')
favorite_color = MultiSelectField(choices=TYPE, max_length=100)
interested_in = MultiSelectField(choices=CATEGORIES, max_length=1000)
last_signin = models.DateTimeField(default = timezone.now)
liked_stores = models.ManyToManyField('Stores')
liked_products = models.ManyToManyField('Product')
phone = PhoneField(blank=True, help_text='Contact phone number')
shares = models.IntegerField(default = "0", blank=True)
signup = models.DateTimeField(default = timezone.now)
def __str__(self):
return self.customer.user.get_full_name()
Here are my serializers & Url
url(r'^api/customer/create_customer_details/$', apis.CustomerDetailViewset.as_view()),
class CustomerDetailUploader(serializers.ModelSerializer):
customer = CustomerDetailSerializer()
current_selfie = serializers.SerializerMethodField()
def get_current_selfie(self, store):
request = self.context.get('request')
current_selfie_url = CustomerDetails.current_selfie.url
return request.build_absolute_uri(current_selfie_url)
class Meta:
model = CustomerDetails
fields = ('nick_name', 'customer', 'current_selfie', 'favorite_color', 'interested_in', 'customer_type')
Here is the apiView I'm using:
class CustomerDetailViewset(APIView):
parser_classes = (MultiPartParser, FormParser)
def post(self, request, *args, **kwargs):
file_serializer = CustomerDetailUploader(data=request.data)
if file_serializer.is_valid():
file_serializer.save()
return Response(file_serializer.data, status=status.HTTP_201_CREATED)
return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I'm trying to create a new customerDetails page for every user when they sign up, assign the data to a Customer, and save the details. Everytime I try to call the function, I do get the success message:
[15/Feb/2019 22:56:10] "POST /api/customer/create_customer_details/?access_token=U3EvAbo1HhOwNAgcEYUR4WOegul6ye HTTP/1.1" 201 99
Can anyone let me know how I can fix this?
You can try this save image (Base64) using DRF
serializer.py
class Base64ImageField(serializers.ImageField):
def to_internal_value(self, data):
from django.core.files.base import ContentFile
import base64
import six
import uuid
# Check if this is a base64 string
if isinstance(data, six.string_types):
# Check if the base64 string is in the "data:" format
if 'data:' in data and ';base64,' in data:
# Break out the header from the base64 content
header, data = data.split(';base64,')
# Try to decode the file. Return validation error if it fails.
try:
decoded_file = base64.b64decode(data)
except TypeError:
self.fail('invalid_image')
# Generate file name:
file_name = str(uuid.uuid4())[:12] # 12 characters are more than enough.
# Get the file name extension:
file_extension = self.get_file_extension(file_name, decoded_file)
complete_file_name = "%s.%s" % (file_name, file_extension, )
data = ContentFile(decoded_file, name=complete_file_name)
return super(Base64ImageField, self).to_internal_value(data)
def get_file_extension(self, file_name, decoded_file):
import imghdr
extension = imghdr.what(file_name, decoded_file)
extension = "jpg" if extension == "jpeg" else extension
return extension
class CustomerDetailUploader(serializers.ModelSerializer):
customer = CustomerDetailSerializer()
current_selfie = Base64ImageField()
class Meta:
model = CustomerDetails
fields = ('nick_name', 'customer', 'current_selfie', 'favorite_color', 'interested_in', 'customer_type')
in api.py
class CustomerDetailViewset(APIView):
parser_classes = (MultiPartParser, FormParser)
def post(self, request, *args, **kwargs):
file_serializer = CustomerDetailUploader(data=request.data)
if file_serializer.is_valid():
file_serializer.save()
return Reponse ({})
hope it help for your problem
Maybe you have some errors, but you are not seeing them, because you're return always 201. The first Response should be inner the if branch.
Your code:
def post(self, request, *args, **kwargs):
file_serializer = CustomerDetailUploader(data=request.data)
if file_serializer.is_valid():
file_serializer.save()
return Response(file_serializer.data, status=status.HTTP_201_CREATED)
return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
correct code:
def post(self, request, *args, **kwargs):
file_serializer = CustomerDetailUploader(data=request.data)
if file_serializer.is_valid():
file_serializer.save()
return Response(file_serializer.data, status=status.HTTP_201_CREATED)
return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
So I have this custom register API which registers a user, but when user successfully register, I want it to have this message "You have successfully register an account!" But I tried a different method but get an error instead.
serializer.py
class UserCreate2Serializer(ModelSerializer):
email = EmailField(label='Email Address')
valid_time_formats = ['%H:%M', '%I:%M%p', '%I:%M %p']
birthTime = serializers.TimeField(format='%I:%M %p', input_formats=valid_time_formats, allow_null=True, required=False)
class Meta:
model = MyUser
fields = ['username', 'password', 'email', 'first_name', 'last_name', 'gender', 'nric', 'birthday', 'birthTime']
extra_kwargs = {"password": {"write_only": True}}
def validate(self, data): # to validate if the user have been used
email = data['email']
user_queryset = MyUser.objects.filter(email=email)
if user_queryset.exists():
raise ValidationError("This user has already registered.")
return data
def create(self, validated_data):
username = validated_data['username']
password = validated_data['password']
email = validated_data['email']
first_name = validated_data['first_name']
last_name = validated_data['last_name']
gender = validated_data['gender']
nric = validated_data['nric']
birthday = validated_data['birthday']
birthTime = validated_data['birthTime']
user_obj = MyUser(
username = username,
email = email,
first_name = first_name,
last_name = last_name,
gender = gender,
nric = nric,
birthday = birthday,
birthTime = birthTime,
)
user_obj.set_password(password)
user_obj.save()
return validated
views.py
class CreateUser2View(CreateAPIView):
permission_classes = [AllowAny]
serializer_class = UserCreate2Serializer
queryset = MyUser.objects.all()
I tried changing this into the serializer
user_obj.set_password(password)
user_obj.save()
content = {'Message': 'You have successfully register an account'}
return content
But got an error instead. I'm unsure how to do the custom response as I only know it is to be done on views.py.
But if I do this on view:
class CreateUser2View(CreateAPIView):
permission_classes = [AllowAny]
serializer_class = UserCreate2Serializer
queryset = MyUser.objects.all()
def post(self, request):
content = {'Message': 'You have successfully register'}
return Response(content, status=status.HTTP_200_OK)
It will show this even if the validation is incorrect. Please help me as I'm still inexperienced in DRF.
class CreateUser2View(CreateAPIView):
permission_classes = [AllowAny]
serializer_class = UserCreate2Serializer
queryset = MyUser.objects.all()
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response({'Message': 'You have successfully register'}, status=status.HTTP_201_CREATED, headers=headers)
from rest_framework import status
from rest_framework.views import exception_handler as base_handler
def exception_handler(exception, context):
"""
Django rest framework for custom exception handler
#exception : Exception
#context : Context
"""
response = base_handler(exception, context)
if response is not None:
response = custom_response(response)
return response
def serializer_errors(data):
"""
Django rest framework serializing the errors
#data : data is python error dictionary
"""
errors = {}
got_msg = False
message = "Bad request."
if isinstance(data, dict):
for key, value in data.items():
try:
if isinstance(value, list):
value = ", ".join(value)
except Exception:
pass
if not got_msg:
if value:
message = value
got_msg = True
errors[key] = value
if not isinstance(message, str):
message = "Bad request"
return errors, message
def error(source, detail, code):
"""
Create python dictionary of error
#source : Where coming the error
#detail : Error detail information
"""
error = {}
error["source"] = source
error["detail"] = detail
if code:
error["code"] = code
return error
def custom_response(response):
"""
Modification the response of django rest framework
#response : Return response
"""
modified_data = {}
modified_data["code"] = response.status_code
modified_data["status"] = get_status(response.status_code)
data, message = serializer_errors(response.data)
modified_data["message"] = message
modified_data["errors"] = data
response.data = modified_data
return response
def get_status(status_code):
"""
Return result base on return http status
#status_code : HTTP status code
"""
result = ""
if status_code == status.HTTP_200_OK:
result = "Success"
elif status_code == status.HTTP_201_CREATED:
result = "Instance create"
elif status_code == status.HTTP_204_NO_CONTENT:
result = "Instance deleted"
elif status_code == status.HTTP_403_FORBIDDEN:
result = "Forbidden error"
elif status_code == status.HTTP_404_NOT_FOUND:
result = "Instance not found"
elif status_code == status.HTTP_400_BAD_REQUEST:
result = "Bad request"
elif status_code == status.HTTP_401_UNAUTHORIZED:
result = "Unauthorized request"
elif status_code == status.HTTP_500_INTERNAL_SERVER_ERROR:
result = "Internal server error"
else:
result = "Unknown error"
return result
in view.py:
#require_POST
#csrf_exempt
def ipn(request):
transactions_logger = logging.getLogger("django")
processor = Ipn(request.POST, logger=transactions_logger)
verification_success = processor.verify_ipn()
encoding = request.POST.get('ok_charset', None)
data = QueryDict(request.body, encoding=encoding)
if verification_success:
form = OkpayIpnForm(data)
if form.is_valid():
print("ALL FINE!!")
form.save()
return HttpResponse("")
In forms.py:
class OkpayIpnForm(forms.ModelForm):
class Meta:
model = OkpayIpn
exclude = []
Code for IPN Checkprocessor = Ipn(request.POST, logger=transactions_logger:
class Ipn(object):
OKPAY_VERIFICATION_URL = 'https://checkout.okpay.com/ipn-verify'
OKPAY_IPN_INVALID = b'INVALID'
OKPAY_IPN_VERIFIED = b'VERIFIED'
OKPAY_IPN_TEST = b'TEST'
OKPAY_STATUS_COMPLETED = 'completed'
__verification_result = False
def __init__(self, request_data, logger):
if 'ok_verify' in request_data:
raise Exception("ok_verify must not be present in initial request data for {}".format(
self.__class__.__name__
))
self._request_data = request_data
self.logger = logger
return
def verify_ipn(self):
self.__verification_result = False
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
}
verify_request_payload = {
'ok_verify': 'true',
}
verify_request_payload.update(self._request_data)
resp = requests.post(self.OKPAY_VERIFICATION_URL, data=verify_request_payload, headers=headers)
if resp.content == self.OKPAY_IPN_VERIFIED or resp.content == self.OKPAY_IPN_TEST:
self.__verification_result = True
# if resp.content == self.OKPAY_IPN_VERIFIED: # anyway disable test on production.
# self.__verification_result = True
return self.__verification_result
All is ok, I revice IPN and validate it, then I try to validate form and save it to Database.
But form doesn't pass validation and doesn't save to database.
Thank You for help
Problem was that 1 CharField of Model for saving IPN has maxlength=20, but recieved 40 symbols.
Thx jape he advised to add in form validation else statement and print form.errors
the error of of form validation was :
<li>ok_item_1_type<ul class="errorlist"><li>Ensure this value has at most 20 characters (it has 40).</li></ul></li>