Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Django REST框架创建和更新嵌套对象_Django_Django Rest Framework - Fatal编程技术网

Django REST框架创建和更新嵌套对象

Django REST框架创建和更新嵌套对象,django,django-rest-framework,Django,Django Rest Framework,我正在尝试创建或更新嵌套对象如果对象存在,我尝试使用create_或_update方法,现在create工作正常,但更新失败,并表示pk已经存在 我的模型: class ContentHotel(models.Model): hotel_id = models.IntegerField(unique=True, blank=True, primary_key=True) star = models.FloatField(blank=True, null=True) cl

我正在尝试创建或更新嵌套对象如果对象存在,我尝试使用create_或_update方法,现在create工作正常,但更新失败,并表示pk已经存在

我的模型:

class ContentHotel(models.Model):
    hotel_id = models.IntegerField(unique=True, blank=True, primary_key=True)
    star = models.FloatField(blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'content_hotels'
        ordering = ('hotel_id',)

    def __str__(self):
        return str(self.hotel_id)


class RateHotel(models.Model):
    rate_hotel_id = models.IntegerField(blank=True, unique=True, primary_key=True)
    content_hotel = models.ForeignKey(ContentHotel, on_delete=models.CASCADE, related_name='rate_hotels')
    source_code = models.CharField(max_length=20, blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'rate_hotels'
        ordering = ('rate_hotel_id',)

    def __str__(self):
        return str(self.rate_hotel_id)
我的序列化程序:

# To handle RateHotel object operations
class RateHotelSerializer(serializers.ModelSerializer):

    class Meta:
        model = RateHotel
        fields = __all__


# To handle nested object operations
class RateHotelSerializerTwo(serializers.ModelSerializer):

    class Meta:
        model = RateHotel
        fields = __all__
        read_only_fields = ('content_hotel',)


class ContentHotelSerializer(serializers.ModelSerializer):
    rate_hotels = RateHotelSerializerTwo(many=True)

    class Meta:
        model = ContentHotel
        fields = __all__

    def create(self, validated_data):
        rate_hotels_data = validated_data.pop('rate_hotels')
        hotel_id = validated_data.pop('hotel_id')
        content_hotel, created = ContentHotel.objects.update_or_create(hotel_id=hotel_id, defaults={**validated_data})

        for rate_hotel_data in rate_hotels_data:
            rate_hotel_id = rate_hotel_data.pop('rate_hotel_id')
            RateHotel.objects.update_or_create(rate_hotel_id=rate_hotel_id, content_hotel=content_hotel,
                                               defaults=rate_hotel_data)

        return content_hotel

    def update(self, instance, validated_data):
        rate_hotels_data = validated_data.pop('rate_hotels')
        rate_hotels = list(instance.rate_hotels.all())
        for key in validated_data:
            instance.key = validated_data.get(key, instance.key)
        instance.save()

        for rate_hotel_data in rate_hotels_data:
            rate_hotel = rate_hotels.pop(0)
            for key in rate_hotel_data:
                rate_hotel.key = rate_hotel_data.get(key, rate_hotel.key)
            rate_hotel.save()

        return instance
JSON:

如果我发送一个put请求来更新嵌套对象,那么content hotel部分工作正常,但是rate hotel部分仍然说“rate\u hotel\u id”已经存在


有人能帮我解决这个问题吗?我在网上找不到任何相关资料,提前谢谢

Hmmmm,这看起来您可能正在寻找“如果存在则更新”用例,Django有一个
get\u或\u create()
方法来执行您想要的操作,请参阅此处的文档以获取参考:

但是,对您来说,它可能看起来像这样:

id = 'some identifier that is unique to the model you wish to lookup'
content_hotel, created = RateHotel.objects.get_or_create(
    rate_hotel_id=rate_hotel_id, 
    content_hotel=content_hotel, 
    defaults=rate_hotel_data
)

if created:
   # means you have created a new content hotel, redirect a success here or whatever you want to do on creation!
else:
   # content hotel just refers to the existing one, this is where you can update your Model
我还建议删除
hotel\u id
hotel\u rate\u id
作为主键:

class ContentHotel(models.Model):
        hotel_id = models.IntegerField(unique=True, blank=True,)
        star = models.FloatField(blank=True, null=True)

        class Meta:
            managed = False
            db_table = 'content_hotels'
            ordering = ('hotel_id',)

        def __str__(self):
            return str(self.hotel_id)


    class RateHotel(models.Model):
        rate_hotel_id = models.IntegerField(blank=True, unique=True,)
        content_hotel = models.ForeignKey(ContentHotel, on_delete=models.CASCADE, related_name='rate_hotels')
        source_code = models.CharField(max_length=20, blank=True, null=True)

        class Meta:
            managed = False
            db_table = 'rate_hotels'
            ordering = ('rate_hotel_id',)

        def __str__(self):
            return str(self.rate_hotel_id)
update\u或\u create()
方法不接受主键,但可以接受其他唯一的数据库字段来执行更新:

因此,
更新或创建()
看起来是这样的:

obj, created = Person.objects.update_or_create(
    first_name='John', last_name='Lennon',
    defaults={'first_name': 'Bob'},
)

您的
create
代码看起来不错,但是您的
update
代码有一些更大的问题,我认为在我们知道真正的问题所在之前,您需要解决这些问题

    for key in validated_data:
        instance.key = validated_data.get(key, instance.key)
    instance.save()
在这里,您尝试循环验证数据中的值,并将该键的值分配给模型上的该属性。您实际要做的是将模型上的属性
key
设置为
validated\u data
中每个键的值。为了更好地说明这个问题,我将举一个例子来纠正这个问题:

    for key in validated_data:
        setattr(instance, key, validated_data.get(key, getattr(instance, key))
    instance.save()
在这里,我们不尝试设置
instance.key
,而是使用python内置方法
setattr
将属性的名称设置为与变量
key
的值相匹配的值,该值是从
验证的\u数据中提取的


不过,我不确定纠正这一点是否能解决您的问题。我会确保您正确地将请求发送到正确的url,并使用正确的头值来访问update方法。可能是Django Rest框架在幕后阻止了创建,因为它认为您正在以创建操作的形式发送请求,并且它已经找到了主键。

Hi Ziru-乍一看,您似乎在尝试更新酒店价格的主键……这是否正确?Hi Ziru-如果您是的,请看下面我的答案……:)你好,Micheal,谢谢你的回复,我不想更新主键,我只会更新主键以外的字段,但它给了我一个错误,即即使我保持主键不变,主键字段仍然存在。这就像你需要去掉主键覆盖并将它们设置为唯一键一样。再次您好,Ziru-如果您执行
RateHotel.objects.update\u或\u create(rate\u hotel\u id=rate\u hotel\u id,content\u hotel=content\u hotel),会发生什么
。。。什么是<代码>房价>酒店数据
?它是数组还是字符串?对于update_或_create方法,我使用了主键,这样我可以检查具有此主键的对象是否存在,如果存在,则更新,否则使用此主键创建一个新对象。我没有其他唯一字段来跟踪对象,您对此有什么解决方案吗?如果您知道要更新的模型的主键,一定要用这个!很遗憾,您无法通过传入主键来更新\u或\u create。所以做一个
get\u或\u create
,如果
created
False
,那么你知道你需要更新一个现有的模型。当你做一个
get\u或\u create()
的时候,你对主键和一些其他数据的查找会返回一个False的get(即使主键存在)…然后当它尝试创建时-当您尝试创建具有相同ID的对象时,它会抛出另一个错误(完整性错误)。因此,只需传入您希望
获取的对象的主键或\u create()
-然后,如前所述,如果创建的都是好的-如果创建的是假的,你知道它已经存在-然后只需更新你知道的与这个主键相关的数据。非常感谢你,唐。我将首先尝试使用
setattr
方法,看看它是否解决了问题。您是对的,创建工作正常,但似乎update\u或\u create方法只执行创建部分,即使对象存在,它仍在尝试创建对象。如果对象存在,update\u或create方法会调用我覆盖的update方法吗?我的猜测是,无论你认为你在做什么来获得你的
update
方法,都不会实现。你应该在那一点上放置一个
pdb
断点或其他东西,以确保你能到达那里。
    for key in validated_data:
        setattr(instance, key, validated_data.get(key, getattr(instance, key))
    instance.save()