Django REST Framework (DRF): установить текущий идентификатор пользователя в качестве значения поля

У меня есть модель NewsModel и 2 сериализатора для него:

models.py

class NewsModel(models.Model):
    title = models.CharField('Заголовок', max_length=255, help_text='Максимальная длина - 255 символов')
    announce = models.TextField('Анонс', help_text='Краткий анонс новости')
    author = models.ForeignKey(settings.AUTH_USER_MODEL, help_text='Автор новости', related_name='news')
    full_text = models.TextField('Полный текст новости', help_text='Полный текст новости')
    pub_date = models.DateTimeField('Дата публикации', auto_now_add=True, default=timezone.now, help_text='Дата публикации')

    def comments_count(self):
        return NewsComment.objects.filter(news=self.id).count()

    def get_author_full_name(self):
        return self.author.get_full_name()

    class Meta:
        db_table = 'news'
        ordering = ('-pub_date',)

serilizers.py:

from rest_framework import serializers
from .models import NewsModel
from extuser.serializers import UserMiniSerializer

class NewsReadSerializer(serializers.ModelSerializer):

    author = UserMiniSerializer()

    class Meta:
        model = NewsModel
        fields = ('id', 'title', 'announce', 'comments_count', 'reviews', 'author_name')

    def get_author_full_name(self, obj):
        return obj.get_author_full_name()


class NewsWriteSerializer(serializers.ModelSerializer):

    def validate_author(self, value):
        value = self.request.user.id
        return value

    class Meta:
        model = NewsModel        

Я выбираю сериализаторы в api.py:

class NewsList(ListCreateAPIView):
    queryset = NewsModel.objects.order_by('-pub_date')
    def get_serializer_class(self, *args, **kwargs):
        if self.request.method == 'GET':
            return NewsReadSerializer
        return NewsWriteSerializer

    class Meta:
        model = NewsModel

Но когда я создам элемент NewsModel, я вижу ошибку 400: неверный запрос [{'author': 'Это поле обязательное'}]

Как я могу установить текущий идентификатор пользователя как значение NewsItem.author при создании нового элемента?

Ответ 1

В версии DRF до 3-го поля должно быть declader с allow_null = True и значением по умолчанию = Нет. DRF не запускает контрольные поля без этих параметров. Код результата:

class NewsReadSerializer(serializers.ModelSerializer):

    """
    Serializer only for reading.

    author field serialized with other custom serializer
    """

    author = UserMiniSerializer()

    class Meta:
        model = NewsModel
        fields = ('id', 'title', 'announce', 'comments_count', 'reviews', 'author', 'pub_date',)


class NewsWriteSerializer(serializers.ModelSerializer):

    """
    Serializer for creating and updating records.

    author here is the instance of PrimaryKeyRelatedField, linked to all users
    """

    author = serializers.PrimaryKeyRelatedField(
        queryset=User.objects.all(), # Or User.objects.filter(active=True)
        required=False, 
        allow_null=True, 
        default=None
    )

    # Get the current user from request context
    def validate_author(self, value):
        return self.context['request'].user

    class Meta:
        model = NewsModel      
        fields = ('title', 'announce', 'full_text', 'author',)

Ответ 2

Я не думаю, что вы правильно используете сериализатор. Лучшей практикой установки данных, связанных с запросом, является переопределение perform_create в вашем представлении:

def perform_create(self, serializer):
    serializer.save(author=self.request.user)

def perform_update(self, serializer):
    serializer.save(author=self.request.user)

а затем установите для вашего автора сериализатора только для чтения:

author = UserMiniSerializer(read_only=True)

таким образом вы можете просто использовать один единственный NewsSerializer для операций чтения и записи.

Ответ 4

Я бы попробовал что-то вроде этого:

ваши models.py

class NewsModel(models.Model):
    title = models.CharField(
        'Заголовок', max_length=255,
        help_text='Максимальная длина - 255 символов')
    announce = models.TextField('Анонс',
        help_text='Краткий анонс новости')
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        help_text='Автор новости', related_name='news')
    full_text = models.TextField(
        'Полный текст новости',
        help_text='Полный текст новости')
    pub_date = models.DateTimeField(
        'Дата публикации', auto_now_add=True,
        default=timezone.now, help_text='Дата публикации')

def comments_count(self):
    return NewsComment.objects.filter(news=self.id).count()

def get_author_full_name(self):
    return self.author.get_full_name()

class Meta:
    db_table = 'news'
    ordering = ('-pub_date',)

serializers.py

(ссылка: http://www.django-rest-framework.org/api-guide/validators/#currentuserdefault)

from <yourapp>.models import NewsModel
from rest_framework import serializers


class NewsModelSerializer(serializers.ModelSerializer):
    author = serializers.HiddenField(default=serializers.CurrentUserDefault())
    class Meta:
        model = NewsModel

Также вы должны установить settings.py примерно так:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',)
}

Ответ 5

author = serializers.HiddenField(default=serializers.CurrentUserDefault())