我被认为应该是一个简单的模式一段时间。所以我将在这里分享我如何为遇到同样事情的其他人解决它。也许有些人会建议更好的解决方案。
为API使用Django Rest Framework,为前端使用Angular 1.5。
包括有关个人家庭的详细(嵌套)信息以及个人记录,以避免额外的网络往返,并且能够更改此人所属的家庭。
默认情况下,DRF很乐意提供相关模型的嵌套信息。但是,如果你改变其中任何一个,它就不会很高兴收回它。
Angular很乐意显示资源的嵌套信息,但其默认操作是在更新时以完全相同的嵌套格式发回所有资源数据。
这里的DRF设置并不起作用:
# Models
class Household(models.Model):
full_address = models.CharField(max_length=200, blank=True, default='')
class Person(models.Model):
household=models.ForeignKey(
'household.Household',
null=True,
related_name="persons",)
full_name=models.CharField(max_length=100)
# Views
class HouseholdViewSet(ModelViewSet):
model = Household
queryset = Household.objects.all()
serializer_class = HouseholdSerializer
class PersonViewSet(ModelViewSet):
model = Person
queryset = Person.objects.all()
serializer_class = PersonSerializer
# Serializers
class HouseholdSerializer(serializers.ModelSerializer):
class Meta:
model = Household
class PersonSerializer(serializers.ModelSerializer):
household = HouseholdSerializer(many=False, read_only=True)
class Meta:
model = Person
fields = ('id', 'household', 'full_name', )
当角度获取人员资源时,家庭ID和完整地址被嵌套,以便"家庭"现在是一个对象而不是主键。
{
"id": 42,
"full_name": "Lisa Adams",
"household": {
"id": 17,
"full_address": "123 Main st, Springfield, ST, 55555"
}
}
当Lisa离开家并与其他家庭中的新室友一起搬入时,用户将家庭更改为不同的现有地址,而角度发送PUT请求。服务器200响应指示成功,但新家庭不持久保存到数据库。因此,如果用户再次查看人员记录,它仍然有旧家庭。
这是在人员序列化程序中将home字段设置为read_only的结果。 DRF以静默方式忽略嵌套对象。
但如果将其更改为read_only = False,DRF会坚持必须包含明确的.update()。
AssertionError: The `.update()` method does not support writable
nestedfields by default. Write an explicit `.update()` method for serializer
我在写一个自定义更新功能已经工作了一段时间,但无法让它工作。我不需要更新嵌套信息中的任何内容。我只需要改变对不同家庭记录的引用。所有示例似乎都比需要的更复杂,我从来没有使用自定义update()来处理这个简单的用例。
当然,更新对外国记录的引用是很常见的,即使存在该记录的详细信息。但我没有找到任何正式记录的例子,我只是在试图修改SO和博客上的例子时坚持错过了一个或几个细节。
答案 0 :(得分:0)
由于DRF很乐意改变对家庭"如果它没有任何嵌套的细节,我通过离开"家庭"来解决更新它的问题。字段完整只是一个主键。然后我添加了一个新字段" household_details"使用PersonSerializer在新名称空间中提供详细信息。
class PersonSerializer(serializers.ModelSerializer):
household_details = HouseholdSerializer(many=False, read_only=True, source='household')
class Meta:
model = Person
fields = ('id', 'household', 'household_details', 'full_name',)
这会在同一个"家庭"创建一个新的字段点。模型,但由于它是read_only,DRF会在以角度提交回来时忽略它。
然后我只需要将我的角度控制器稍微复杂一点,以便从" household_details"现场并写信给"家庭"来自" household_details"的id字段的字段更新时。
<household-small-card household="person.household_detail"></household-small-card>
function update(new_household_detail) {
vm.person.household = new_household_detail.id;
vm.person.$update(function () {
toastr.success('Updated ' + vm.person.full_name + ' Successfully');
}, function (errorResponse) {
toastr.error('Failed: ' + errorResponse.data.message);
});
}
注意:此代码全部简化为我的工作代码。我没有确认它是否有效。但这里的概念应该更加清晰。以这种格式编写它有助于我在脑海中巩固解决方案。我希望它可以帮助其他人在这里。
答案 1 :(得分:0)
反向替代到@shanemgrey:
不是将_detail
附加到主对象(这是令人讨厌的IMO),而是可以翻转字段。使用household_id
作为您的ID字段,并将household
保留为您的对象字段:
class PersonSerializer(serializers.ModelSerializer):
household = HouseholdSerializer(read_only=True)
household_id = serializers.IntegerField()
class Meta:
model = Person
fields = ('id', 'household', 'household_id', 'full_name',)
DRF会自动将您的JSON中的household_id
链接到该对象,因此您无需执行任何其他操作。