Динамическая сериализация для связанных полей

У меня есть следующие модели:

class Country(models.Model):
    """
    Country model
    """
    # With name and isoCode (charfield) 
    ...
class State(models.Model):
    """
    State model
    """
    # With name and isoCode (charfield) 
    country = models.ForeignKey(Country, on_delete=models.CASCADE)
    ...
class City(models.Model):
    """
    City model
    """
    name = models.CharField(max_length=32)
    state = models.ForeignKey(State, on_delete=models.CASCADE)
    country = models.ForeignKey(Country, on_delete=models.CASCADE)
    ...

And UserLocation referenced by:

class Location(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="location")
    country = models.ForeignKey(Country, on_delete=models.CASCADE)
    state = models.ForeignKey(State, on_delete=models.CASCADE)
    city = models.ForeignKey(City, on_delete=models.CASCADE)

Как создать сериализатор, который создает UserLocation, а также возвращает информацию в JSON?

Я пытался

class LocationSerializer(serializers.ModelSerializer):
    country = serializers.SlugRelatedField(slug_field="isoCode", queryset=Country.objects.all())
    state = serializers.SlugRelatedField(slug_field="isoCode", queryset=State.objects.filter(country__isoCode=country))
    city = serializers.SlugRelatedField(slug_field="name", queryset=City.objects.all())
    class Meta:
        model = Location
        fields = ["user", "country", "state", "city"]

Но это не работает, выдает ошибку {"state":["Object with isoCode=BC does not exist."],...

Как создать динамически связанный сериализатор? Или как это можно обойти?

Думаю, вам нужен следующий сериализатор

class LocationSerializer(serializers.ModelSerializer):
    country = serializers.ReadOnlyField(source="country.isocode")
    state = serializers.ReadOnlyField(source="state.isocode")
    city = serializers.ReadOnlyField(source="city.name")
    
    class Meta:
        model = Location
        fields = ["user", "country", "state", "city"]

Однако, похоже, что ваша модель спроектирована неправильно. Вам не нужно иметь внешние ключи country, state в модели Location, так как модель City имеет state, модель State имеет country.

Для будущих пользователей. Я обнаружил, что

class LocationSerializer(serializers.ModelSerializer):
    '''Used to serialize user location'''
    country = serializers.SlugRelatedField(slug_field="isoCode", queryset=Country.objects.all(), required=True)

    class Meta:
        model = Location
        fields = ["user", "country"]
        extra_kwargs = {"user": { "validators":[UniqueValidator(queryset=Location.objects.all(), message=_("User already has a location. Please update user location. Hint: use PUT request"))]}}


    def __init__(self, *args, **kwargs):

        super().__init__(*args, **kwargs)
        if "country" in kwargs['context']['request'].data and len(Country.objects.get(isoCode=self.initial_data["country"]).state_set.all()) > 0:
            self.fields["state"] = serializers.SlugRelatedField(slug_field="isoCode", queryset=State.objects.filter(country__isoCode=self.initial_data["country"]), required=True)
            
            if "state" in kwargs['context']['request'].data and len(State.objects.get(isoCode=self.initial_data["state"], country__isoCode=self.initial_data["country"]).city_set.all()) > 0:
                self.fields["city"] = serializers.SlugRelatedField(slug_field="name", queryset=City.objects.filter(state__isoCode=self.initial_data["state"],country__isoCode=self.initial_data["country"]), required=True)

Показалось, что это сработало в моем случае

Вернуться на верх