I have an API that can create testruns, but I need an instrument serial number to create it.
I would like to be able to have this POST request :
{
"serial_number":"4331214L"
"operator": "John Doe"
}
But, right now I have to do :
{
"instrument": {
"serial_number":"4331214L"
},
"operator": "John Doe"
}
current models:
class InstrumentModel(models.Model):
class Meta:
db_table = "instruments"
verbose_name = "Instrument"
serial_number = models.CharField(max_length=10, unique=True, db_index=True)
def __str__(self):
return self.serial_number
class TestRun(models.Model):
class Meta:
db_table = "test_runs"
verbose_name = "Test run"
operator = models.CharField(max_length=70)
instrument = models.ForeignKey(InstrumentModel, related_name="instruments", db_column="instrument", on_delete=models.CASCADE)
created_at = models.DateTimeField(db_index=True, default=timezone.now)
I tried with the depth meta field. That doesn't work. Maybe it's not at the serializer level?
class TestRunSerializer(serializers.ModelSerializer):
instrument = InstrumentSerializer()
class Meta:
model = TestRun
fields = ('operator', 'instrument')
depth = 1
def create(self, validated_data):
serial_number = validated_data.pop('serial_number')
instrument, _ = InstrumentModel.objects.get_or_create(serial_number=serial_number)
return TestRun.objects.create(**validated_data, instrument=instrument)
I think it can be right like that if you used to_internal_value
class TestRunSerializer(serializers.ModelSerializer):
instrument = InstrumentSerializer()
class Meta:
model = TestRun
fields = ('operator', 'instrument')
depth = 1
def to_internal_value(self, data):
serial_number = obj.get('serial_number')
if not serial_number:
raise serializers.ValidationError({
'serial_number': 'This field is required.'
})
data['insturment'] = {'serial_number': serial_number}
return data
Related
I want to design solution for ordering items. I have endpoint that create orders BUT I need to to have items object in the order. let me show you the code
class ItemModel(models.Model):
name = models.CharField(max_length=50)
price = models.FloatField()
discretion = models.CharField(max_length=500)
available = models.BooleanField(default=True)
class OrderModel(models.Model):
phone = models.CharField(max_length=20)
delevary_time = models.DateTimeField()
class CartModel(models.Model):
order = models.ForeignKey(OrderModel, on_delete=models.CASCADE, related_name='order_m')
item = models.ForeignKey(ItemModel, on_delete=models.CASCADE, related_name='item_m')
I need endpoint that create order to me. her what I did
class CartSerializer(serializers.ModelSerializer):
class Meta:
model = CartModel
exclude = ['order',]
depth = 2
class OrderSerializer(serializers.ModelSerializer):
cart = serializers.SerializerMethodField()
class Meta:
model = OrderModel
fields = ['phone', 'state', 'delevary_time', 'cart']
def get_cart(self, obj):
cart = CartModel.objects.filter(order__id=obj.id)
serializer = CartSerializer(cart, many=True)
return serializer.data
this is the endpoint
router.register('order', OrderViewSet, 'api-order')
{
"phone": 124997988698,
"delevary_time": "2020-07-17T19:34:00",
"cart": [
{
"item": 1
},
{
"item": 2
}
]
}
when I post the json it don't save the cart it only save the oder phone and delevary_time. How I can save the cart at the same time
class CartSerializer(serializers.ModelSerializer):
class Meta:
model = CartModel
exclude = ['order',]
depth = 2
class OrderSerializer(serializers.ModelSerializer):
order_m = CartSerializer(many=True) # adding this
class Meta:
model = OrderModel
fields = ['phone', 'state', 'delevary_time', 'order_m']
def create(self, validated_data):
cart_data = validated_data.pop('order_m')
order = OrderModel.objects.create(**validated_data)
for c in cart_data:
CartModel.objects.create(order=order, **c)
return order
when serialising a foreign key object, I'll get the object ID instead of the object. Any advise on how to get the object excluding the PK is greatly appreciated.
Output:
"biosamples": [
{
"short_form": "BTO_0004725",
"label": "embryonic fibroblast",
"ontology": 1
}
],
Models:
class Biosample(models.Model):
biosample_id = models.AutoField(primary_key=True)
ontology = models.ForeignKey('Ontology', models.DO_NOTHING, related_name='biosample_ontologies')
short_form = models.CharField(max_length=255, unique=True )
label = models.CharField(max_length=255)
class Meta:
managed = True
db_table = 'biosample'
def __str__(self):
return self.label
class Ontology(models.Model):
ontology_id = models.AutoField(primary_key=True)
name = models.CharField(unique=True, max_length=255)
short_name = models.CharField(max_length=255)
url = models.CharField(max_length=255)
base_url = models.CharField(max_length=255)
rest_base_url = models.CharField(max_length=255)
prefix = models.CharField(max_length=255, unique=True)
class Meta:
managed = True
db_table = 'ontology'
def __str__(self):
return self.name
Serializers:
class OntologieSerializer(base.ObjectSerializer):
class Meta:
model = Ontology
fields = '__all__'
class BiosampleSerializer(base.ObjectSerializer):
class Meta:
model = Biosample
fields = '__all__'
ontology = OntologieSerializer(hidden=['ontology_id'])
ObjectSerializer (Data is read from a spreadsheet, strings need to be empty to load):
class ObjectSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
data = super().to_representation(instance)
# Need empty string for loading
return {key: ('' if data[key] is None else value) for key, value in data.items()}
Thanks!
Indentation error, ontologie ended upin class Meta
class BiosampleSerializer(base.ObjectSerializer):
class Meta:
model = Biosample
fields = '__all__'
#Culprit:
ontology = OntologieSerializer(hidden=['ontology_id'])
Query :
I have a GET request which gives the data from the 2 models (single_tracklog_object in View). However, when I serialize this object instance using the serializers I am getting an empty data for devices as below.
{
"lat": "51.0038",
"lon": "8.0038",
"speed": 50,
"course": 5,
"device": {} # this needs to be having a value but is empty.
}
I am not understanding why its happening. Please guide me on this.
My Models :
class Tracklogs(models.Model):
tracklog_id = models.AutoField(primary_key=True)
device = models.ForeignKey(Tracking_devices, related_name='tracklogs')
lat = models.CharField(max_length=10, null=False)
lon = models.CharField(max_length=11, null=False)
.........
#timestamps
tracker_datetime = models.DateTimeField(blank=True, null=True)
class Meta:
get_latest_by = "tracker_datetime"
class Tracking_devices(models.Model):
device_id = models.AutoField(primary_key=True)
device_type = models.ForeignKey(Device_type)
user = models.ForeignKey(User, null=False)
name = models.CharField(max_length=100)
description = models.CharField(max_length=256, blank=True, null=True)
My View :
serializer_class = ShowLocationInfoSerializer
def get(self, request, *args, **kwargs):
# get the imei from the url
imei = self.kwargs['imei']
try:
single_tracklog_object = Tracklogs.objects.filter(device__imei = imei).values('lat', 'lon','speed','course','device','device__name').latest()
# Here its causing problem!!!
serializer = self.serializer_class(single_tracklog_object)
return Response(serializer.data)
except ObjectDoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
My Serializer:
class Tracking_DeviceSerializer(serializers.ModelSerializer):
name = serializers.CharField(read_only=True)
class Meta:
model = Tracking_devices
fields = ('name')
class ShowLocationInfoSerializer(serializers.ModelSerializer):
lat = serializers.CharField(read_only=True)
lon = serializers.CharField(read_only=True)
speed = serializers.IntegerField(read_only=True)
course = serializers.FloatField(read_only=True)
device = Tracking_DeviceSerializer()
class Meta:
model = Tracklogs
fields = ('lat', 'lon', 'tracker_datetime', 'speed', 'course', 'device' )
Thanks in advance.
I have the following models:
class Asset(models.Model):
isin = models.CharField(max_length=100)
asset_type = models.CharField(max_length=50)
last_price = models.FloatField
security_weight = models.FloatField
update_date = models.DateTimeField
def __str__(self):
return self.isin
class Meta:
ordering = ('isin',)
class PortfolioElement(models.Model):
nominal = models.FloatField
weight = models.FloatField
asset = models.OneToOneField(
Asset,
on_delete=models.CASCADE,
primary_key=True,
)
def __str__(self):
return self.asset.isin
class Meta:
ordering = ('asset',)
class Portfolio(models.Model):
number = models.CharField(max_length=100)
update_date = models.DateTimeField
elements = models.ManyToManyField(PortfolioElement)
def __str__(self):
return self.number
class Meta:
ordering = ('number',)
class Client(models.Model):
number = models.CharField(max_length=100)
update_date = models.DateTimeField
portfolios = models.ManyToManyField(Portfolio)
def __str__(self):
return self.number
class Meta:
ordering = ('number',)
and the following serializer:
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = Client
fields = ('number', 'portfolios')
depth = 1
However, I would like to see the actual data in the portfolios (and portfolio elements). But when I try to make a GET request on an arbitrary Client (by the (Client).number field) I can only see the following:
{
"number": "28101317",
"portfolios": [
{
"id": 14,
"number": "5471-339425",
"elements": [
{
"asset": 326
},
{
"asset": 327
}, ... (and so on)
How can a tweak my code, so that I also can get the actual "asset" information?
/Niclas
You can try this:
class AssetSerializer(serializers.ModelSerializer):
class Meta:
model = Asset
fields = '__all__'
class PortfolioElementSerializer(serializers.ModelSerializer):
asset = AssetSerializer()
class Meta:
model = PortfolioElement
fields = ('nominal', 'weight', 'asset')
class PortfolioSerializer(serializers.ModelSerializer):
elements = PortfolioElementSerializer(many=True)
class Meta:
model = Portfolio
fields = ('number', 'update_date', 'elements')
class ClientSerializer(serializers.ModelSerializer):
portfolios = PortfolioSerializer(many=True)
class Meta:
model = Client
fields = ('number', 'portfolios')
I got events that happen at locations:
class Event(models.Model):
title = models.CharField(max_length=200)
date_published = models.DateTimeField('published date',default=datetime.now, blank=True)
date_start = models.DateTimeField('start date')
date_end = models.DateTimeField('end date')
def __unicode__(self):
return self.title
description = models.TextField()
price = models.IntegerField(null=True, blank=True)
tags = TaggableManager()
location = models.ForeignKey(Location, blank=False)
class Location(models.Model):
location_title = models.CharField(max_length=200)
location_date_published = models.DateTimeField('published date',default=datetime.now, blank=True)
location_latitude = models.CharField(max_length=200)
location_longitude = models.CharField(max_length=200)
location_address = models.CharField(max_length=200)
location_city = models.CharField(max_length=200)
location_zipcode = models.CharField(max_length=200)
location_state = models.CharField(max_length=200)
location_country = models.CharField(max_length=200)
location_description = models.TextField()
def __unicode__(self):
return u'%s' % (self.location_title)
I can get the results of all via:
class EventSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.Field()
class Meta:
model = Event
depth = 2
fields = ('url','id','title','date_start','date_end','description', 'price', 'location')
Which outputs:
{
"url": "http://localhost:8000/api/event/3/",
"id": 3,
"title": "Testing",
"date_start": "2013-03-10T20:19:00Z",
"date_end": "2013-03-10T20:19:00Z",
"description": "fgdgdfg",
"price": 10,
"location": {
"id": 2,
"location_title": "Mighty",
"location_date_published": "2013-03-10T20:16:00Z",
"location_latitude": "37.767475",
"location_longitude": "-122.406878",
"location_address": "119 Utah St, San Francisco, CA 94103, USA",
"location_city": "San Francisco",
"location_zipcode": "94103",
"location_state": "California",
"location_country": "United States",
"location_description": "Some place"
}
},
However, I don't want it to grab all fields, as I don't need all of them. How can I define what fields should be retrieved from my nested object? Thanks!
Serializers can be nested, so do something like this...
class LocationSerializer(serializers.ModelSerializer):
class Meta:
model = Location
fields = (...)
class EventSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.Field()
location = LocationSerializer()
class Meta:
model = Event
fields = ('url','id','title','date_start','date_end','description', 'price', 'location')
I have been to this and did not get a perfect solution, But I did something you may check for it.
This method will not create nested serializers
**class LocationSerializer(serializers.ModelSerializer):**
class Meta:
model = Location
fields = (...) #does not matter
exclude = (...) #does not matter
class EventSerializer(serializers.ModelSerializer):**
loc_field_1 = serializers.CharField(required=False,*source='location.loc_field_1'*)
loc_field_2 = serializers.CharField(required=False,*source='location.loc_field_2'*)
***#ADD YOUR DESIRE FIELD YOU WANT TO ACCESS FROM OTHER SERIALIZERS***
class Meta:
model = Event
fields =('url','id','title','date_start','date_end','description', 'price', 'location')
I found this question when I was trying to figure out how to exclude certain fields from a serializer only when it was being nested. Looks like Tasawer Nawaz had that question as well. You can do that by overriding get_field_names. Here's an example based on Tom Christie's answer:
class LocationSerializer(serializers.ModelSerializer):
class Meta:
model = Location
fields = (...)
exclude_when_nested = {'location_title', 'location_date_published'} # not an official DRF meta attribute ...
def get_field_names(self, *args, **kwargs):
field_names = super(LinkUserSerializer, self).get_field_names(*args, **kwargs)
if self.parent:
field_names = [i for i in field_names if i not in self.Meta.exclude_when_nested]
return field_names
class EventSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.Field()
location = LocationSerializer()
class Meta:
model = Event
fields = ('url','id','title','date_start','date_end','description', 'price', 'location')