Faster API for front end data table page? - reactjs

I'm using Django to feed a front end web page built with React.
I have an API that gets the necessary data with some formatting, but it's pretty slow. Any suggestions on how to build a faster API? It's currently returning 8 records which takes >3 seconds.
def deployed_data(request):
deployments = deployment.objects.filter(LAUNCH_DATE__isnull=False).filter(HISTORICAL=False)
res = []
for dep in deployments:
crt_dep = {
"FLOAT_SERIAL_NO":dep.FLOAT_SERIAL_NO,
"PLATFORM_NUMBER":dep.PLATFORM_NUMBER,
"PLATFORM_TYPE":dep.PLATFORM_TYPE.VALUE,
"DEPLOYMENT_CRUISE_ID":dep.DEPLOYMENT_CRUISE_ID,
"DEPLOYMENT_PLATFORM":dep.DEPLOYMENT_PLATFORM.VALUE,
"LAUNCH_DATE":dep.LAUNCH_DATE.strftime("%Y-%m-%d"),
"status":dep.status,
"last_report":dep.last_report.strftime("%Y-%m-%d %H:%M"),
"next_report":dep.next_report.strftime("%Y-%m-%d %H:%M"),
"days_since_last":dep.days_since_last,
"last_cycle":dep.last_cycle,
"age":dep.age.days
}
res.append(crt_dep)
return JsonResponse(res, status = 200, safe=False)

of course it's slower, you reialize on every loop every value in the dict is a separate hit to the database!
just use drf serializer or even django serializer to convert these data at once
or use values after filter

views.py
class GetDeploymentData(generics.ListAPIView):
serializer_class = DeployedDataSerializer
queryset=deployment.objects.filter(LAUNCH_DATE__isnull=False).filter(HISTORICAL=False)
serializers.py
class DeployedDataSerializer(serializers.Serializer):
FLOAT_SERIAL_NO = serializers.IntegerField()
PLATFORM_NUMBER = serializers.IntegerField()
PLATFORM_TYPE = serializers.CharField()
status = serializers.CharField()
DEPLOYMENT_CRUISE_ID = serializers.CharField()
DEPLOYMENT_PLATFORM = serializers.CharField()
LAUNCH_DATE = serializers.DateTimeField(format="%Y-%m-%d %H:%M")
last_report = serializers.DateTimeField(format="%Y-%m-%d %H:%M")
next_report = serializers.DateTimeField(format="%Y-%m-%d %H:%M")
days_since_last = serializers.IntegerField()
last_cycle = serializers.IntegerField()
age = serializers.IntegerField(source="age.days")
As Mohamed pointed out, serializers are much faster. But this is still not as fast as the same page created using django's templates.

Related

Add M2M field using create(): Django

I have a lot of doubts about managing the M2m field, I finally got a solution to add that data to a model, but there are still some issues, give me a solution to overcome this,
class CourseListSerializer(serializers.ModelSerializer):
instructors = serializers.SerializerMethodField()
image = FileField()
keyarea = CourseKeyAreaSerializer
subject = CourseSubjectsSerializer
sections = serializers.ListField(write_only=True)
beneficiaries = serializers.ListField(write_only=True)
section = CourseSectionSerializers
beneficiary = CourseBeneficiarySerializer
def create(self, validated_data):
data = validated_data
try:
new = Course.objects.create(image=data['image'], name=data['name'], description=data['description'], is_free=data['is_free'],
keyarea=data['keyarea'], subject=data['subject'])
new.save()
beneficiary_data = data['beneficiaries']
new.beneficiary.set(*[beneficiary_data])
section_data = data['sections']
new.section.set(*[section_data])
return new
except Exception as e:
e = "invalid data"
return e
here first creating the "new" object after that to set the M2M field like
"new.beneficiary.set(*[beneficiary_data])"
but is there any way to add beneficiary and section like this
"new = Course.objects.create(image=data['image'],name=data['name'], description=data['description'],is_free=data['is_free'],....)"

'Anonymous user' error after passing data with Angular to Rest

