链接到具有多个记录的创建时的现有记录

时间:2019-03-02 11:19:43

标签: python django django-rest-framework

我在两个模型(位置和标签)之间有很多关系。但是,标签表中似乎有不必要的重复。

例如,当使用退出标签创建新地点时,它会创建一个具有相同名称的重复标签并将其链接,而不是链接已经存在的标签。

我认为使名称字段在模型上唯一会有所帮助,但可以理解,在运行发布请求时会导致以下错误:

{"tags":[{"name":["tags with this name already exists."]},{"name":["tags with th
is name already exists."]}]}

序列化器

class PlaceTagSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Tags
        fields = ('name',)


class PlaceSerializerPost(serializers.ModelSerializer):
    tags = PlaceTagSerializer(many=True)

    class Meta:
        model = Place
        fields = ('title', 'lat', 'lon', 'tags', 'featured_image_url', 'created_at')

    def create(self, validated_data):
        tags_data = validated_data['tags']

        """
        Tags need to be deleted otherwise the place object will not save
        as they need to be handled separately.
        """
        del validated_data['tags']

        place = Place.objects.create(**validated_data)

        for tag_data in tags_data:
            place.tags.get_or_create(place=place, **tag_data)

        return place

模型

    class Tags(models.Model):
    name = models.CharField(max_length=200, unique=True)

    def __str__(self):
        return self.name

    class Meta:
        ordering = ('name',)


class Place(models.Model):
    title = models.CharField(max_length=800)
    lat = models.DecimalField(max_digits=20, decimal_places=10)
    lon = models.DecimalField(max_digits=20, decimal_places=10)
    featured_image_url = models.CharField(max_length=2000)
    created_at = models.DateTimeField(auto_now_add=True)
    tags = models.ManyToManyField(Tags)
    live = models.BooleanField(default=1)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ('title',)

1 个答案:

答案 0 :(得分:0)

问题出在您的get_or_create行上。首先,您正在现有的place.tags.all() QuerySet上调用该方法,并且由于要创建一个新位置,因此它将永远不会返回现有对象。

第二,get_or_create(defaults=None, **kwargs)有两组参数:

  • kwargs:要搜索的值,其中已经多余地包含了place,因为您已经在place.tags上进行了过滤。但实际上您是在说:找到具有相同的Tagtag_data的现有place对象。
  • defaults:将为新对象设置这些属性,但不会搜索。由于Tag只有一个字段,因此此处无需设置任何内容。

因此,您应该这样做:

tag, _ = Tag.objects.get_or_create(**tag_data)  
# I'm not sure what `tag_data` is, but it should be dictionary {'name': 'some tag name'}, if not:
tag, _ = Tag.objects.get_or_create(name=tag_data)
place.tags.add(tag)