I'm developing a Web App for a uni project and it's about airports and carriers...
The problem is when I try to feed to the database I'm doing in a parallel way because in the json file I'm using as the reference there is a lot of entries about carriers and airports.
When you update(PUT and PATCH) one by one in a sequential way it is working as it should but when I try PUT/PATCH parallel requests the instance in the DB is being overwritten every time.
Each airport has a list of carriers and when I tried to add more carriers to that list via PUT or PATCH in a parallel way it overwrites the instance previous carriers list
My models are:
class Carrier(models.Model):
code = models.CharField(max_length=10, primary_key=True)
name = models.TextField()
def __str__(self):
return self.name
class Airport(models.Model):
code = models.CharField(max_length=10, primary_key=True)
name = models.TextField()
carriers = models.ManyToManyField(Carrier, related_name='airports')
def __str__(self):
return self.name
Serializers:
class AirportListSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='airport-detail')
class Meta:
model = models.Airport
fields = ('code', 'name', 'url')
class AirportDetailSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='airport-detail')
class Meta:
model = models.Airport
fields = ('code', 'name', 'url', 'carriers')
And I'm having problems with my update method I had to override it because for appending new data to the carriers array of an instance of an airport:
def update(self, request, *args, **kwargs):
instance = self.get_object()
serializer = serializers.AirportDetailSerializer(
instance=instance,
data=request.data,
context={'request': request}
)
if serializer.is_valid(raise_exception=True):
# Getting the user inputed carriers after it was validated by the serializer
carriers = set(dict(request.data)['carriers'])
# Adding new carriers to the current airport list of carriers without deleting the old ones
for carrier in serializer.validated_data['carriers']:
print(carrier)
carriers.add(carrier)
print('Carriers %s' % carriers)
# Saving alterations to the db
serializer.save(carriers=carriers)
# Overriding the original data for more features
data = serializer.data
# Creating the carrier links
data['carriers'] = ['http://%s/api/carriers/%s/' % (request.get_host(), carrier) for carrier in data['carriers']]
return Response(data)
Every time you are calling serializer.save(carriers=carriers)
, you are saving the Airport
instance with only the carriers from your particular PUT/PATCH request...rather than adding carriers to your Airport
instance.
You should look at the docs for writable nested serializers and use a separate CarrierSerializer
.
On a related note, your update
logic is better suited as part of the AirportSerializer
, not your view. This makes it more reusable. That section of the DRF docs is the perfect example for you.
Something like this pseudo-code adapted from the Albums/Tracks example:
class AirportSerializer(serializers.ModelSerializer):
carriers = CarrierSerializer(many=True)
class Meta:
model = Airport
fields = ......
def update(self, instance, validated_data):
carriers_data = validated_data.pop('carriers')
for carrier in carriers_data:
Carrier.objects.update_or_create(airport=instance, defaults=carrier_data)
return instance