Nested Models in Serializer django - django

I cannot get the last measurement for each device based on the device's ID from the measurement. If someone can advise me on how to implement this?
Models
class Devices(models.Model):
deviceid = models.AutoField(db_column='deviceId', primary_key=True) # Field name made lowercase.
devicename = models.CharField(db_column='deviceName', unique=True, max_length=128) # Field name made lowercase
devicestatus = models.IntegerField(db_column='deviceStatus') # Field name made lowercase.
Class Meta:
managed = False
db_table = 'devices'
class Measurements(models.Model):
measurementid = models.AutoField(db_column='measurementId', primary_key=True) # Field name made lowercase.
deviceid = models.ForeignKey(Devices, models.DO_NOTHING, related_name="measurment_details", db_column='deviceId') # Field name made lowercase.
measurement = models.CharField(max_length=64, blank=True, null=True)
class Meta:
managed = False
get_latest_by = 'measurementtime'
db_table = 'measurements'
Serializer
class MeasurmentsSerializer(serializers.ModelSerializer):
class Meta:
model = Measurements
fields = ('measurementid','measurement')
class DeviceSerializer(serializers.ModelSerializer):
latestmeasurment = serializers.SerializerMethodField()
count = 0
def get_latestmeasurment(self, obj):
qs = Measurements.objects.using('###').last()
serializer = MeasurmentsSerializer(instance=qs, many=False)
self.count = 1 + self.count
print(self.count , serializer.data )
return serializer.data
class Meta:
model = Devices
fields = ("devicename", 'latestmeasurment')
Views
class RetrieveAllDevicesView(viewsets.ModelViewSet):
http_method_names = ['get']
permission_classes = [permissions.IsAuthenticated]
serializer_class = DeviceSerializer
queryset = Devices.objects.using('###')
In serializer, you can see the count for primitive debug:
1 {'measurementid': 2942080, 'measurement': '35.0'}
2 {'measurementid': 2942080, 'measurement': '35.0'}
3 {'measurementid': 2942080, 'measurement': '35.0'}
4 {'measurementid': 2942080, 'measurement': '35.0'}
5 {'measurementid': 2942080, 'measurement': '35.0'}
6 {'measurementid': 2942080, 'measurement': '35.0'}
7 {'measurementid': 2942080, 'measurement': '35.0'}
8 {'measurementid': 2942080, 'measurement': '35.0'}
9 {'measurementid': 2942080, 'measurement': '35.0'}
10 {'measurementid': 2942080, 'measurement': '35.0'}
Response in JSON from view:
enter image description here

def get_latestmeasurment(self, obj):
device_measurements = obj.measurment_details.all()
last_measurement = device_measurements.order_by('id').last()
serializer = MeasurmentsSerializer(last_measurement)
return serializer.data
you get all measurments for each device and after sorting it you'll get the last one as your last_measurment

Related

Check the current values of instance while doing perform_update in django rest framework

I'm using Django Rest Framework.
Here is model:
class TimeSlot(models.Model):
date_start = models.DateTimeField(default=None, null=True, blank=True)
booked = models.BooleanField(default=False)
user = models.ForeignKey(User, related_name='time_slots', on_delete=models.SET_NULL, default=None)
Here is my serializer:
class CreateBookingSerializer(serializers.ModelSerializer):
class Meta:
model = TimeSlot
fields = ('id','booked','user',)
extra_kwargs = {'booked': {'required': True}}
Here is my view:
class CreateBookingViewSet(viewsets.ModelViewSet):
queryset = TimeSlot.objects.all()
serializer_class = CreateBookingSerializer
http_method_names = ['put']
def perform_update(self, serializer):
if (self.request.data['booked'] == 1):
serializer.save(user=self.request.user, booked=True)
I want to set booked to true only if the current value is False.
I'm using PUT method. so my url is /create_booking/id/
If I could get the id in my view, I would check the current booked value! How to get the id?
You can try to use self.kwargs['id'].
class CreateBookingViewSet(viewsets.ModelViewSet):
queryset = TimeSlot.objects.all()
serializer_class = CreateBookingSerializer
http_method_names = ['put']
def perform_update(self, serializer):
id = self.kwargs['id']
if (self.request.data['booked'] == 1):
serializer.save(user=self.request.user, booked=True)

optimise django sql query

