I want to be able to set the borrower
field (a foreign key) in my Asset
model to be NULL
but I can't seem to get it to work. I'm trying to send a PATCH request with JSON data that has the key borrower
equal to value of NULL
but the borrower
field won't get updated to NULL
for the model instance. Perhaps there is an issue with the serializer that is preventing the foreign key field from being able to be set to NULL
?
I have already tried passing in allow_null=True
to BorrowSerializer
class but that hasn't worked. I've searched high and low on StackOverflow for posts with similar problems and solutions but nothing I've tried has worked.
Here is my models.py:
from django.conf import settings
from django.db import models
from django.utils import timezone
from datetime import date
from django.contrib.auth.models import User
from django.urls import reverse
import uuid
class Category(models.Model):
"""Model representing an Asset category"""
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Borrower(models.Model):
first_name = models.CharField(max_length=64)
last_name = models.CharField(max_length=128)
associated_user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
def __str__(self):
return f'{self.first_name} {self.last_name}'
class Asset(models.Model):
"""Model representing an Asset"""
# Unique identifier for an instance of an asset (a barcode of sorts)
uid = models.UUIDField(primary_key=True, default=uuid.uuid4)
name = models.CharField(max_length=200)
manufacturer = models.CharField(max_length=64)
model = models.CharField(max_length=128)
description = models.TextField()
category = models.ManyToManyField(Category)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
borrower = models.ForeignKey(Borrower, on_delete=models.CASCADE, null=True, blank=True)
checked_out = models.BooleanField(default=False)
return_date = models.DateField(null=True, blank=True)
CONDITION_TYPE = (
('e', 'Excellent'),
('g', 'Good'),
('f', 'Fair'),
('p', 'Poor'),
)
condition = models.CharField(
max_length=1,
choices=CONDITION_TYPE,
blank=True,
help_text='Asset condition')
class Meta:
ordering = ['return_date']
@property
def is_dueback(self):
if self.return_date and date.today() > self.return_date:
return True
return False
def display_category(self):
"""Create a string for the Category. This is required to display category in Admin."""
return ', '.join(category.name for category in self.category.all())
display_category.short_description = 'Category'
def __str__(self):
return f'{self.uid} - {self.name}'
def get_absolute_url(self):
return reverse('asset-detail', args=[str(self.uid)])
Here is my serializers.py file:
from rest_framework import serializers
from inventory.models import Asset, Borrower, Category
class BorrowerSerializer(serializers.ModelSerializer):
class Meta:
model = Borrower
fields = ('first_name',
'last_name',
'associated_user'
)
def update(self, instance, validated_data):
print('Update method triggered.')
instance.first_name = validated_data.get('first_name', instance.first_name)
instance.last_name = validated_data.get('last_name', instance.last_name)
instance.associated_user = validated_data.get('associated_user'. instance.associated_user)
instance.save()
return instance
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = '__all__'
class AssetSerializer(serializers.ModelSerializer):
borrower = BorrowerSerializer(allow_null=True)
category = serializers.StringRelatedField(many=True)
condition = serializers.CharField(source='get_condition_display')
class Meta:
model = Asset
fields = ('name',
'manufacturer',
'model',
'description',
'condition',
'category',
'borrower',
'checked_out',
'return_date',
'is_dueback',
)
Here are my DRF API Views:
class AssetRetrieveUpdateDestroy(RetrieveUpdateDestroyAPIView):
lookup_field = 'uid'
serializer_class = AssetSerializer
def get_queryset(self):
user = self.request.user
return Asset.objects.filter(owner=user)
class BorrowerRetrieveUpdateDestroy(RetrieveUpdateDestroyAPIView):
lookup_field = 'id'
serializer_class = BorrowerSerializer
def get_queryset(self):
return Borrower.objects.all()
I expected the borrower
field in my Asset
model instance to be updated to NULL when I pass in this JSON:
data = {
'borrower': null
}
However, my model instance won't update the borrower
field when it's a foreign key. It works fine if the field is CharField
or something else, but on foreign keys. I printed out the data returned from my AJAX request but the borrower
field stays unchanged.
Thank you in advance for any help you can provide.
From the docs :
If you're supporting writable nested representations you'll need to write
.create()
or.update()
methods that handle saving multiple objects.
Thus you need to implement the .update()
method in your AssetSerializer
:
class AssetSerializer(serializers.ModelSerializer):
borrower = BorrowerSerializer(allow_null=True)
...
class Meta:
model = Asset
fields = (...)
def update(self, instance, validated_data):
instance.borrower = validated_data.get('borrower')
instance.save()
return instance
This should do the work. So no matter that you've passed allow_null=True
, it will accept null values , but won't update your nested relationship unless you define your custom update mechanism.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.