Django REST Framework JSON API показывает пустой объект связи отношений при использовании relations.HyperRelatedField из rest_framework_json_api
Я создаю REST API для отчета о пространственной связке, я хочу, чтобы связка была дочерней для каждого отчета.
Мои модели:
from django.db import models
from django.utils import timezone
class Report(models.Model):
class Meta:
managed = False
db_table = 'report'
ordering = ['-id']
predict_start = models.DateTimeField(null=True)
predict_end = models.DateTimeField(null=True)
process_duration = models.IntegerField(default=0, null=True)
create_conjunction_date = models.DateTimeField(null=True)
ephe_filename = models.CharField(max_length=100, null=True)
class Conjunction(models.Model):
class Meta:
managed = False
db_table = 'conjunction'
ordering = ['-conjunction_id']
conjunction_id = models.IntegerField(primary_key=True)
tca = models.DateTimeField(max_length=3, null=True)
missdt = models.FloatField(null=True)
probability = models.FloatField(null=True)
prob_method = models.CharField(max_length=45, null=True)
norad = models.OneToOneField(SatelliteCategory, to_field='norad_cat_id', db_column='norad', null=True, on_delete=models.DO_NOTHING)
doy = models.FloatField(null=True)
ephe_id = models.IntegerField(null=True)
pri_obj = models.IntegerField(null=True)
sec_obj = models.IntegerField(null=True)
report = models.ForeignKey(Report, related_name='conjunctions', null=True, on_delete=models.DO_NOTHING)
probability_foster = models.FloatField(null=True)
probability_patera = models.FloatField(null=True)
probability_alfano = models.FloatField(null=True)
probability_chan = models.FloatField(null=True)
Мои сериализаторы:
class ConjunctionSerializer(serializers.ModelSerializer):
class Meta:
model = Conjunction
fields = '__all__'
class ReportSerializer(serializers.ModelSerializer):
conjunctions = relations.ResourceRelatedField(many=True, read_only=True)
class Meta:
model = Report
fields = '__all__'
Мои взгляды:
from rest_framework import permissions
from rest_framework_json_api.views import viewsets
from .serializers import ReportSerializer, ConjunctionSerializer
from .models import Report, Conjunction
class ReportViewSet(viewsets.ModelViewSet):
queryset = Report.objects.all()
serializer_class = ReportSerializer
permission_classes = [permissions.AllowAny]
class ConjunctionViewSet(viewsets.ModelViewSet):
queryset = Conjunction.objects.all()
serializer_class = ConjunctionSerializer
permission_classes = [permissions.AllowAny]
Мой urls.py
from django.contrib import admin
from django.urls import include, path
from rest_framework import routers
from api.views import UserViewSet, GroupViewSet
from shared.views import ReportViewSet, SatelliteCategoryViewSet, ConjunctionViewSet, ReportSentViewSet
router = routers.DefaultRouter()
router.register(r'users', UserViewSet)
router.register(r'groups', GroupViewSet)
router.register(r'reports', ReportViewSet)
router.register(r'report_sent', ReportSentViewSet)
router.register(r'satellite_category', SatelliteCategoryViewSet)
router.register(r'conjunctions', ConjunctionViewSet)
# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
Когда я использую ResourceRelatedField
вывод JSON будет выглядеть так:
{
"links": {
"first": "http://127.0.0.1:8000/api/reports/?page%5Bnumber%5D=1",
"last": "http://127.0.0.1:8000/api/reports/?page%5Bnumber%5D=84",
"next": "http://127.0.0.1:8000/api/reports/?page%5Bnumber%5D=2",
"prev": null
},
"data": [
{
"type": "Report",
"id": "838",
"attributes": {
"predict_start": "2023-01-26T12:00:00Z",
"predict_end": "2023-02-02T12:00:00Z",
"process_duration": 752,
"create_conjunction_date": "2023-01-26T14:52:45Z",
"ephe_filename": "Filename.txt"
},
"relationships": {
"conjunctions": {
"meta": {
"count": 107
},
"data": [
{
"type": "Conjunction",
"id": "78728"
},
# ... more data ...
{
"type": "Conjunction",
"id": "78622"
}
]
}
}
}
],
"meta": {
"pagination": {
"page": 1,
"pages": 84,
"count": 838
}
}
}
Но когда я использую HyperlinkedRelatedField
, он выдает пустой объект conjunctions
:
{
"links": {
"first": "http://127.0.0.1:8000/api/reports/?page%5Bnumber%5D=1",
"last": "http://127.0.0.1:8000/api/reports/?page%5Bnumber%5D=84",
"next": "http://127.0.0.1:8000/api/reports/?page%5Bnumber%5D=2",
"prev": null
},
"data": [
{
"type": "Report",
"id": "838",
"attributes": {
"predict_start": "2023-01-26T12:00:00Z",
"predict_end": "2023-02-02T12:00:00Z",
"process_duration": 752,
"create_conjunction_date": "2023-01-26T14:52:45Z",
"ephe_filename": "Filename.txt"
},
"relationships": {
"conjunctions": {}
}
},
],
"meta": {
"pagination": {
"page": 1,
"pages": 84,
"count": 838
}
}
}
Вот что я ожидаю:
{
"links": {
"first": "http://127.0.0.1:8000/api/reports/?page%5Bnumber%5D=1",
"last": "http://127.0.0.1:8000/api/reports/?page%5Bnumber%5D=84",
"next": "http://127.0.0.1:8000/api/reports/?page%5Bnumber%5D=2",
"prev": null
},
"data": [
{
"type": "Report",
"id": "838",
"attributes": {
"predict_start": "2023-01-26T12:00:00Z",
"predict_end": "2023-02-02T12:00:00Z",
"process_duration": 752,
"create_conjunction_date": "2023-01-26T14:52:45Z",
"ephe_filename": "Filename.txt"
},
"relationships": {
"conjunctions": {
# Any links or something.
}
}
},
],
"meta": {
"pagination": {
"page": 1,
"pages": 84,
"count": 838
}
}
}
Я могу решить проблему сейчас.
Отныне я буду использовать drf-nested-routers
для разрешения конъюнкций, связанных с ссылками на отчеты.
Вы можете установить по
pip install drf-nested-routers
Добавлять эту библиотеку в файл settings.py вашего проекта Django не нужно, так как она не содержит ни app, ни signal, ни model.
В urls.py добавьте следующие маршрутизаторы
from django.urls import path, include
from rest_framework_nested import routers
from api.views import UserViewSet, GroupViewSet
from shared.views import ReportViewSet, SatelliteCategoryViewSet, ConjunctionViewSet, ReportSentViewSet, SatelliteViewSet, DiscosObjectViewSet, CoordinateViewSet, ReportRelationshipView
router = routers.DefaultRouter()
router.register(r'users', UserViewSet)
router.register(r'groups', GroupViewSet)
router.register(r'reports', ReportViewSet)
router.register(r'report_sent', ReportSentViewSet)
router.register(r'satellite_categories', SatelliteCategoryViewSet)
router.register(r'conjunctions', ConjunctionViewSet)
router.register(r'satellites', SatelliteViewSet)
router.register(r'discos_objects', DiscosObjectViewSet)
router.register(r'coordinates', CoordinateViewSet)
reports_router = routers.NestedSimpleRouter(router, 'reports', lookup='report')
reports_router.register(r'conjunctions', ConjunctionViewSet, basename='report-conjunctions')
urlpatterns = [
path('admin/', admin.site.urls),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
] + [
path('api/', include(router.urls)) for router in [router, reports_router]
]
В файле serializers.py добавьте HyperlinkedRelatedField
в ReportSerializer
класс.
class ReportSerializer(serializers.HyperlinkedModelSerializer):
conjunctions = relations.HyperlinkedRelatedField(
many=True, read_only=True,
related_link_view_name='report-conjunctions-list',
related_link_url_kwarg='report_pk'
)
class Meta:
model = Report
fields = '__all__'
В views.py, из класса ConjunctionViewSet
, переопределите метод get_queryset
для фильтрации любых конъюнкций, связанных с отчетом.
class ConjunctionViewSet(viewsets.ModelViewSet):
queryset = Conjunction.objects.all()
serializer_class = ConjunctionSerializer
permission_classes = [permissions.AllowAny]
# Add code below
# | | | | | | |
# v v v v v v v
def get_queryset(self):
queryset = super().get_queryset()
report_pk = self.kwargs.get('report_pk')
if report_pk is not None:
queryset = queryset.filter(report__pk=report_pk)
return queryset
Данный результат вывода JSON
{
"data": {
"type": "Report",
"id": "838",
"attributes": {
"predict_start": "2023-01-26T12:00:00Z",
"predict_end": "2023-02-02T12:00:00Z",
"process_duration": 752,
"create_conjunction_date": "2023-01-26T14:52:45Z",
"ephe_filename": "Filename.txt"
},
"relationships": {
"conjunctions": {
"links": {
"related": "http://127.0.0.1:8000/api/reports/838/conjunctions/"
}
}
},
"links": {
"self": "http://127.0.0.1:8000/api/reports/838/"
}
}
}