I'm using Django 2.x.
I have two models
class AmountGiven(models.Model):
contact = models.ForeignKey(Contact, on_delete=models.PROTECT)
amount = models.FloatField(help_text='Amount given to the contact')
interest_rate = models.FloatField(blank=True, default=None, null=True)
given_date = models.DateField(default=timezone.now)
total_due = models.FloatField(blank=True, default=0.0, editable=False)
class AmountReturned(models.Model):
amount_given = models.ForeignKey(AmountGiven, on_delete=models.CASCADE, blank=True)
amount = models.FloatField()
return_date = models.DateField(default=date.today)
Use case
There can be multiple records of the amount given to a contact
There can be multiple records of the returned amount for an amount given
Now, I want to get total_due amount for a particular contact. This includes
total_payable = total_given + interest
total_due = total_payable - total_returned
To calculate total_due and interest, I have defined few property methods in the AmountGiven model.
#property
def interest_to_pay(self):
if self.interest_rate:
simple_interest_amount = ...
return simple_interest_amount
return 0
#property
def total_payable(self):
return self.amount + self.interest_to_pay
#property
def amount_due(self):
total_due = self.total_payable - self.total_returned
self.total_due = total_due
self.save()
return total_due
#property
def total_returned(self):
returned_amount = self.amountreturned_set.aggregate(total_returned=Sum('amount'))['total_returned']
if not returned_amount:
returned_amount = 0
return returned_amount
In Contact model, there is a property method to get the total due amount for the contact.
#property
def amount_due(self):
total_due = 0
for due in self.amountgiven_set.all():
total_due += due.amount_due
return total_due
Query
ContactSerializer
class ContactMinSerializer(serializers.ModelSerializer):
class Meta:
model = Contact
fields = (
'id', 'first_name', 'amount_due', 'created', 'modified'
)
Since amount_due property is being used in the ContactSerializer, amount_due property is called everytime a contact is call and thus results in nested DB queries.
How can I optimise the above scenario in the application to reduce the DB queries while getting contact or list of contacts? Specially two properties amount_due and total_returned.
amount_due() updates the total_due field in the table, every time it is called.
Edit 2
class ContactViewSet(LoggingMixin, viewsets.ModelViewSet):
serializer_class = ContactMinSerializer
def get_queryset(self):
return Contact.objects.filter(user=self.request.user).annotate(
total_due=Sum(
F('amountgiven_set__total_payable')
- F('amountgiven_set__total_returned')
)
).order_by('first_name')
You're looking for annotations.
Your viewset should define a queryset as follows:
from django.db.models import F, Sum
Contact.objects.annotate(
total_due=Sum(
F('amountgiven_set__total_payable')
- F('amountgiven_set__total_returned')
)
)
Then define a MethodSerializer field on your serializer to account for it.
class ContactMinSerializer(serializers.ModelSerializer):
total_due = serializers.SerializerMethodField()
def get_total_due(self, obj):
return return self.total_due
class Meta:
model = Contact
fields = (
'id', 'first_name', 'created', 'modified',
'total_due',
)

How to filter or query using abstract parent class in Django model?

This one is interesting to solve. I am building a module to register address for hospital, medical store and doctors. There is an abstracted model PrimaryAddress and a subclass called MedicalStorePrimaryAddress, and more subclasses will use the same abstracted model. I am using django rest framework to get the listings based on proximity (latitude, longitude and city). Now how could I filter it all using parent class, i.e PrimaryAddress model as I want to filter all the entities, i.e hospital, medical store and doctor nearby.
I have looked into django-polymorphic library but it doesnt help with geodjango and abstract class.
Any help suggestion is appreciated. Thanks
Here is the code sample:
# MODELS
class PrimaryAddress(gismodels.Model):
street = gismodels.CharField(max_length=255)
city = gismodels.CharField(max_length=60)
state = gismodels.CharField(max_length=100,
choices=settings.US_STATES,
default="CT")
landmark = gismodels.TextField()
latitude = gismodels.FloatField(null=True, blank=True)
longitude = gismodels.FloatField(null=True, blank=True)
location = gismodels.PointField(null=True, blank=True)
objects = gismodels.GeoManager()
def __unicode__(self):
return self.street
class Meta:
verbose_name = "Address"
verbose_name_plural = "Addresses"
abstract = True
def save(self, *args, **kwargs):
if self.latitude and self.longitude:
self.location = Point(self.longitude, self.latitude)
super(PrimaryAddress, self).save(*args, **kwargs)
class MedicalStoreAddress(PrimaryAddress):
medical_store = gismodels.OneToOneField(MedicalStore, related_name="medical_store_address",
on_delete=gismodels.CASCADE, null=True, blank=True)
# objects = gismodels.GeoManager()
def __unicode__(self):
return self.street
class Meta:
verbose_name = "Medical Store Address"
verbose_name_plural = "Medical Store Addresses"
def save(self, *args, **kwargs):
if self.latitude and self.longitude:
self.location = Point(self.longitude, self.latitude)
super(MedicalStoreAddress, self).save(*args, **kwargs)
# VIEW
class ProximityFilter(ListAPIView):
serializer_class = AddressSerializer
# authentication_classes = (authentication.TokenAuthentication, authentication.SessionAuthentication,)
# permission_classes = (permissions.IsAuthenticated,)
pagination_class = StandardResultsSetPagination
def get_queryset(self):
longitude = self.kwargs.get('longitude')
latitude = self.kwargs.get('latitude')
city = self.kwargs.get('city')
current_point = GEOSGeometry('POINT(%s %s)' % (longitude, latitude), srid=4326)
# raise
queryset = MedicalStoreAddress.objects.filter(city__iexact=city, location__distance_lte=(current_point, D(mi=700000000))).distance(
current_point).order_by('distance')
return queryset
# SERIALIZER
class AddressSerializer(HyperlinkedModelSerializer):
class Meta:
model = DoctorPrimaryAddress
fields = ('pk', 'street', 'latitude', 'longitude', 'city')
This paste expires on 2018-03-29 21:26:23. View raw. Remove now (Why am I seeing this?) Pasted through web.

