简体   繁体   English

Django / Django Rest Framework-如何允许模型序列化程序将模型的外键字段设置为null?

[英]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. 预先感谢您提供的任何帮助。

From the docs : 文档

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.

相关问题 Django Rest Framework我不能使用具有外键的序列化器保存模型 - Django Rest Framework I can't use Serializer save model of have foreign key 如何获取外键模型的字段出现在Django序列化器中? - How to get a field of a foreign key Model appear in a Django-Serializer? 如何在 Django Rest Framework 中为作为另一个模型上的外键的模型添加附加字段 - How to add additional field in Django Rest Framework for a model that is a foreign key on another model 如何在 Django REST 框架序列化程序中获取超链接外键? - How do I get a hyperlinked foreign key in Django REST Framework serializer? 在序列化器中编辑外键字段-Django Rest Framework - Editing the foreign key field in Serializer - Django Rest Framework 如何从 django 的外键模型字段中获取干净的数据? - How do I get clean data from foreign-key model's field in django? 如何使用Django REST框架与外键的默认值模型? - How to use Django REST framework with a model with default value for foreign key? 如何编写django-rest-framework序列化程序以保存包含通用模型的嵌套层次结构? - How do I write a django-rest-framework serializer to save a nested hierarchy containing a generic model? django rest框架外键序列化器问题 - django rest framework foreign key serializer issue 如何在包含另一个序列化程序(模型)、django rest 框架的序列化程序中创建自定义列表字段? - How to create custom list field in serializer, which contains another serializer(model), django rest framework?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM