我使用的是Django REST框架。我为库存系统中的项目创建了一个模型,也为项目本身之间的多对多关系创建了贯穿表(命名为子组件(,因此一个项目可以是其他项目的子部分,反之亦然。
我只是不确定我做得对,而且我似乎没有得到任何结果。当我访问诸如http://localhost:8000/api/subassemblies/2/,响应为
{"detail": "Not found."}
但我希望看到一个项目的所有子部分,或者";儿童";。PUT或任何其他类型的请求都具有相同的结果。
如果重要的话,当从管理页面访问子组件时,我可以很好地创建项目之间的关系。但一次只能有一个。我需要能够一次性编辑项目的所有子部分(至少在前端(。目前,请求主体的结构如下:
{
"parent_id": 2,
"children": [
{ "child_id": 5, "qty": 2 },
{ "child_id": 4, "qty": 3 },
]
}
这也允许我在特定项的子项上使用.set((,这很有用,因为我认为它还可以删除任何未包含在新集合中的先前子项。
视图.py
class SubassemblyDetail(generics.RetrieveUpdateDestroyAPIView):
"""
Retrieve, update, or delete a particular items subassembly
"""
queryset = Subassembly.objects.all()
serializer_class = SubassemblySerializer
def get_queryset(self):
item_id = self.kwargs['pk']
item = Item.objects.get(pk=item_id)
return item.children.all()
型号.py
class Item(models.Model):
# ... (various other fields)
children = models.ManyToManyField('self', through='Subassembly', blank=True)
class Subassembly(models.Model):
parent_id = models.ForeignKey(Item, related_name='parent_item', on_delete=models.CASCADE)
child_id = models.ForeignKey(Item, related_name='child_item', on_delete=models.CASCADE)
child_qty = models.PositiveSmallIntegerField(default=1)
序列化程序.py
class SubassemblySerializer(ModelSerializer):
parent_id = get_primary_key_related_model(ShortItemSerializer)
child_id = get_primary_key_related_model(ShortItemSerializer)
class Meta:
model = Subassembly
fields = '__all__'
def update(self, instance, validated_data):
children = validated_data.pop('children')
child_list = []
qty_list = []
for child in children:
pk = child['child_id']
qty = child['qty']
obj = Item.objects.get(id=pk)
child_list.append(obj)
qty_list.append(qty)
instance.children.set(child_list, through_defaults={'qty': qty_list})
instance.save()
return instance
def delete(self, instance):
instance.children.clear()
为了引用父项和子项对象,我使用了本文中的mixin或其他东西,这样我就可以只使用它们的主键。
此外,项目序列化程序代码当前没有通过表或其序列化程序引用部件。我尝试添加类似的内容,但错误仍然存在,而且在创建项目时还需要children字段,这是我不想要的。代码看起来是这样的:
class ItemSerializer(ModelSerializer):
# ... (other fields)
children = SubassemblySerializer(many=true)
def create(self, validated_data):
return Item.objects.create(**validated_data)
class Meta:
model = Item
fields = '__all__'
urls.py
urlpatterns = [
path('', views.RouteList.as_view()),
path('items/', views.ItemList.as_view(), name='item-list'),
path('items/<int:pk>/', views.ItemDetail.as_view(), name='item-detail'),
path('suppliers/', views.SupplierList.as_view(), name='supplier-list'),
path('suppliers/<int:pk>/', views.SupplierDetail.as_view(), name='supplier-detail'),
path('subassemblies/<int:pk>/', views.SubassemblyDetail.as_view(), name='subassembly-detail')
]
其他url都工作正常,只是组件url返回了这个错误。
如果我理解正确,您的问题涉及从Item
对象检索children
。我怀疑Item
对象没有被检索到。诊断方法如下:
使用以下命令进入Django交互式shell:
python manage.py shell
在外壳内执行以下操作:
# Import Item
from <your_model_name>.models import Item
# Retrieve an Item object
item = Item.objects.get(id=2)
# Retrieve children
children = item.children.all()
# Get the count of children
print(children.count())
如果children.count()
为0,则表示您的项目对象没有任何子对象。如果你能排除这种可能性,那就意味着你的视图或序列化程序就是问题所在。
粗略地看,SubAssemblyDetail
中的get_queryset()
方法返回一个Item
查询集,这可能是一个问题。在引擎盖下,SubAssemblyDetail
执行retrieve()
方法,请参阅:https://www.cdrf.co/3.13/rest_framework.generics/RetrieveUpdateDestroyAPIView.html
已解决!多亏了Hamster Hooey,问题是在SubassemblyDetail
视图下的get_queryset()
方法中,我返回的是项查询集,而不是子组件查询集,这似乎是Django无法接受的。
所以我没有做item.children.all()
,而是做了Subassembly.objects.filter(parent_id=item_id)
,结果一切都很好。