Добавление поля в сериализатор с 2 внешними ключами - PullRequest
0 голосов
/ 23 марта 2020

У меня есть 2 модели, которые выглядят так:

class Topic(models.Model):
    name = models.CharField(max_length=25, unique=True)

    def save(self, *args, **kwargs):
        topic = Topic.objects.filter(name=self.name)

        if topic:
            return topic[0].id

        super(Topic, self).save(*args, **kwargs)
        return self.id

class PostTopic(models.Model):
    topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
    post= models.ForeignKey(Post, on_delete=models.CASCADE)

Если topi c уже находится в таблице Topic, то мы возвращаем идентификатор этой topi c. Мы не создаем другого. Когда пользователь отправляет Post с помеченными темами (представьте, что это хештеги), тогда, если эти темы не существуют в таблице Topic, они будут созданы вместе со связью в PostTopic

* 1009. Как говорится, вот как выглядит мой сериализатор:
class PostSerializer(serializers.ModelSerializer):
    topics = serializers.ListField(
         child=serializers.CharField(max_length=256), max_length=3
    )

    class Meta:
        model = Post
        fields = ('user', 'status', 'topics')

    def create(self, validated_data):
        topics= validated_data.pop('topics')
        post = Post.objects.create(**validated_data)

        for topic in topics:
             topic_id = Topic(name=topic).save()
             PostTopic(post_id=post.id, topic_id=topic_id).save()

        return post

В настоящее время мой сериализатор дает мне AttributeError, потому что themes не является полем в Post. Как я могу это исправить, чтобы я мог заставить его работать? Если я использую PostTopic, то как я могу заставить пользователя задавать актуальные темы?

1 Ответ

1 голос
/ 23 марта 2020

Я думаю, что вы ищете Many To Many связь между Post и Topic. Вы можете добавить его следующим образом:

class Post(models.Model):
    # rest of the fields
    topics = models.ManyToManyField('Topic', through='PostTopic')

class Topic(models.Model):
    name = models.CharField(max_length=25, unique=True)

   # def save(self, *args, **kwargs):
   #     **Important:** Django model's save function does not return anything. So handling it here won't be good. Let us handle duplicate entry in serializer
   #     topic = Topic.objects.filter(name=self.name)

   #     if topic:
   #         return topic[0].id

   #     super(Topic, self).save(*args, **kwargs)
   #     return self.id

class PostTopic(models.Model):
    topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
    post= models.ForeignKey(Post, on_delete=models.CASCADE)

Кроме того, ваш метод обработки дубликатов не будет работать, потому что метод сохранения модели ничего не возвращает. Давайте разберемся с ним в сериализаторе с некоторыми незначительными исправлениями:

class PostSerializer(serializers.ModelSerializer):
    topics = serializers.ListField(
         child=serializers.CharField(max_length=256), max_length=3
    )

    class Meta:
        model = Post
        fields = ('user', 'status', 'topics')

    def create(self, validated_data):
        topics= validated_data.pop('topics')
        post = Post.objects.create(**validated_data)

        for topic in topics:
             new_topic, _ = Topic.objects.get_or_create(name=topic)
             PostTopic(post_id=post.id, topic=new_topic).save()

        return post
...