Поток данных в 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()
отправить десериализованное значение в базу данных.
Чтобы полностью осознать силу Serializer
s, пройдите учебник и отработайте каждую его часть.