How to render a json data into restapi? - django

I got a JSON response from some url. I have to show that into rest api but i got error. Here is my code
views
class StoreView(APIView):
serializer_class = PostcodeLookupSerializer
resp = requests.get('https://api.postcodes.io/postcodes/BN14 9GB')
resp_data = resp.json()['result']
result_dic = {
'longitude': resp_data['longitude'],
'latitude': resp_data['latitude']
}
result_data = JsonResponse(result_dic)
def result(self):
json_data = self.resp_data()
file_serializer = PostcodeLookupSerializer(json_data, many=True)
return Response(data=file_serializer.data, status=status.HTTP_200_OK)
serializer
class PostcodeLookupSerializer(serializers.Serializer):
postcode = serializers.CharField(required=True)
name = serializers.CharField(required=True)
and url
urlpatterns = [
path('views/', StoreView.as_view(), name='postcode_lookup'),]
how to display a json response into restapi?
I got this error
"detail": "Method \"GET\" not allowed."

You should return data inside response as below
return Response(data=file_serializer.data, status=status.HTTP_200_OK)

Related

TypeError: Field 'id' expected a number but got <django.contrib.auth.models.AnonymousUser object at 0x7f5e95756920>

first time I ask on the website.
I was testing a Django Restframework app.
The is to check an unauthenticated user that wants to create a review.
I got this error:
TypeError: Field 'id' expected a number but got <django.contrib.auth.models.AnonymousUser object at 0x7f5e95756920>.
this is the class test:
class ReviewTestCase(APITestCase):
def setUp(self):
self.user = User.objects.create_user(
username="example", password="Password#123")
self.token = Token.objects.get(user__username=self.user)
self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key)
self.stream = models.StreamPlatform.objects.create(
name="Netflix",
about="#1 Platform",
website="https://www.netflix.com"
)
self.watchlist = models.WatchList.objects.create(
platform=self.stream, title="Example Movie",
storyline="Example Movie",
active=True
)
self.watchlist2 = models.WatchList.objects.create(platform=self.stream, title="Example Movie",
storyline="Example Movie", active=True)
self.review = models.Review.objects.create(review_user=self.user, rating=5, description="Great Movie",
watchlist=self.watchlist2, active=True)
def test_review_create(self):
data = {
"review_user": self.user,
"rating": 5,
"description": "Great Movie!",
"watchlist": self.watchlist,
"active": True
}
response = self.client.post(
reverse('reviewcreate', args=(self.watchlist.id,)), data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(models.Review.objects.count(), 2)
response = self.client.post(
reverse('reviewcreate', args=(self.watchlist.id,)), data)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
**#The test who cause the error**
def test_review_create_unauth(self):
data = {
"review_user": self.user,
"rating": 5,
"description": "Great Movie!",
"watchlist": self.watchlist,
"active": True
}
self.client.force_authenticate(user=None, token=None)
response = self.client.post(
reverse('reviewcreate', args=(self.watchlist.id,)), data)
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
def test_review_update(self):
data = {
"review_user": self.user,
"rating": 4,
"description": "Great Movie! - Updated",
"watchlist": self.watchlist,
"active": False
}
response = self.client.put(
reverse('review-detail', args=(self.review.id,)), data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_review_list(self):
response = self.client.get(
reverse('movie-review', args=(self.watchlist.id,)))
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_review_ind(self):
response = self.client.get(
reverse('review-detail', args=(self.review.id,)))
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_review_ind_delete(self):
response = self.client.delete(
reverse('review-detail', args=(self.review.id,)))
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
def test_review_user(self):
response = self.client.get(
'/watch/review/?username' + self.user.username)
self.assertEqual(response.status_code, status.HTTP_200_OK)
In data items, you are passing an object, and you have to pasa an id. Change this:
review_user: self.user.id
Thanks to everyone,
I found the mistake.
In fact the problem was not in the func in the tests.py but in the view,
where I misspelled:
permission_classes = [IsAuthenticated]
with:
permission_clasees = [IsAuthenticated]
So everything is fine now.
Thanks again to all of you

How to convert Django model that has FileField into JSON

I tried to get the last inserted data from the following method
latest = AudioContentModel.objects.latest('id').id
object = model_to_dict(AudioContentModel.objects.get(pk=latest))
but I get the following error
TypeError: Object of type 'FieldFile' is not JSON serializable
How can I get the data from the table that was last inserted?
This is my model.py
class AudioContentModel(models.Model):
background_music = models.FileField(upload_to='documents/')
tts = models.FileField(upload_to='documents/')
final_audio = models.FileField(upload_to='documents/')
created = models.DateField(auto_now_add=True)
This is my view.py
def index(request):
if request.method == 'POST':
if request.is_ajax():
audiouploadform = AudioUploadForm(request.POST, request.FILES)
if audiouploadform.is_valid():
audiouploadform.save()
latest = AudioContentModel.objects.latest('id').id
print('Need to get the all the data from the latest and resturn as a JsonResponse')
data{
'background_music':
'tts':
'id':
}
return JsonResponse({'error': False, 'data': data})
else:
return JsonResponse({'error': True, 'errors': audiouploadform.errors})
else:
error = {
'message': 'Error! Must be an Ajax call'
}
return JsonResponse(error, content_type="application/json")
else:
audiouploadform = AudioUploadForm()
all_audio_files = AudioContentModel.objects.all()
data = {
'audio_file_list': all_audio_files,
'audiouploadform': audiouploadform,
}
return render(request, template_name='index.html', context=data)
I figure it out.
latest = AudioContentModel.objects.latest('id').id
print(latest)
instance = AudioContentModel.objects.get(pk=latest)
data = {
'id': instance.id,
'background_music': instance.background_music.url,
'tts': instance.tts.url,
'created':instance.created,
}

Automation with Celery Periodic Tasks in Django 1.11

I have implemented the following class based view below that creates a payslip and it's working perfectly. I was thinking further to automate this functionality by running it periodically i.e every month. How do I trigger the POST method with celery tasks.py to run periodically? I'm using celery==4.1.0,RabbitMQas my message broker,Python3andDjango 1.11anddjangorestframework==3.8.2`.
class PayslipPostAPIView(APIView):
"""
.. http:get:: /payslip_create/
**Request**:
.. sourcecode:: http
GET /payslip_create/web HTTP/1.1
Host: {{theDomain}}
Accept: application/json, text/javascript
**Response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: text/javascript
[
{
"id": 123,
"employee": 123,
"basic_salary": ["server", "web"],
"payment_mode": "I tried Nginx",
"currency": "Currency",
"payslip_no": "Payslip Number",
"month_ending": "Date",
"is_accounted": "True/False",
"created_at": "Date"
"modified_at": "Date",
"total_allowances": 123,
"total_deductions": 123,
"net_pay": 123,
"organization": 123
}
]
:reqheader Authorization: JWT token required to authenticate
.. http:post:: /payslip_create/
:param post_id: post's unique id
:type post_id: int
:reqheader Authorization: JWT token required to authenticate
:status 201: Payslip successfully Created
:status 400: Post parameters are invalid or missing
"""
permission_classes = (permissions.DjangoObjectPermissions,)
queryset = Payslip.objects.all()
model_list = [EmployeeProfile, Salary, Allowance, Deduction, PaymentMode]
def get(self, request, format=None):
payslip = Payslip.objects.filter(organization=get_auth(request)).all()
serializer = PayslipSerializer(payslip, many=True)
return Response(serializer.data)
def post(self, request, format=None):
try:
allowance_list = request.data.pop('allowance_list')
deduction_list = request.data.pop('deduction_list')
# employee = EmployeeProfile.objects.get(
# id=request.data.pop('employee'), organization=get_auth(request))
employee = EmployeeProfile.objects.get(id=request.data.pop('employee'),
organization=get_auth(request))
basic_salary = Salary.objects.get(
employee=employee)
# print(basic_salary)
payment_mode = PaymentMode.objects.get(
id=request.data.pop('payment_mode'), organization=get_auth(request))
data = request.data
data["organization"] = get_auth(request)
payslip = Payslip.objects.create(**data)
payslip.payslip_no = "PAYSLIP" + str(payslip.id) + "DT" + \
str(datetime.datetime.today())
payslip.basic_salary = basic_salary
payslip.employee = employee
payslip.payment_mode = payment_mode
payslip.save()
for item in allowance_list:
allowance = Allowance.objects.create(name=AllowanceType.objects.get(id=item['name']),
amount=item['amount'],
payslip=payslip,
organization=get_auth(
request)
)
for item in deduction_list:
ded = DeductionType.objects.get(id=item['name'])
deduction = Deduction.objects.create(name=ded,
amount=item['amount'],
payslip=payslip,
organization=get_auth(
request)
)
serializer = PayslipSerializer(payslip)
allow = Allowance.objects.filter(
payslip=payslip.id).aggregate(Sum('amount'))
deduct = Deduction.objects.filter(
payslip=payslip.id).aggregate(amount=Sum('amount'))
total_deductions = deduct['amount']
total_allowances = allow['amount__sum']
net_pay = (payslip.basic_salary.salary_value +
allow['amount__sum']) - deduct['amount']
payslip.total_deductions = total_deductions
payslip.total_allowances = total_allowances
payslip.basic_salary = basic_salary
payslip.organization = get_auth(request)
payslip.net_pay = net_pay
payslip.save()
serializer = PayslipSerializer(payslip)
payload = {
"allowances": list(Allowance.objects.filter(payslip=payslip.id, organization=get_auth(request)).values('name', 'amount', 'name__name')),
"deductions": list(Deduction.objects.filter(payslip=payslip.id, organization=get_auth(request)).values('name', 'amount', 'name__name')),
"app": "payroll",
"organization": get_auth(request),
"total_deductions": total_deductions,
"basic": payslip.basic_salary.salary_value,
"sal_grp": payslip.basic_salary.salary_group.name,
"total_allowances": total_allowances,
"net_pay": net_pay,
"paid": payslip.is_paid,
"data": json.dumps(serializer.data)
}
# print(payload)
###############################################
# Post the paslip entry updates to accounting #
###############################################
#
# ACC_IP = "http://0.0.0.0:8000"
accounting_url = ACC_IP + "/acc/incoming/transations/"
try:
if send_payslip_accounts(payload, accounting_url):
payslip.is_accounted = True
payslip.save()
return Response(data=json.dumps(serializer.data), status=status.HTTP_201_CREATED)
else:
payslip.is_accounted = False
payslip.save()
except Exception as e:
return Response(data=str(e), status=status.HTTP_400_BAD_REQUEST)
return Response(status=status.HTTP_201_CREATED)
except Exception as e:
raise e
return Response(serializer.data, status=status.HTTP_201_CREATED)
tasks.py
from celery import task
#task()
send_payslip_accounts(payload, accounting_url, payslip):
...
payslip.is_accounted = True
payslip.save()
views.py
from .tasks import send_payslip_accounts
class PayslipPostAPIView(APIView):
...
payslip.is_accounted = False
payslip.save()
send_payslip_accounts.apply_async((payload, accounting_url, payslip),)
...

Django rest framework custom return response

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

Django: How can I download images from Base64ImageField?

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);