PUT-запрос к Django API для обновления списка вложенных объектов со связями «многие ко многим» - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть пользовательская модель со связью ManyToMany с другой моделью

class User(AbstractUser):
    countries = models.ManyToManyField(Country, blank=True)
    count = models.IntegerField(blank=True, default=0)

    def save(self, *args, **kwargs):
        # Must save model before Many To Many relationship can be used.
        super(User, self).save(*args, **kwargs)
        self.count = self.countries.count()
        super(User, self).save(*args, **kwargs)

, и моя модель страны является довольно большой моделью:

class Country(models.Model):
    '''
    Describes the countries, as well as territories of the world.
    '''
    name = models.CharField(max_length=255, null=True, blank=True)
    top_level_domain = JSONField(null=True, blank=True)
    alpha2code = models.CharField(max_length=255, null=True, blank=True)
    alpha3code = models.CharField(max_length=255, null=True, blank=True)
    calling_codes = JSONField(null=True, blank=True)
    capital = models.CharField(max_length=255, null=True, blank=True)
    alt_spellings = JSONField(null=True, blank=True)
    region = models.CharField(max_length=255, null=True, blank=True)
    subregion = models.CharField(max_length=255, null=True, blank=True)
    population = models.IntegerField(null=True, blank=True)
    latlng = JSONField(null=True, blank=True)
    demonym = models.CharField(max_length=255, null=True, blank=True)
    area = models.FloatField(null=True, blank=True)
    gini = models.FloatField(null=True, blank=True)
    timezones = JSONField(null=True, blank=True)
    borders = JSONField(null=True, blank=True)
    native_name = models.CharField(max_length=255, null=True, blank=True)
    numeric_code= models.CharField(max_length=255, null=True, blank=True)
    currencies = models.ManyToManyField(Currency)
    languages = models.ManyToManyField(Language)
    flag = models.CharField(max_length=255, null=True, blank=True)
    regional_blocs = models.ManyToManyField(RegionalBloc, blank=True)
    cioc = models.CharField(max_length=255, null=True, blank=True)

    def __str__(self):
        return self.name

Я пытаюсь сделатьПоставьте запрос от моего внешнего интерфейса, чтобы обновить список стран, связанных с (данные отправляются в виде массива объектов из React с аксиосами).Я получил сообщение об ошибке «AssertionError: Метод .update() не поддерживает вложенные поля для записи по умолчанию. Напишите явный метод .update() для сериализатора api.serializers.UserDetailSerializer или установите read_only=True для вложенных полей сериализатора».Поскольку я, очевидно, не могу сделать мои страны read_only = True, я пытаюсь добавить метод обновления в мой сериализатор.

class UserDetailSerializer(UserDetailsSerializer):
    countries = CountrySerializer(many=True)
    count = serializers.IntegerField(read_only=True)

    class Meta:
        model = User
        fields = ('pk', 'username', 'email', 'count', 'countries')

    # Update the instance upon Put Request from frontend.
    def update(self, instance, validated_data):
        instance.countries = validated_data['countries']
        instance.save()
        return instance

Этот метод обновления выдает ошибку «Прямое назначение передней стороне множества« многие ко многим »запрещено.Вместо этого используйте country.set (). '

Когда я меняю метод обновления на

  instance.countries.set(validated_data['countries'])

, я получаю сообщение об ошибке «Ошибка типа: недопустимый тип:« collection.OrderedDict »».Начинаю чувствовать себя немного потерянным, и как будто я бегаю кругами.Как правильно написать метод обновления?

edit: То, что я пытаюсь сделать, это просто добавить / удалить объект Country в список стран Users.На самом деле я не хочу редактировать ни один из объектов страны.

публикуемые данные о моей стране будут представлять собой список объектов стран, выглядящих следующим образом

{
    "id": 6,
    "currencies": [
        {
            "code": "EUR",
            "name": "European Euro",
            "symbol": "€"
        }
    ],
    "languages": [
        {
            "iso639_1": "ca",
            "name": "Catalan",
            "native_name": "Català"
        }
    ],
    "regional_blocs": [],
    "name": "Andorra",
    "top_level_domain": [
        ".ad"
    ],
    "alpha2code": "AD",
    "alpha3code": "AND",
    "calling_codes": [
        "376"
    ],
    "capital": "Andorra la Vella",
    "alt_spellings": [
        "AD",
        "Principality of Andorra",
        "Principat d'Andorra"
    ],
    "region": "Europe",
    "subregion": "Southern Europe",
    "population": 78014,
    "latlng": [
        42.5,
        1.5
    ],
    "demonym": "Andorran",
    "area": 468.0,
    "gini": null,
    "timezones": [
        "UTC+01:00"
    ],
    "borders": [
        "FRA",
        "ESP"
    ],
    "native_name": "Andorra",
    "numeric_code": "020",
    "flag": "https://restcountries.eu/data/and.svg",
    "cioc": "AND"
}

1 Ответ

0 голосов
/ 10 ноября 2018

Вы получаете TypeError: unhashable type: 'collections.OrderedDict', потому что вы пытаетесь присвоить объект типа collections.OrderedDict странам, что является ManyToManyField.

Вместо этого выполните следующие действия:

def update(self, instance, validated_data):
    country_names = [cdata['name'] for cdata in validated_data['countries']]
    countries = Country.objects.filter(name__in=country_names)
    instance.countries.set(countries)
    return instance
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...