Django Restful Api of ManytoMany models to show the foreign objects

The "Brand" object is foreign key of "company",they are ManytoMany relationship,and Brand object exists the field "company_Group"
the models are as follows:
class Brand(models.Model):
Company_Group = models.ManyToManyField(Company)
Brand_Group = models.CharField(u'Brand Group',max_length=255, default="")
Pref_Brand_Name_Flg = models.CharField(u'Preferred Name Flag',max_length=255, default="")
Pref_Brand_Name = models.CharField(u'Preferred Name',max_length=255, default="")
PrimaryContact = models.ForeignKey(UserRole, null=True, blank=True)
class Company(models.Model):
Pref_Company_Name_Flg = models.CharField(u'Preferred Name Flag',max_length=255, default="")
Pref_Company_Name = models.CharField(u'Preferred Name',max_length=255, default="")
Company_Type = models.CharField(u'Company Type',max_length=255, default="")
serializers
class BrandSerializer(serializers.ModelSerializer):
class Meta:
model = Brand
fields = '__all__'
the Serializer as follows ,data_export_setting.Company_form_stand is the field as
class CompanySerializer(serializers.HyperlinkedModelSerializer):
Brand = BrandSerializer(source='brand', read_only=True)
class Meta:
model = Company
Company_form_stand=['id', 'Brand', 'Company_Type','Company_Name','company_Name_SC']
fields = data_export_setting.Company_form_stand
depth = 2
def create(self, validated_data):
return Company.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.__dict__.update(**validated_data)
instance.save()
return instance
the viewset are as follows
class BrandViewSet(viewsets.ModelViewSet):
queryset = Brand.objects.all()
serializer_class = BrandSerializer
model = Brand
def get_serializer(self, *args, **kwargs):
if 'data' in kwargs:
data = kwargs['data']
if isinstance(data, list):
kwargs['many'] = True
return super(BrandViewSet, self).get_serializer(*args, **kwargs)
class CompanyViewSet(viewsets.ModelViewSet):
queryset = Company.objects.all()
serializer_class = CompanySerializer
and I want to show the company objects with Brand objects ,however,it seems to ignore the brand object and its field
appreciate any help ,thanks
Try,
Brand = BrandSerializer(source='brand_set', read_only=True, many=True)
Since, you have defined the field relation as ManyToMany, more than one Brand objects are related to a single Company instance. By using the reverse relation, you can access them in your serializer, and many=True lets the serializer handle multiple objects in the relation.

Django REST nested objects validate

My database:
User
-----------------------------------
id | name
-----------------------------------
1 | Phuong Vu
-----------------------------------
Profile
-----------------------------------
user_id | phone_number
-----------------------------------
1 | 123456
-----------------------------------
My models:
class User(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
class Profile(models.Model):
user = models.OneToOneField(User, primary_key=True)
phone_number = models.CharField(max_length=15, unique=True, blank=True)
My serializers:
class ProfileSerializer(serializers.ModelSerializer):
def validate(self, attrs):
##################################
# I want get current instance here
##################################
print self.instance
return attrs
class Meta:
model = Profile
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer(many=False)
class Meta:
model = User
This is in my view, I called is_valid 2 times in 2 ways to test:
profile_data = {
'phone_number':'123456'
}
user = User.objects.get(pk=1)
profile = Profile.objects.get(user_id=1)
setattr(user, 'profile', profile)
data = {
'profile': profile_data
}
serializer = UserSerializer(
user,
data=data,
partial=True
)
# This said 'Profile phone number is exist'
# because ProfileSerialiser.instance is None
serializer.is_valid()
# This is fine because ProfileSerialiser.instance is not None
profile_serialiser = ProfileSerialiser(profile, data=profile_data, partial=True)
profile_serializer.is_valid()
After create serializer instance, UserSerializer.instance is not None but children ProfileSerializer.instance is None.
So how can I fix this issue? (Access to self.instance in ProfileSerializer after it has created via UserSerialiser)