Django Rest Framework - Создание объекта внешнего ключа на POST - PullRequest
0 голосов
/ 28 октября 2018

У меня есть простой DRF REST API, который я хочу использовать для создания статей блога.Я хочу иметь возможность добавлять теги к тем статьям блога, чтобы пользователи могли искать теги и просматривать соответствующие статьи.Однако теги могут еще не существовать.Я создал Article модель с полем ForeignKey для Tag модели, подобной этой:

class Tag(models.Model):

    name = models.CharField(max_length=32)

    def _str__(self):
        return self.name

    class Meta:
        ordering = ('name',)

class Article(models.Model):

    title = models.CharField(max_length=256)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField()
    date = models.DateTimeField(auto_now_add=True)
    tags = models.ForeignKey(Tag, on_delete=models.CASCADE, blank=True, default=None)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ('date', 'id')

В идеале я хочу иметь возможность ПОСТАВИТЬ новую Article с набором тегови, если какой-либо из тегов не существует, создайте их в БД.Однако, как и в настоящее время, теги уже должны существовать для добавления в Article.Визуально DRF показывает это в виде раскрывающегося списка, который заполнен уже существующими тегами:

DRF Interface

Как добавить или создать несколько Tag s измоя Article конечная точка API?

РЕДАКТИРОВАТЬ: В соответствии с запросом, я добавил мои views.py

views.py:

from api.blog.serializers import ArticleSerializer, TagSerializer
from rest_framework import viewsets

# /api/blog/articles
class ArticleView(viewsets.ModelViewSet):

    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

# /api/blog/tags
class TagView(viewsets.ModelViewSet):

    queryset = Tag.objects.all()
    serializer_class = TagSerializer

Для полноты здесьмои сериализаторы из моего REST API serializers.py.

serializers.py:

class ArticleSerializer(serializers.ModelSerializer):

    class Meta:
        model = Article
        fields = '__all__'


class TagSerializer(serializers.ModelSerializer):

    class Meta:
        model = Tag
        fields = '__all__'

urls.py:

from rest_framework import routers

router = routers.DefaultRouter()
router.register('articles', views.ArticleView)
router.register('tags', views.TagView)

urlpatterns = [
    path('', include(router.urls)),
]

Ответы [ 2 ]

0 голосов
/ 28 октября 2018

Хорошо, спасибо @JPG за помощь.Это то, что я закончил.Это позволяет пользователям добавлять теги, разделенные пробелом, в CharField на конечной точке /api/blog/article.Когда выполняется запрос POST, теги разделяются на пробелы get_or_create() d (для этого мне нужно было сделать Tag.name первичным ключом), а затем добавляются к Article с помощью article.tags.set(tag_list).Как предложили @JPG и @Martins, лучший способ сделать это - ManyToManyField().

Вот мой полный код:

serializers.py:

class ArticleSerializer(serializers.ModelSerializer):

    class TagsField(serializers.CharField):

        def to_representation(self, tags):
            tags = tags.all()
            return "".join([(tag.name + " ") for tag in tags]).rstrip(' ')


    tags = TagsField()

    class Meta:
        model = Article
        fields = '__all__'

    def create(self, validated_data):

        tags = validated_data.pop('tags') # Removes the 'tags' entry
        tag_list = []
        for tag in tags.split(' '):
            tag_instance, created = Tag.objects.get_or_create(name=tag)
            tag_list += [tag_instance]

        article = Article.objects.create(**validated_data)
        print(tag_list)
        article.tags.set(tag_list)
        article.save()
        return article


class TagSerializer(serializers.ModelSerializer):

    class Meta:
        model = Tag
        fields = '__all__'

Обратите внимание, что мне пришлось создать пользовательский TagField() и переопределить to_representation().Это потому, что если бы я использовал обычные serializer.CharField() теги отображались как: «Blog.tag.None» вместо значений тегов, например:

Blog.tag.None

models.py:

class Tag(models.Model):

    name = models.CharField(max_length=32, primary_key=True)

    def __str__(self):
        return self.name

    class Meta:
        ordering = ('name',)

class Article(models.Model):

    title = models.CharField(max_length=256)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField()
    date = models.DateTimeField(auto_now_add=True)
    tags = models.ManyToManyField(Tag)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ('date', 'id')
0 голосов
/ 28 октября 2018

Переопределение метода create() сериализатора как

<Code>class ArticleSerializer(serializers.ModelSerializer):
    <b>tags = serializers.CharField()</b>

    class Meta:
        model = Article
        fields = '__all__'

    <b>def create(self, validated_data):
        tag = validated_data.pop('tags')
        tag_instance, created = Tag.objects.get_or_create(name=tag)
        article_instance = Article.objects.create(**validated_data, tags=tag_instance)
        return article_instance</b></code>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...