Django REST API-запрос по связанному полю - PullRequest
1 голос
/ 24 октября 2019

У меня есть 3 модели, Run, RunParameter, RunValue:

class Run(models.Model):
    start_time = models.DateTimeField(db_index=True)
    end_time = models.DateTimeField()

class RunParameter(models.Model):
    parameter = models.ForeignKey(Parameter, on_delete=models.CASCADE)

class RunValue(models.Model):
    run = models.ForeignKey(Run, on_delete=models.CASCADE)
    run_parameter = models.ForeignKey(RunParameter, on_delete=models.CASCADE)
    value = models.FloatField(default=0)

    class Meta:
            unique_together=(('run','run_parameter'),)

A Run может иметь RunValue , который является значением с плавающей запятой со значениемимя, полученное из RunParameter (который в основном представляет собой таблицу с именами), например:

A RunValue может быть AverageTime или Максимальная температура

A Запуск может иметь RunValue = RunParameter: AverageTime со значением X.

Другой Выполнить экземпляр может иметь RunValue = RunParameter: MaximumTempera со значением Y и т. д.

Я создал конечную точку для запроса моего API, но у меня есть только RunParameter ID (из-за способа, которым вы можете выбрать, какой параметр вы хотите отобразить), а не RunValue ID напрямую. Я в основном показываю список всех RunParameter и список всех Run экземпляров, потому что если бы я показал все экземпляры RunValue , список был бы слишком длинным и запутаннымвместо "Максимальная температура" вы увидите:

  • "Максимальная температура для прогона X"

  • "Максимальная температура для прогона Y"

  • " Максимальная температура для прогона Z "и т. Д. (Повторите 50+ раз).

Мой API-интерфейс выглядит следующим образом:

class RunValuesDetailAPIView(RetrieveAPIView):
    queryset = RunValue.objects.all()
    serializer_class = RunValuesDetailSerializer
    permission_classes = [IsOwnerOrReadOnly]]

И сериализатор для этого выглядит следующим образом:

class RunValuesDetailSerializer(ModelSerializer):
    run = SerializerMethodField()
    class Meta:
        model = RunValue
        fields = [
            'id',
            'run',
            'run_parameter',
            'value'
        ]
    def get_run(self, obj):
        return str(obj.run)

И URL на всякий случай, если он уместен:

url(r'^run-values/(?P<pk>\d+)/$', RunValuesDetailAPIView.as_view(), name='values_list_detail'),

Так как я новичок вREST API, до сих пор я имел дело только с идентификатором представления API модели, который я запрашиваю напрямую, но никогда не идентификатором связанного поля. Я не уверен, где изменить свой набор запросов, чтобы передать ему идентификатор для получения соответствующего экземпляра модели из связанного поля.

В момент, когда я делаю запрос API, у меня есть Выполнить идентификатор экземпляра и RunParameter ID. Мне нужно, чтобы набор запросов был:

run_value = RunValue.objects.get(run=run_id, run_parameter_id=param_id)

Хотя до сих пор мне приходилось только делать что-то вроде:

run_value = RunValue.objects.get(id=value_id) # I don't have this ID

Ответы [ 2 ]

1 голос
/ 24 октября 2019

Ну, это довольно просто, все, что вам нужно сделать, это переопределить метод get_object, например (копия, вставленная из документации ):

# view
from django.shortcuts import get_object_or_404

class RunValuesDetailAPIView(RetrieveAPIView):
    queryset = RunValue.objects.all()
    serializer_class = RunValuesDetailSerializer
    permission_classes = [IsOwnerOrReadOnly]]
    lookup_fields = ["run_id", "run_parameter_id"]

    def get_object(self):
        queryset = self.get_queryset()             # Get the base queryset
        queryset = self.filter_queryset(queryset)  # Apply any filter backends
        filter = {}
        for field in self.lookup_fields:
            if self.kwargs[field]: # Ignore empty fields.
                filter[field] = self.kwargs[field]
        obj = get_object_or_404(queryset, **filter)  # Lookup the object
        self.check_object_permissions(self.request, obj)
        return obj

# url
url(r'^run-values/(?P<run_id>\d+)/(?P<run_parameter_id>\d+)/$', RunValuesDetailAPIView.as_view(), name='values_list_detail'),

Но одна большая вещь, которую вынужно быть осторожным, если не иметь дублирующиеся записи с одинаковыми run_id и run_parameter_id, то это приведет к ошибкам. Чтобы избежать этого, либо используйте unique_together=['run', 'run_parameter'], либо вы можете использовать queryset.filter(**filter).first() вместо get_object_or_404 в представлении. Но второй вариант будет давать неправильные результаты при создании повторяющихся записей.

1 голос
/ 24 октября 2019

Если я правильно понимаю, вы пытаетесь получить экземпляр RunValue только с идентификатором Run и идентификатором RunParameter, то есть запрос на основе связанных полей.

Набор запросов можетбыть достигнуто с помощью следующего:

run_value = RunValue.objects.get(
                          run__id=run_id,
                          run_parameter__id=run_parameter_id
            )

При условии, что экземпляр RunValue имеет только 1 связанный Run и RunParameter, это вернет экземпляр RunValue, который вы ищете.

Дайте мне знать, если вы не это имеете в виду.

Двойное подчеркивание позволяет вам получить доступ к этим связанным полям экземпляра в вашем запросе.

...