我有一个AngularJS项目,通过Django Rest框架(DRF)使用Django作为框架。
我已经创建了一个Group模型,并为它设置了一个序列化器类,但是我现在想在该模型上建立一个名为related_groups
的新字段,它将作为主键数组引用相同的模型(Group)。
我不知道是否可以在序列化器中自我引用,但是,我也不知道如何从前端传递相关的组,这些组可以由拥有组的用户挑选。我希望该字段引用其他Group行的主键,并遍历该组集合以建立相关的组关系。
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = mod.Group
fields = (
'group_id',
'group_name',
'category',
'related_groups',
)
和表示似乎正是我想要的:
GroupSerializer():
group_id = IntegerField(read_only=True)
group_name = CharField(max_length=100)
category = CharField(max_length=256, required=False
related_groups = PrimaryKeyRelatedField(many=True, queryset=Group.objects.all(), required=False)
,模型表示为:
class Group(models.Model):
"""
Model definition of a Group. Groups are a collection of users (i.e.
Contacts) that share access to a collection of objects (e.g. Shipments).
"""
group_id = models.AutoField(primary_key=True)
group_name = models.CharField(max_length=100)
owner_id = models.ForeignKey('Owner', related_name='groups')
category = models.CharField(max_length=256)
related_groups = models.ManyToManyField('self', blank=True, null=True)
history = HistoricalRecords()
def __unicode__(self):
return u'%s' % (self.group_name)
def __str__(self):
return '%s' % (self.group_name)
访问这个模型的视图是非常简单的CRUD视图:
@api_view(['GET', 'PUT', 'DELETE'])
@authentication_classes((SessionAuthentication, BasicAuthentication))
@permission_classes((IsAuthenticated, HasGroupAccess))
def group_detail(request, pk, format=None):
group, error = utils.get_by_pk(pk, mod.Group, request.user)
if error is not None:
return error
if request.method == 'GET':
serializer = ser.GroupSerializer(group)
return Response(serializer.data)
elif request.method == 'PUT':
return utils.update_object_by_pk(request, pk, mod.Group,
ser.GroupSerializer)
elif request.method == 'DELETE':
return utils.delete_object_by_pk(request.user, pk, mod.Group)
调用一些消毒和验证方法:
def update_object_by_pk(request, pk, obj_type, serializer):
try:
with transaction.atomic():
obj, error = select_for_update_by_pk(pk, obj_type, request.user)
if error is not None:
return error
obj_serializer = serializer(obj, data=request.data)
if obj_serializer.is_valid():
obj_serializer.save()
else:
response = ("Attempt to serialize {} with id {} failed "
"with errors {}").format(str(obj_type), str(pk),
str(serializer.errors))
return Response(response, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
response = ("Error attempting to update {} with ID={}. user={}, "
"error={}".format(str(obj_type), str(pk),
str(request.user.email), str(e)))
return Response(response, status=status.HTTP_400_BAD_REQUEST)
else:
resp_str = ("Successfully updated {} with ID={}".format(str(obj_type),
str(pk)))
return Response(resp_str, status=status.HTTP_200_OK)
调用:
def select_for_update_by_pk(pk, mod_type, user):
response = None
obj = None
try:
obj = mod_type.objects.select_for_update().get(pk=pk)
except mod_type.DoesNotExist:
resp_str = ("{} could not be found with ID={}.".
format(str(mod_type), str(pk)))
response = Response(resp_str, status=status.HTTP_404_NOT_FOUND)
return obj, response
是select_for_update()
Django方法的一个包装。
迁移创建了一个名为group_related_groups的新表,它有一个ID,一个from_group和一个to_group列,Django使用它作为连接/查找来建立这些关系。
我可以单独写入该端点,但是序列化器GroupSerializer似乎不希望在默认情况下允许多个值通过。
因此,使用PUT请求将值'2'放入PK为1的组是成功的。然而,试图将['2','3']
, [2,3]
, 2,3
和'2','3'
通过视图将其追溯到实用程序方法,我看到它是serializer.is_valid()
请求失败,因此这使我认为这是many=True
问题,但我不知道要使用哪个关系序列化器用于这个特定的自我引用的ManyToManyField问题。
调试时,我将serializer.is_valid()错误输出到syslog,如下所示:
response = ("Attempt to serialize {} with id {} failed "
"with errors {}").format(str(obj_type), str(pk),
str(serializer.errors))
logger.exception(response)
我得到这个异常消息作为响应:
Message: "Attempt to serialize <class 'bioapi.models.Group'> with id 1 failed with errors
"
obj_serializer的调试错误输出。错误是
obj_serializer.error of {'related_groups': ['Incorrect type. Expected pk value, received str.']}
这是请求时的调试信息。数据:
{'group_name': 'Default Guest Group', 'related_groups': [1], 'group_id': 2, 'category': 'guest'}
成功,
<QueryDict: {'group_name': ['requestomatic'], 'related_groups':['2,2'], category': ['guest']}>
而失败。现在看着这个,我想知道是否邮差表单数据格式是问题。如果是这样的话,我会觉得自己很蠢。
我是否能够用DRF表示从模型到自身的多对多关系,或者我是否需要为关系表拥有一个自定义序列化器?DRF的文档不使用自引用模型,我在网上找到的所有示例要么使用多个模型,要么使用多个序列化器。
是否有可能在我的模型中使用ManyToManyField,这是使用Django Rest框架(DRF)及其序列化器进行自我引用?如果有,怎么做?
看起来像是嵌套序列化。模型应为-
class Group(models.Model):
group_id = models.IntegerField(read_only=True)
group_name = models.CharField(max_length=100)
category = models.CharField(max_length=256, required=False)
related_groups = models.ForeignKey('self', required=False, related_name='children')
和序列化器-
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = (
'group_id', 'group_name', 'category', 'related_groups',
)
class NestedGroupSerializer(serializers.ModelSerializer):
children = GroupSerializer(many=True, read_only=True)
class Meta:
model = Group
fields = ('group_id', 'group_name', 'category', 'related_groups', 'children')
你可以使用NestedGroupSerializer来访问所有相关的组。
默认情况下,嵌套序列化器是只读的。如果你想支持对嵌套序列化器字段的写操作,你需要创建create()和/或update()方法,以便显式地指定子关系应该如何保存。希望对你有帮助。
尝试使用ModelViewSet作为视图:
class GroupViewSet(viewsets.ModelViewSet):
queryset = models.Group.objects.all()
serializer_class = serializers.GroupSerializer
authentication_classes = (SessionAuthentication, BasicAuthentication)
permission_classes = (IsAuthenticated, HasGroupAccess)
和在你的urls.conf
中,类似于:从导入视图从rest_framework导入路由器
router = routers.SimpleRouter()
router.register(r'group', views.GroupViewset)
urlpatterns = router.urls