Поток данных в Django Rest Framework?

Недавно я начал изучать Django Rest Framework и столкнулся с небольшим препятствием, пытаясь понять поток данных в DRF.

Насколько я понимаю, представления принимают веб-запрос и возвращают веб-ответ, поэтому они являются первым компонентом в потоке данных DRF, верно? (после урлов).

Тогда каков второй шаг? Представления обычно ссылаются на сериализатор, так что наш сериализатор будет выполнен следующим. Если да, то почему бы и нет, ведь сериализатор используется для преобразования сложных типов данных, таких как экземпляры моделей, в JSON.

У меня возник этот и несколько связанных с ним вопросов после изучения DRF docs tutorial part-4.

КОНТЕКСТ: В документах мы создаем фрагменты кода и теперь хотим связать пользователей с созданными ими фрагментами.

Для этого выполняем следующие шаги в следующем порядке:

Ниже в учебнике мы создаем сериализатор для представления пользователя. Как сериализатор помогает представлять пользователя, ведь сериализаторы используются для преобразования данных?

1 Добавление конечных точек для наших моделей пользователей

Теперь, когда у нас есть несколько пользователей, с которыми мы можем работать, нам лучше добавить представления этих пользователей в наш API.

class UserSerializer(serializers.ModelSerializer):
    snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())

    class Meta:
        model = User
        fields = ['id', 'username', 'snippets']

Ниже кроется моя основная проблема, в документации говорится, что пользователь не отправляется как часть сериализованного представления, а является свойством входящего запроса.

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

2 Ассоциирование сниппетов с пользователями

На данный момент, если бы мы создали сниппет кода, не было бы возможности связать пользователя, создавшего сниппет, с экземпляром сниппета. Пользователь не отправляется как часть сериализованного представления, а является свойством входящего запроса.

Мы решаем эту проблему путем переопределения метода .perform_create() в наших представлениях сниппетов, что позволяет нам изменять способ сохранения экземпляра и обрабатывать любую информацию, которая неявно содержится во входящем запросе или запрашиваемом URL.

В класс представления SnippetList добавьте следующий метод:

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

Как проверить свойства входящего запроса.

3 Обновление нашего сериализатора

Теперь, когда сниппеты ассоциируются с создавшим их пользователем, давайте обновим наш SnippetSerializer, чтобы он отражал это. Добавьте следующее поле в определение сериализатора в serializers.py:

owner = serializers.ReadOnlyField(source='owner.username')

Как эти три шага помогают добавить пользователя в наши сниппеты. Как именно здесь происходит поток данных?

Спасибо.

P.S.: У меня возник один вопрос после просмотра кода, написанного другими, что означает serializer.save(data=data) или serializer.create(data=data)?

Код ниже:

views.py

class SnippetList(generics.ListCreateAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]


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

serializers.py

class SnippetSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source="owner.username")

    class Meta:
        model = Snippet
        fields = ["id", "title" , "code", "linenos", "language", "style", "owner"]

class UserSerializer(serializers.ModelSerializer):
    snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())

    class Meta:
        model = User
        fields = ["id", "username", "snippets"]

models.py

class Snippet(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=100, blank=True, default='')
    code = models.TextField()
    linenos = models.BooleanField(default=False)
    language = models.CharField(choices=LANGUAGE_CHOICES, default="python", max_length=100)
    style = models.CharField(choices=STYLE_CHOICES, default="friendly", max_length=100)
    owner = models.ForeignKey("auth.User", related_name="snippets", on_delete=models.CASCADE)
    highlighted = models.TextField()

    class Meta:
        ordering = ['created']

    def save(self,*args, **kwargs):
        """
        Use the "pygments" library  to create a highlighted HTML representation of the code snippet.
        """
        lexer = get_lexer_by_name(self.language)
        linenos = "table" if self.linenos else False
        options = {"title": self.title} if self.title else{}
        formatter = HtmlFormatter(style=self.style, linenos=linenos, full=True ,**options)
        self.highlighted = highlight(self.code, lexer, formatter)
        super().save(*args, **kwargs)

Я пытался разобраться, гуглил, но не нашел удовлетворительных ответов.

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

Они действительно таковы. Serializer позволяют преобразовывать сложные данные, такие как QuerySet и экземпляры Model, в собственные типы данных Python, которые затем можно легко преобразовать в JSON, XML или другие типы содержимого. Serializer также обеспечивают десериализацию, позволяя преобразовывать разобранные данные обратно в сложные типы, предварительно проверив входящие данные.

... в документации говорится, что пользователь не отправляется как часть сериализованного представления, а является свойством входящего запроса.

Когда пользователь аутентифицируется в Django, атрибут user HttpRequest становится экземпляром AUTH_USER_MODEL, представляющим текущего вошедшего в систему пользователя . Если пользователь не вошел в систему, user будет установлен в экземпляр AnonymousUser. DRF ничего не меняет в этом случае, поэтому вы всегда можете получить экземпляр текущего зарегистрированного пользователя через HttpRequest.user. Из этого видно, что нет необходимости отправлять его в составе request.body.

Как проверить свойства входящего запроса[?]

Вы можете определить, вошел ли пользователь в систему, выполнив проверку:

if request.user.is_authenticated:
    print("Yes user is logged in.")

Как эти три шага помогают добавить пользователя в наши сниппеты[?]

Существует множество способов решения этой задачи, но я приведу самые основные, чтобы избежать путаницы:

С model Snippet так:

class Snippet(models.Model):
    #•••Rest of code•••
    owner = models.ForeignKey("auth.User", related_name="snippets", on_delete=models.CASCADE)
    #•••Rest of code•••

Вы можете создать новый Snippet следующим образом:

snippet = Snippet.objects.create(
    #•••Other fields•••
    owner = request.user
    #•••Rest of code•••
)

Вся документация DRF по Serializer направлена на то, чтобы показать вам, насколько они мощны. Приведенный выше пример можно выполнить с помощью Serializer. С помощью Serializer можно десериализовать body разобранного HttpRequest, проверить его и save() отправить десериализованное значение в базу данных.


Чтобы полностью осознать силу Serializers, пройдите учебник и отработайте каждую его часть.

Вернуться на верх