无法使用 Django REST 框架从多个选择元素中发布 JSON 数据

Posted

技术标签:

【中文标题】无法使用 Django REST 框架从多个选择元素中发布 JSON 数据【英文标题】:Unable to POST JSON data from multiple select element with Django REST Framework 【发布时间】:2019-12-29 18:47:54 【问题描述】:

我希望能够向我的 API 端点发送 AJAX POST 请求,以创建我的Asset 模型的新实例,其中在我的Asset 模型中引用了多个类别实例,因此是多对多字段输入我的Asset 模型。

我能够成功发布并创建新的Asset 实例,但是我的category 字段根本不接受任何数据。创建新的Asset 实例时,类别字段保持为空。我认为这与我的CategorySerializer 有关。我仍在学习如何使用 Django REST Framework,所以如果我能得到一些帮助来弄清楚如何在 Django REST Framework 中使用序列化程序,我将不胜感激。

我已经尝试修改 AssetSerializer create 方法来处理解析 JSON 和验证数据,但没有奏效。我还尝试了我在 *** 上找到的其他帖子中建议的其他解决方案,但没有找到适合我情况的任何解决方案。

这是我的serializers.py 文件:

class CategorySerializer(serializers.ModelSerializer):
    name = serializers.CharField(required=False, read_only=True)

    class Meta:
        model = Category
        fields = ('id', 'name')

class AssetSerializer(serializers.ModelSerializer):
    name = serializers.CharField(allow_null=True)
    description = serializers.CharField(allow_null=True)
    manufacturer = serializers.CharField(allow_null=True)
    uid = serializers.UUIDField(read_only=True, allow_null=True)
    borrower = BorrowerSerializer(allow_null=True, read_only=True)
    condition = serializers.ChoiceField(choices=Asset.CONDITION_TYPE, default='g', allow_null=True)
    owner = serializers.ReadOnlyField(source='owner.username')
    return_date = serializers.DateField(allow_null=True)
    checked_out = serializers.BooleanField(allow_null=True)
    category = CategorySerializer(required=False, many=True)


    class Meta:
        model = Asset
        fields = ('uid',
                  'name', 
                  'manufacturer', 
                  'model',
                  'description',
                  'owner',
                  'condition',
                  'category',
                  'borrower',
                  'checked_out',
                  'return_date',
                  'is_dueback',
        )

    def update(self, instance, validated_data):
        instance.borrower = validated_data.get('borrower', instance.borrower)
        instance.return_date = validated_data.get('return_date', instance.return_date)
        instance.checked_out = validated_data.get('checked_out', instance.checked_out)

        instance.name = validated_data.get('name', instance.name)
        instance.manufacturer = validated_data.get('manufacturer', instance.manufacturer)
        instance.model = validated_data.get('model', instance.model)
        instance.description = validated_data.get('description', instance.description)
        instance.condition = validated_data.get('condition', instance.condition)
        instance.category = validated_data.get('category', instance.category)
        instance.save()
        return instance

    def create(self, validated_data):
        return Asset.objects.create(**validated_data)

这是我的Asset 模型:

class Asset(models.Model):
    """Model representing an Asset"""
    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(settings.AUTH_USER_MODEL, 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)])

这是我的Category 模型:

class Category(models.Model):
    """Model representing an Asset category"""
    name = models.CharField(max_length=128)

    def __str__(self):
        return self.name

如果您能提供任何帮助,我将不胜感激。提前谢谢你。

【问题讨论】:

所以你的问题是ManyToManyField 不起作用? 您知道您不需要在序列化程序类中定义每个字段,对吧?你只需创建class Meta,至少我就是这样创建我的 API 【参考方案1】:

我几乎是 DRF 的新手,但我会尽力提供帮助。为什么在使用ModelsSerializer 时在序列化程序中编写所有字段?不需要告诉ModelSerializer 应该是什么类型的字段,因为您指向class Meta 中的模型并且DRF 知道字段和类型等。第二个关于序列化程序中的allow_null=True,当模型没有null=True时,你不能除了DRF可以创建一个不可为空的字段,例如null=True所以如果你不想一个字段可以为空,只需添加null=TrueModel 类中。对于您关于 ManytoMantry 字段的问题,请尝试在序列化程序中将 Primary key relation 用于 ManyToMany 字段,然后在列表中传递 Category 实例的 id:

class AssetSerializer(serializers.ModelSerializer):
    borrower = BorrowerSerializer(allow_null=True, read_only=True)
    category =  serializers.PrimaryKeyRelatedField(many=True, queryset=Category.objects.all())


    class Meta:
        model = Asset
        fields = ('uid',
                  'name', 
                  'manufacturer', 
                  'model',
                  'description',
                  'owner',
                  'condition',
                  'category',
                  'borrower',
                  'checked_out',
                  'return_date',
                  'is_dueback',
        )
     read_only_fields = ( 'uid' , ) # this fields will be read_only 

取决于您在视图中如何使用此序列化程序,saveupdate 有不同的方式。如果您的视图是generics 类,那么createupdate 本身将通过POSTPUT 方法进行。对于不属于generics DRF 视图的其他类视图,您可以使用@987654340 @创建一个新的实例。希望对您有所帮助。 传递数据类似于:


  "name" : "foo",
  "manufacture" : "foo",
  .
  .
  .
  "category" : [1,2,3,24,65]

【讨论】:

以上是关于无法使用 Django REST 框架从多个选择元素中发布 JSON 数据的主要内容,如果未能解决你的问题,请参考以下文章