Django Rest Framework, вложенные поля для записи, mixins drf_writable_nested - PullRequest
0 голосов
/ 18 марта 2019

В настоящее время я пытаюсь использовать drf_writable_nested для выполнения обновлений и создания моей текущей схемы БД, и я столкнулся с этой ошибкой:

Метод .create() не поддерживает записи вложенных полей по умолчанию. Напишите явный метод .create() для сериализатора trvl.serializers.StatisticsSerializer или установите read_only=True для вложенных полей сериализатора.

Основная модель:

class Statistics(models.Model):
    """Instance: {airport_code, carrier_code, month, year, flight, delay_count, delay_time}"""
    airport = models.ForeignKey(Airport, on_delete=models.CASCADE)
    carrier = models.ForeignKey(Carrier, on_delete=models.CASCADE)
    month = models.IntegerField(
        validators=[MinValueValidator(1), MaxValueValidator(12)])
    year = models.IntegerField(validators=[MinValueValidator(
        1900, message='Invalid year: year < 1900.')])
    # statistics linkage
    flight = models.ForeignKey(
        FlightStatistics, on_delete=models.DO_NOTHING)
    delay_count = models.ForeignKey(
        DelayCountStatistics, on_delete=models.DO_NOTHING)
    delay_time = models.ForeignKey(
        DelayTimeStatistics, on_delete=models.DO_NOTHING)

    # Guaranteeing the "primary key" of the tuple
    class Meta:
        unique_together = ('airport', 'carrier', 'month', 'year')

    def __str__(self):
        return '%s_%s_%s_%s' % (self.airport, self.carrier, self.month, self.year)

Serializer:

class StatisticsSerializer(WritableNestedModelSerializer):
    # Using nest serializer for handling get and post
    # Using serializers instead of the model fields
    flight = FlightStatisticsSerializer()
    delaycount = DelayCountStatisticsSerializer()
    delaytime = DelayTimeStatisticsSerializer()

    class Meta:
        model = models.Statistics
        fields = ('airport', 'carrier', 'month', 'year',
                  'flight', 'delaytime', 'delaycount')

Вид:

class StatisticsView(viewsets.ModelViewSet, NestedCreateMixin, NestedUpdateMixin):
queryset = models.Statistics.objects.all()
serializer_class = serializers.StatisticsSerializer

def post(self,request,*args, **kwargs):
    return self.create(request, *args, **kwargs)

def put(self, request, *args, **kwargs):
    return self.update(request, *args, **kwargs)

Пример полезной нагрузки:

{
    "airport": "ATL",
    "carrier": "AA",
    "month": 7,
    "year": 2008,
    "flight": {
        "cancelled": 2,
        "on_time": 30,
        "total": 100l,
        "delayed": 303,
        "diverted": 121
    },
    "delaytime": {
        "late_aircraft": 21,
        "weather": 2121,
        "security": 2121,
        "national_aviation_system": 21212,
        "carrier": 22
    },
    "delaycount": {
        "late_aircraft": 1212,
        "weather": 1212,
        "security": 1221,
        "national_aviation_system": 1221,
        "carrier": 1212
    }
}

Django HTML-форма для этого представления: HTML Form

Ответы [ 2 ]

0 голосов
/ 19 марта 2019

UPDATE

Я решил реализовать свой собственный вложенный сериализатор:

class StatisticsSerializer(serializers.ModelSerializer):
    # Using nest serializer for handling get and post
    # Using serializers instead of the model fields
    url = serializers.HyperlinkedIdentityField(view_name='statistics-detail')
    flight = FlightStatisticsSerializer(allow_null=True)
    delay_count = DelayCountStatisticsSerializer(allow_null=True)
    delay_time = DelayTimeStatisticsSerializer(allow_null=True)

    class Meta:
        model = models.Statistics
        fields = ('url','airport', 'carrier', 'month', 'year',
                  'flight', 'delay_time', 'delay_count')

    def create(self, validated_data):
        flight_statistics = models.FlightStatistics.objects.create(
            **(validated_data.pop('flight')))
        delay_time_statistics = models.DelayTimeStatistics.objects.create(
            **(validated_data.pop('delay_time')))
        delay_count_statistics = models.DelayCountStatistics.objects.create(
            **(validated_data.pop('delay_count')))
        print(flight_statistics)

        statistics = models.Statistics.objects.create(**validated_data, flight=flight_statistics,
                                                      delay_time=delay_time_statistics, delay_count=delay_count_statistics)

        return statistics

    def update(self, instance, validated_data):
        flight, _ = models.FlightStatistics.objects.update_or_create(id=instance.flight.id, defaults=validated_data.pop('flight'))
        delay_time, _ = models.DelayTimeStatistics.objects.update_or_create(id=instance.delay_time.id, defaults=validated_data.pop('delay_time'))
        delay_count, _ = models.DelayCountStatistics.objects.update_or_create(id=instance.delay_count.id, defaults=validated_data.pop('delay_count'))
        new_instance, _ = models.Statistics.objects.update_or_create(id=instance.id, defaults=validated_data)

        return new_instance
0 голосов
/ 18 марта 2019

Вы пытались реализовать предложение в сообщении об ошибке?

class StatisticsSerializer(WritableNestedModelSerializer):
    # Using nest serializer for handling get and post
    # Using serializers instead of the model fields
    flight = FlightStatisticsSerializer(read_only=True)         # <--
    delaycount = DelayCountStatisticsSerializer(read_only=True) # <--
    delaytime = DelayTimeStatisticsSerializer(read_only=True)   # <--

    class Meta:
        model = models.Statistics
        fields = ('airport', 'carrier', 'month', 'year',
                  'flight', 'delaytime', 'delaycount')
...