Как создать модель Django с полем FK на основе идентификатора из URL почтового запроса? - PullRequest
0 голосов
/ 15 апреля 2019

Я делаю простой 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 ().Я обнаружил некоторые лакомые кусочки о настройке пользовательских контекстов (где я могу получить к ним доступ и затем обратиться к ним во время работы в сериализаторе, но это кажется огромным перегибом для проблемы, которая, как мне кажется, является довольно распространенной, и которая, я надеюсь, должна иметь готовое решение, которое япропал без вести.

1 Ответ

0 голосов
/ 15 апреля 2019

Вы бы связали определенный маршрут с вашим конкретным EduApp или передали бы его в полезной нагрузке.

Маршрут /eduapp/10/tasks может использоваться для создания определенного Task, в то же время он содержит информацию о eduapp_id, которая поможет вам найти уникальный экземпляр, с которым вы хотите связать его.

Так что теперь вы можете сделать поиск:

instance.eduapp = EduApp.objects.get(id=eduapp_id)

при условии, что вы назвали параматер eduapp_id

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...