[英]Django/Django Rest Framework - How do I allow model serializer to set model's foreign key field to null?
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. 我希望能够在我的Asset
模型中将borrower
字段(外键)设置为NULL
但似乎无法使其正常工作。 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. 我正在尝试使用具有密钥borrower
等于NULL
值的JSON数据发送PATCH请求,但是对于模型实例, borrower
字段不会更新为NULL
。 Perhaps there is an issue with the serializer that is preventing the foreign key field from being able to be set to NULL
? 也许序列化程序存在一个问题,即无法将外键字段设置为NULL
?
I have already tried passing in allow_null=True
to BorrowSerializer
class but that hasn't worked. 我已经尝试过将allow_null=True
传递给BorrowSerializer
类,但这没有用。 I've searched high and low on StackOverflow for posts with similar problems and solutions but nothing I've tried has worked. 我已经在StackOverflow的高处和低处搜索了具有类似问题和解决方案的帖子,但我尝试过的任何方法都没有奏效。
Here is my models.py: 这是我的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: 这是我的serializers.py文件:
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: 这是我的DRF API视图:
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: 当我传递此JSON时,我希望我的Asset
模型实例中的borrower
字段更新为NULL:
data = {
'borrower': null
}
However, my model instance won't update the borrower
field when it's a foreign key. 但是,我的模型实例是外键时,不会更新borrower
字段。 It works fine if the field is CharField
or something else, but on foreign keys. 如果该字段是CharField
或其他名称,但在外键上,则可以正常工作。 I printed out the data returned from my AJAX request but the borrower
field stays unchanged. 我打印了从我的AJAX请求返回的数据,但borrower
字段保持不变。
Thank you in advance for any help you can provide. 预先感谢您提供的任何帮助。
If you're supporting writable nested representations you'll need to write
.create()
or.update()
methods that handle saving multiple objects. 如果您支持可写的嵌套表示形式,则需要编写用于保存多个对象的.create()
或.update()
方法。
Thus you need to implement the .update()
method in your AssetSerializer
: 因此,你需要实现.update()
在你的方法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. 因此,无论您传递了allow_null=True
,它都将接受null值 ,但是除非您定义自定义更新机制,否则它不会更新嵌套关系。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.