I am a beginner in Angular and Rest and I have a problem. I have a form in Django template and I want to pass data with Angular, receive it with Rest and process it. Angular knows to pass (post) the data by url to:
url(r'^api/nowyPacjent/$', CreateNewPatient.as_view(), name="api_tempPatient"),
The CreateNewPatient class looks like this:
class CreateNewPatient(generics.ListCreateAPIView):
model = TempPatient
queryset = TempPatient.objects.all()
serializer_class = CreateNewPatientSerializer
and the serializer looks like this:
class CreateNewPatientSerializer(serializers.Serializer):
name = serializers.CharField(max_length=30)
surname = serializers.CharField(max_length=70)
phone = serializers.CharField(max_length=15, required=False)
age = serializers.IntegerField(max_value=99, min_value=1, required=False)
company = serializers.PrimaryKeyRelatedField(many=False, queryset=Company.objects.all())
therapyStart = serializers.DateField(required=False)
def create(self, validated_data):
if 'therapyStart' in validated_data:
therapy_start = validated_data['therapyStart']
else:
therapy_start = datetime.date.today()
if 'age' in validated_data:
patient_age = validated_data['age']
else:
patient_age = 1;
if 'phone' in validated_data:
patient_phone = validated_data['phone']
else:
patient_phone = ''
newTempPatient = TempPatient(
name = validated_data['name'],
surname = validated_data['surname'],
company = validated_data['company'],
therapyStart = therapy_start,
age = patient_age,
phone = patient_phone
)
newTempPatient.save()
newPatient = Patient(
name=validated_data['name'],
surname=validated_data['surname'],
phone=patient_phone,
age=patient_age
)
newPatient.save()
user=None
request = self.context.get('request')
if request and hasattr(request,"user"):
user=request.user
newTherapyGroup = TherapyGroup.objects.create(
start = therapy_start,
patient = newPatient,
therapist = Therapist.objects.get(user = user),
company = validated_data['company']
)
newTherapyGroup.save()
return newTempPatient
Everything is fine - after submitting the template form the patient is created - until the code tries to get logged user from the request (just after the last if statement of the serializer). Then I receive the 'AnonymousUser' error and cannot create final model instance. I've tried to pass the data to the Django views and then use the Rest's serializer. However, the error occurred again. I've searched for the answer but nothing was helpful. Please, notice that I don't want to authenticate the logged user but to get data about him.
I think the problem is that Angular somehow loose information about CSRF token and log session and that is the reason of both errors (that is only my assumption).
Below is how Angular config looks like. NewPatientCtrl is responsible for mentioned form and model is one of the form element (and it works fine).
angular.module('pacjent', ['ngMessages', 'ui.bootstrap', 'datetime'])
.constant('companyListApi','http://localhost:8000/finanse/api/list/')
.constant('tempPatientApi','http://localhost:8000/pacjent/api/nowyPacjent/')
.factory('ModelUtils', ModelUtils)
.factory('newPatientFormApi',newPatientFormApi )
.factory('companyApi', companyApi)
.factory('mySharedService', mySharedService)
.controller('PacjentCtrl', PacjentCtrl)
.controller('NewPatientCtrl', NewPatientCtrl)
.controller('ModalInstanceCtrl', ModalInstanceCtrl)
.config(function($interpolateProvider, $httpProvider) {
$interpolateProvider.startSymbol('{[{');
$interpolateProvider.endSymbol('}]}');
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
})
The interesting thing is that this code works perfect on my colleague's system (Windows 7, Chrome) - the user data is gathered perfectly. However, I've tested it on three different systems (Windows 7 x64, Xubuntu 14.04, Ubuntu 14) and several browsers (Firefox, Chromium) on my PCs and the same error occurs.
Thank you a lot for any comments and advice. Sorry also for any non-professional statements.
it is because of this line:
user=request.user
# ...
therapist = Therapist.objects.get(user = user),
you are trying to get a therapist from your database with an Anynomous user in your ORM - it means a user who is not logged in.
you need is_authenticated() in your check:
if request and hasattr(request,"user") and request.user.is_authenticated():
user=request.user
newTherapyGroup = TherapyGroup.objects.create(
start = therapy_start,
patient = newPatient,
therapist = Therapist.objects.get(user=user),
company = validated_data['company']
)
newTherapyGroup.save()

Overriding validation for Django for base64 string for model.imagefield

I am using Angular and Bootstrap to serve my forms. If a user uploads an image, Angular serves it in the "data:" format, but Django is looking for a file type. I have fixed this issue by overriding both perform_authentication (To modify the image to a file) and perform_create (to inject my user_id). Is there a better way to override?
I'd rather not override my view. I'd rather override the way Django validates ImageFields. What I want to do is check if the passed value is a 64-bit string, if it is, modify it to a file type, then validate the ImageField. The below code works as is, I just don't feel is optimal.
Here is my view:
class UserCredentialList(generics.ListCreateAPIView):
permission_classes = (IsCredentialOwnerOrAdmin,)
serializer_class = CredentialSerializer
"""
This view should return a list of all the purchases
for the currently authenticated user.
"""
def get_queryset(self):
"""
This view should return a list of all models by
the maker passed in the URL
"""
user = self.request.user
return Credential.objects.filter(member=user)
def perform_create(self, serializer):
serializer.save(member_id=self.request.user.id)
def perform_authentication(self, request):
if request.method == 'POST':
data = request.data.pop('document_image', None)
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:
import imghdr
file_extension = imghdr.what(file_name, decoded_file)
file_extension = "jpg" if file_extension == "jpeg" else file_extension
complete_file_name = "%s.%s" % (file_name, file_extension,)
data = ContentFile(decoded_file, name=complete_file_name)
request.data['document_image'] = data
request.user
And here is my serializer:
class CredentialSerializer(serializers.ModelSerializer):
class Meta:
model = Credential
fields = (
'id',
'credential_type',
'credential_number',
'date_received',
'is_verified',
'date_verified',
'document_image',
)
And here is my model:
class Credential(models.Model):
"""Used to store various credentials for member validation."""
document_image = models.ImageField(
upload_to=get_upload_path(instance="instance",
filename="filename.ext",
path='images/credentials/'))
PASSENGER = 'P'
OWNER = 'O'
CAPTAIN = 'C'
CREDENTIAL_CHOICES = (
(PASSENGER, 'Passenger'),
(OWNER, 'Owner'),
(CAPTAIN, 'Captain'),
)
credential_type = models.CharField(max_length=1,
choices=CREDENTIAL_CHOICES,
default=PASSENGER)
credential_number = models.CharField(max_length=255)
date_received = models.DateTimeField(auto_now_add=True)
is_verified = models.BooleanField(default=False)
date_verified = models.DateTimeField(blank=True, null=True)
member = models.ForeignKey(settings.AUTH_USER_MODEL,
related_name='credentials')
I used the below link to help me, now I just want to figure out how override the proper method
Django REST Framework upload image: "The submitted data was not a file"
Well I've made one change since making: I have moved this function to my serializer and instead I now override the method: is_valid and that works as well. At least it's not in my view anymore.

