Mam projekt AngularJS, który używał Django jako frameworka za pośrednictwem Django Rest Framework (DRF).Django Rest Framework Wiele do wielu pól związanych z samym sobą
Utworzono model grupy i skonfigurowałem dla niego klasę serializera, jednak chcę teraz ustanowić nowe pole w tym modelu o nazwie related_groups
, które będzie odwoływać się do tego samego modelu (grupy) jako tablicy kluczy podstawowych .
Nie wiem, czy możliwe jest samodzielne odwoływanie się do serializera, i nie wiem, jak inaczej przejść przez powiązane grupy z front-endu, które mogą być wybrane i wybrane przez użytkowników kto jest właścicielem grupy. Chcę, aby to pole odwoływać się do kluczy podstawowych innych wierszy grupy i iterować przez ten zbiór grup, aby ustanowić pokrewną relację grupy.
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = mod.Group
fields = (
'group_id',
'group_name',
'category',
'related_groups',
)
i reprezentacja wydaje się być dokładnie tym, czego chcę:
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)
a model jest reprezentowany jako takie:
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)
Widok dostępu do tego modelu jest dość prosty widok 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)
który wywołuje pewne metody odkażania i walidacji:
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)
który wzywa:
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
który jest po prostu otoki wokół select_for_update()
metoda Django.
Migracja utworzyła nową tabelę o nazwie group_related_groups, z identyfikatorem, grupą from_group i kolumną to_group, używaną przez Django jako skrzyżowanie/odnośnik do ustanowienia tych relacji.
Mogę pisać indywidualnie do tego punktu końcowego, ale serializator GroupSerializer wydaje się nie chcieć dopuszczać wielu wartości przez domyślnie.
Tak więc, przy użyciu żądania PUT do PUT wartość "2" do grupy z PK z 1 zakończy się pomyślnie. Jednak próby umieścić ['2','3']
, [2,3]
, 2,3
i '2','3'
Śledzenie go z powrotem przez myślą o metodzie użytkowego, widzę, że to serializer.is_valid()
braku żądania, tak że sprawia mi myśleć, że to many=True
problem, ale don” t wiedzieć, który serial serializator relacji użyć do tego konkretnego samoodnawialnego problemu ManyToManyField.
Gdy debugowanie, mam wyprowadzania serializer.is_valid() błędów do syslog tak:
response = ("Attempt to serialize {} with id {} failed "
"with errors {}").format(str(obj_type), str(pk),
str(serializer.errors))
logger.exception(response)
A ja dostaję ten komunikat wyjątku jako odpowiedź:
Message: "Attempt to serialize <class 'bioapi.models.Group'> with id 1 failed with errors
"
Wyjście błędu debugowania dla obj_serializer.Błąd jest
obj_serializer.error of {'related_groups': ['Incorrect type. Expected pk value, received str.']}
A oto debug messasge na request.data:
{'group_name': 'Default Guest Group', 'related_groups': [1], 'group_id': 2, 'category': 'guest'}
którym się powiedzie, a
<QueryDict: {'group_name': ['requestomatic'], 'related_groups':['2,2'], category': ['guest']}>
która nie powiedzie się. Patrząc na to teraz, zastanawiam się, czy problemem jest formatowanie danych formularza Postman. Jeśli tak, to będę się czuł głupio.
Czy mogę reprezentować relacje wiele do wielu z modelu z powrotem do siebie z DRF, czy też potrzebuję niestandardowego serializera tylko dla tabeli relacji? Dokumentacja dla DRF nie korzysta z modeli self-referencyjnych, a wszystkie przykłady, które znajduję online, używają wielu modeli lub wielu Serializatorów.
Czy można korzystać z ManyToManyField w moim modelu, który jest samoodnoszący się przy użyciu Django Rest Framework (DRF) i serializerów? Jeśli tak to jak?
proszę wyjaśnić co masz na myśli przez 'GroupSerializer() : 'in your second snippet – e4c5
Gdy' serializer.is_valid() 'nie działa, jaka jest zawartość' serializer.errors'? Zwykle daje dobre wskazówki, dlaczego się nie udaje. –
@ e4c5, sprawdzając relację serializera z metodą opisaną w dokumentacji relacji serializera, tutaj: http://www.django-rest-framework.org/api-guide/relations/#inspecting-relationships, a relacja wydaje się być w porządku. – Smittles