我想实现标记功能,以便使用文章创建标记。我建立了两个模型,即Article和Tag。在Article模型上,我定义了一个引用该标签的标签字段(ManyToMany Field)。
我现在拥有的代码可以很好地创建带有标签的文章。我觉得可以改善。有人告诉我,我正在硬编码很多东西(重复自己)。例如,他指出我不应该定义用于创建标签的自定义方法。所以,现在我想也许有一种方法可以在post方法内调用TagSerializer,以将标签保存在文章中。我真的不确定如何解决这个问题。
是否可以通过更多利用内置的Django原理来改进标记代码? (特别是保存标签的部分)。
Models.py
from django.db import models
from django.utils import timezone
from authors.apps.authentication.models import User
from .utils import get_unique_slug
class Tag(models.Model):
""" Model for Tag """
tag = models.CharField(max_length=30, unique=True)
slug = models.SlugField(max_length=100, unique=True)
author = models.ForeignKey('authentication.User', on_delete=models.CASCADE)
def __str__(self):
return self.tag
class Article(models.Model):
"""
Model for Article
"""
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=255, null=False, blank=False)
description = models.TextField(null=False, blank=False)
body = models.TextField(null=False, blank=False,)
tags = models.ManyToManyField(
'Tag', related_name='articles')
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
self.slug = get_unique_slug(self, 'title', 'slug')
return super().save(*args, **kwargs)
Serializers.py
from rest_framework import serializers
from authors.apps.articles.models import Article
from authors.apps.articles.models import Tag
class ArticleSerializer(serializers.ModelSerializer):
"""Serializer for articles."""
author = serializers.ReadOnlyField(source='author.username')
tag_list = serializers.StringRelatedField(many=True, required=False, source='tags')
class Meta:
model = Article
fields = ('author','title','slug','description','body','created_at','updated_at','tag_list')
class TagSerializer(serializers.ModelSerializer):
author = serializers.CharField(source='author.username')
class Meta:
model = Tag
fields = '__all__'
Views.py
from rest_framework import generics
from rest_framework import status
from rest_framework.permissions import IsAuthenticated,IsAuthenticatedOrReadOnly,AllowAny
from rest_framework.response import Response
from authors.apps.articles.serializers import ArticleSerializer, TagSerializer
from .models import Article, Tag
from rest_framework import serializers
def create_tag(tags, article):
"""
This method checks whether a tag with tag provided exists in the
database and creates it if it does not exist.
"""
for tag in tags.split(','):
article_tag = Tag.objects.filter(tag__icontains=tag.strip())
if not article_tag:
data = {'tag': tag.strip()}
serializer = TagSerializer(data=data)
serializer.is_valid(raise_exception=True)
article_tag = serializer.save()
article.article_tags.add(article_tag)
else:
article.article_tags.add(article_tag.first())
article.save()
return None
class ArticleAPIView(generics.ListCreateAPIView):
"""
get:
Retrieve all articles
post:
Create a new article
"""
queryset = Article.objects.all()
serializer_class = ArticleSerializer
renderer_classes = (ArticleJSONRenderer,)
permission_classes = (IsAuthenticatedOrReadOnly,)
def post(self, request):
"""
Creates an article
"""
article = {
'title': request.data.get('title', None),
'body': request.data.get('body', None),
'description': request.data.get('description', None),
'author': request.user.id
}
# pass article data to the serializer class, check whether the data is
# valid and if valid, save it.
serializer = self.serializer_class(data=article)
serializer.is_valid(raise_exception=True)
article = serializer.save()
# retrieve the tags as passed on in the article data
tags = request.data.get('tags', None)
if tags:
create_tag(tags, article)
return Response(serializer.data, status.HTTP_201_CREATED)