【问题标题】:Django Rest - ManyToManyField with SlugRelatedField Data Is Not Being CreatedDjango Rest - 未创建具有 SlugRelatedField 数据的 ManyToManyField
【发布时间】:2020-05-04 20:14:08
【问题描述】:

我的数据库中有以下结构:

{
        "name": "sum",
        "formula": "a+b",
        "date": "2020-01-17T19:02:24.143000Z",
        "tags": [
            "sum",
            "test"
        ],
        "latex": "a+b"
    }

“tags”Table Calculator 中具有 ManyToManyField 关系的字段。我使用了一个中间模型 (TagLink),它指定了计算器的外键和涉及多对多关系的标记模型。

型号:

class Tag(models.Model):
    name = models.CharField(max_length=25, primary_key=True, db_column='sTag')

    class Meta:
        db_table = 'tTag'

class Calculator(models.Model):
    name = models.CharField(max_length=100, primary_key=True, db_column='sName')
    formula = models.CharField(max_length=200, db_column='sFormula')
    date = models.DateTimeField(auto_now=True, db_column='dtModifiedDate')
    tags = models.ManyToManyField(Tag, through='TagLink', through_fields=('calculator', 'tag'), related_name='calculator', symmetrical=False)

    class Meta:
        db_table = 'tCalculator'

class TagLink(models.Model):
    calculator = models.ForeignKey(Calculator, on_delete=models.CASCADE, db_column='sCalculator')
    tag = models.ForeignKey(Tag, on_delete=models.CASCADE, db_column='sTag')

    class Meta:
        db_table = 'tTagLink'
        auto_created = True
        unique_together = [['calculator', 'tag']]

这是序列化器

class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = ['name']

class CalculatorSerializer(serializers.ModelSerializer):
    tags = serializers.SlugRelatedField(
        many=True, queryset=Tag.objects.all(), slug_field='name')

    class Meta:
        model = Calculator
        fields = ['name', 'formula', 'date', 'tags']

    def create(self, validated_data):
        tags = validated_data.pop('tags')
        calculadora = self.Meta.model.objects.create(**validated_data)

        for tag in tags:
        obj, _ = Tag.objects.get_or_create(name=tag)
        calculadora.tags.add(obj)

         calculadora.save()
         return calculadora

-> 我在 create() 方法中创建新“标签”时遇到问题;

(1)成功条件:如果标签已经存在于数据库(TagLink表)中,则创建成功:

(Pdb) calc_serializer.data
{'name': 't4', 'formula': 'r', 'date': '2020-01-17T18:54:18.448332Z', 'tags': ['erika'], 'inputs': [OrderedDict([('name', 'r'), ('calculatorName', 't4'), ('isCalculator', False), ('isArray', False), ('isMatrix', False)])]}

(2)失败条件:如果标签不存在于数据库中,则标签没有被创建,我得到以下错误“CalculatorNotFound”:

return CalculatorNotFoundException(logger, request_json['name']).response

Ps.:calc_serializer.data 正确返回。但是发生的事情是 calc_serializer 没有验证。

有人可以帮我解决这个错误吗?我花了很长时间试图找出答案! :/

非常感谢!!!

【问题讨论】:

    标签: django django-rest-framework many-to-many slug serialization


    【解决方案1】:

    我发现了错误! \o/

    我更正了失败条件(如果数据库中不存在该标签)。我做了以下事情: 在保存计算器之前,我首先将标签保存到数据库中。这样我就可以更新标签了!!!!

    for tag_name in request_json['tags']:
                tag_object = Tag.objects.get_or_create(name=tag_name)
                tag_serializer = TagSerializer(data={'name': tag_name}) # -> I save first to the database
    
            calc_serializer = CalculatorSerializer(data=request_json)
    
            if calc_serializer.is_valid():
                calc_serializer.save()
    
                response = JsonResponse(
                    calc_serializer.data, status=status.HTTP_201_CREATED)
    
                return response
    

    我特别感谢@DaviWesley 的帮助! :)

    【讨论】:

    • tmj!抱歉没有给出完整的答案我工作太忙了,我可能会建议对您的代码进行一些更改,当您执行 tag_object =Tag.objects.get_or_create(name=tag_name) 时,您正在获取现有标签或保存标签,您不需要将数据传递给 TagSerializer因为您已经拥有上一行中的对象,所以我只想更改为 TagSerializer(tag_object[0]) 想象一下,如果您有很多属性,则必须使用 data={attr1:8,attr2:737.... 逐个编写我会坚持使用 @来自 DRF 的 987654325@ 方法使用 serializer.save() 并不理想
    【解决方案2】:

    你的代码是说如果我有一个现有的标签与计算器建立关系,你不需要验证Tag是否存在你可以简单地使用get_or_createmethod来获取现有的Tag或创建一个新的,您还试图在Calculator 模型关系中添加string,请记住,在您的情况下,validated_data.pop('tags')stringslist,就像这样['erika']

    def create(self, validated_data):
            tags = validated_data.pop('tags')
            calculadora = self.Meta.model.objects.create(**validated_data)
    
            for tag in tags:
                # return the Tag object model
                obj, _ = Tag.objects.get_or_create(name=tag)
                calculadora.tags.add(obj)
    
            calculadora.save()
            return calculadora
    

    有用的学习人员:

    【讨论】:

    • 朋友你好!首先,非常感谢您花时间帮助我。我实现了您的解决方案,但不幸的是我得到了同样的错误:“CalculatorNotFoundException(logger, request_json['name']).response”。我在另一个线程link 中读到,DRF 提供的 SlugRelatedField 与许多相关字段一样,旨在与已经存在的对象一起使用。就我而言,我想添加存在/不存在的标签。这个解决方案适用于我的吗?谢谢
    • hmm...我误解了你的问题,get_or_create 方法可能会在获取现有对象时为你完成这项工作,但我不确定它为什么会引发 CalculatorNotFoundException,因为你的SlugRelatedField 没有链接到计算器模型,一旦我不知道 SlugRelatedField,我会尝试为你找到更好的解决方案
    • 既然 Tag 模型只有一个字段,为什么不直接使用 TagSerializer 呢?
    • 戴维,我发现了错误!!!!我在下面的帖子上发布了:)非常感谢您的帮助! \o/
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    • 2021-09-09
    • 1970-01-01
    • 2023-03-29
    • 2020-09-14
    相关资源
    最近更新 更多