Я делаю простой API в DjangoRESTFramework.У меня есть следующая модель задачи, которая принадлежит одному и только одному учебному приложению (для краткости eduapp):
class Task(models.Model):
id = models.AutoField(primary_key=True, blank=True)
name = models.TextField()
eduapp = models.ForeignKey(EduApp, on_delete=models.CASCADE, null=False)
и простой сериализатор для него:
class TaskSerializer(serializers.ModelSerializer):
taskId = serializers.IntegerField(source='id', required=False)
class Meta:
model = Task
fields = ('taskId', 'name')
Для доступа к этимЗадачи, у меня есть представление, которое показывает список всех задач с заданным идентификатором eduapp (eduapp - другая модель).Идентификатор Eduapp берется из URL-адреса, используемого для запросов со следующим шаблоном URL: path('eduapps/<int:eduapp_id>/tasks/', views.TaskList.as_view()),
, например, так:
localhost:8000/eduapps/1/tasks/
дает мой идентификатор eduapp вида 1:
class TaskList(generics.ListCreateAPIView):
serializer_class = TaskSerializer
def get_queryset(self):
queryset = Task.objects.all()
eduapp_id = self.kwargs.get('eduapp_id')
queryset = queryset.filter(eduapp=eduapp_id)
return queryset
Это работает простохорошо.Однако сейчас я хочу сохранить новые задачи (ранее введенные прямо в БД), а не просто перечислить существующие.Мне интересно, как распространять eduapp_id из представления в сериализатор и как затем использовать его в качестве внешнего ключа для нового поля eduapp (которое уже существует в модели), что-то вроде:
class TaskSerializer(serializers.ModelSerializer):
taskId = serializers.IntegerField(source='id', required=False)
eduapp = ??? some magic ???
class Meta:
model = Task
fields = ('taskId', 'name', 'eduapp') # new field name here
До сих пор я пытался определить свою собственную функцию создания в сериализаторе и установить там FK:
def create(self, validated_data):
instance = Task.objects.create(**validated_data)
instance.eduapp = EduApp.objects.get(id=1)
return instance
здесь с жестко закодированным идентификатором eduapp, равным 1. Это, казалось, работало нормально, но сделало так, чтобы POSTвсе еще требуется тело, чтобы включить значение eduapp
.Чтобы противостоять этому, я включил это в сериализатор:
eduapp = EduAppSerializer(read_only=True,
many=False,
allow_null=True)
, который мне не очень нравится, потому что, хотя он делает eduapp
больше не требующимся на POST, у меня не было намерения фактически отображать часть eduappпри десериализации на GET (хотя я могу жить с этим).
Однако я не смог пройти через жестко закодированное значение в моей функции create ().Я обнаружил некоторые лакомые кусочки о настройке пользовательских контекстов (где я могу получить к ним доступ и затем обратиться к ним во время работы в сериализаторе, но это кажется огромным перегибом для проблемы, которая, как мне кажется, является довольно распространенной, и которая, я надеюсь, должна иметь готовое решение, которое япропал без вести.