GAE + Cloud Storage - Unable to get FileInfo after File is uploaded

I am using Flask Web Framework on GAE/Python. After uploading a file to Cloud Storage I want to get a reference to the file so that it can be served. I can't get the parse_file_info to work. I've searched long and hard and spent over two days trying to make this work. I'm at my wit's end!! You can see my handlers below:
#app.route('/upload_form', methods = ['GET'])
def upload_form():
blobupload_url = blobstore.create_upload_url('/upload', gs_bucket_name = 'mystorage')
return render_template('upload_form.html', blobupload_url = blobupload_url)
#app.route('/upload', methods = ['POST'])
def blobupload():
file_info = blobstore.parse_file_info(cgi.FieldStorage()['file'])
return file_info.gs_object_name
The data is encoded in the payload of uploaded_file you retrieve after uploading a blob. This is example code on how to extract the name:
import email
from google.appengine.api.blobstore import blobstore
def extract_cloud_storage_meta_data(file_storage):
""" Exctract the cloud storage meta data from a file. """
uploaded_headers = _format_email_headers(file_storage.read())
storage_object_url = uploaded_headers.get(blobstore.CLOUD_STORAGE_OBJECT_HEADER, None)
return tuple(_split_storage_url(storage_object_url))
def _format_email_headers(raw_headers):
""" Returns an email message containing the headers from the raw_headers. """
message = email.message.Message()
message.set_payload(raw_headers)
payload = message.get_payload(decode=True)
return email.message_from_string(payload)
def _split_storage_url(storage_object_url):
""" Returns a list containing the bucket id and the object id. """
return storage_object_url.split("/")[2:4]
#app.route('/upload', methods = ['POST'])
def blobupload():
uploaded_file = request.files['file']
storage_meta_data = extract_cloud_storage_meta_data(uploaded_file)
bucket_name, object_name = storage_meta_data
return object_name

effective counting of objects

I have 2 models:
Category(models.Model):
name = models.CharField(max_length=30)
no_of_posts = models.IntegerField(default=0) # a denormalised field to store post count
Post(models.Model):
category = models.ForeignKey(Category)
title = models.CharField(max_length=100)
desc = models.TextField()
user = models.ForeignKey(User)
pub_date = models.DateTimeField(null=True, blank=True)
first_save = models.BooleanField()
Since I always want to show the no. of posts alongwith each category, I always count & store them every time a user creates or deletes a post this way:
## inside Post model ##
def save(self):
if not pub_date and first_save:
pub_date = datetime.datetime.now()
# counting & saving category posts when a post is 1st published
category = self.category
super(Post, self).save()
category.no_of_posts = Post.objects.filter(category=category).count()
category.save()
def delete(self):
category = self.category
super(Post, self).delete()
category.no_of_posts = Post.objects.filter(category=category).count()
category.save()
........
My question is whether, instead of counting every object, can we not use something like:
category.no_of_posts += 1 // in save() # and
category.no_of_posts -= 1 // in delete()
Or is there a better solution!
Oh, I missed that! I updated the post model to include the relationship!
Yes, a much better solution:
from django.db.models import Count
class CategoryManager(models.Manager):
def get_query_set(self, *args, **kwargs):
qs = super(CategoryManager, self).get_query_set(*args, **kwargs)
return qs.annotate(no_of_posts=Count('post'))
class Category(models.Model):
...
objects = CategoryManager()
Since you didn't show the relationship between Post and Category, I guessed on the Count('posts') part. You might have to fiddle with that.
Oh, and you'll want to get rid of the no_of_posts field from the model. It's not necessary with this. Or, you can just change the name of the annotation.
You'll still be able to get the post count with category.no_of_posts but you're making the database do the legwork for you.

Resources