I have an AngularJS project that used Django as a platform through the Django Rest Framework (DRF).
I created a group model and set up a serializer class for it, however now I want to set a new field in this model called related_groups , which will refer to the same model (group) as an array of primary keys.
I donโt know if self-esteem is possible in the serializer, and I donโt know how else to get through the related groups from the front-end, which can be selected and selected by users who own the group. I want this field to refer to the primary keys of other lines in the group and repeat this collection of groups to establish related group relationships.
class GroupSerializer(serializers.ModelSerializer): class Meta: model = mod.Group fields = ( 'group_id', 'group_name', 'category', 'related_groups', )
and the view seems to be exactly what I want:
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)
and the model is presented as such:
class Group(models.Model): """ Model definition of a Group. Groups are a collection of users (ie Contacts) that share access to a collection of objects (eg 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)
View, access to this model, a fairly simple view of 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)
What causes some disinfection and verification methods:
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)
which causes:
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
which is just a wrapper around the select_for_update() method of Django.
As a result of the migration, a new group_related_groups table was created with the identifier, from_group and to_group column, which is used by Django as a join / search to establish these relations.
I can write individually for this endpoint, but the GroupSerializer serializer doesn't seem to want to allow multiple defaults.
Thus, using the PUT request for PUT, the value '2' for grouping with PK of 1 is successful. However, attempts to put ['2','3'] , [2,3] , 2,3 and '2','3'
Tracking it back through the view to the utilitarian method, I see that it serializer.is_valid() does not fulfill the request, so it seems to me that this is a many=True problem, but I donโt know which relationship serializer to use for this special ManyToManyField self-referential problem.
When debugging, I output serializer.is_valid () errors in syslog as follows:
response = ("Attempt to serialize {} with id {} failed " "with errors {}").format(str(obj_type), str(pk), str(serializer.errors)) logger.exception(response)
And I get this exception message as an answer:
Message: "Attempt to serialize <class 'bioapi.models.Group'> with id 1 failed with errors "
Debug error output for obj_serializer.error -
obj_serializer.error of {'related_groups': ['Incorrect type. Expected pk value, received str.']}
And here is the debug messasge on request.data:
{'group_name': 'Default Guest Group', 'related_groups': [1], 'group_id': 2, 'category': 'guest'}
which succeeds, and
<QueryDict: {'group_name': ['requestomatic'], 'related_groups':['2,2'], category': ['guest']}>
which fails. Looking at this now, I wonder if Postman data formatting is a problem. If in this case I will feel pretty stupid.
Can I imagine many-to-many relationships from a model back to myself using DRF, or do I need to have my own serializer just for the relationship table? The documentation for DRF does not use self-referenced models, and all the examples that I find on the Internet either use several models or several serializers.
Is it possible to use ManyToManyField in my model, which is self-referential using the Django Rest Framework (DRF) and its serializers? If so, how?