如何使用Django REST API的POST请求返回对象列表?

huangapple go评论62阅读模式
英文:

How to return a list of objects using a Django REST API post request?

问题

我是新手使用REST API,尝试创建一个API,可以进行POST请求,包含关键字,然后返回与该关键字相关的文章列表。

无法使用GET请求的原因是因为我不是从数据库中获取任何内容,我是基于POST请求中的关键字创建文章列表。

Views.py:

def article_get(request):
    if request.method == 'POST':
        serializer = serializers.ArticleListSerializer(data=request.data)
        if serializer.is valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

classes.py:

class Article:

    title = ""
    url = ""

    def __init__(self, url, title):
        self.title = title
        self.url = url

class ArticleList:
    keywords = ""
    articles = []

    def __init__(self, keywords, articles):
        self.keywords = keywords
        self.articles = articles

        self.articles.append(serializedArticle)

self.articles.append(serializedArticle) 行将一个序列化的文章附加到文章列表,我希望这只会将以JSON格式表示的文章添加到文章列表,但实际上产生了以下错误:类型为ArticleSerializer的对象无法进行JSON序列化

serializers.py:

class ArticleSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=300)
    url = serializers.CharField(max_length=300)

    def create(self, validated_data):
        return classes.Article(**validated_data)

class ArticleListSerializer(serializers.Serializer):
    articles = serializers.ListField()
    keywords = serializers.CharField(max_length=100)

    def create(self, validated_data):
        return classes.ArticleList(**validated_data)

正如我提到的,我远非API专家。我希望通过将序列化的Article对象附加到ArticleList中,它能够返回响应中的ArticleList,但它不能。

有人知道如何修复这个问题吗?或者:有人知道我是否走在正确的道路上吗?我很难理解Django REST API文档,所以我认为我很可能犯了一些愚蠢的错误。所以,任何反馈都非常感激。

英文:

I am new to using REST API's and am trying to create an API where I can make a POST request containing keywords, which should then return a list of articles related to that keyword.

The reason I can't use a GET request is because I am not GETting anything from a database, I am creating the list of articles based on the keyword from the POST request.

Views.py:

def article_get(request):
    if request.method == 'POST':
        serializer = serializers.ArticleListSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

classes.py:

class Article:
	
	title = ""
        url = ""

	def __init__(self, url, title):
                self.title = title
		self.url = url
class ArticleList:
	keywords = ""
	articles = []

	def __init__(self, keywords, articles):
		self.keywords = keywords
		self.articles = articles
                
                self.articles.append(serializedArticle)
		

The self.articles.append(serializedArticle) line appends a serialized article to the articles list,
which I hoped would simply add an article in JSON format to the articlelist, but instead it produces the following error:
Object of type ArticleSerializer is not JSON serializable

serializers.py:
class ArticleSerializer(serializers.Serializer):
	title = serializers.CharField(max_length=300)
	url = serializers.CharField(max_length=300)
	def create(self, validated_data):
		return classes.Article(**validated_data)

class ArticleListSerializer(serializers.Serializer):
	articles = serializers.ListField()
	keywords = serializers.CharField(max_length=100)

	def create(self, validated_data):
		return classes.ArticleList(**validated_data)

As I mentioned, I am FAR from being an API expert. I had hoped that by appending a serialized Article object to the ArticleList, that it would be able to return the ArticleList in the response, but it can't.

Does anyone know how to fix this? Or: does anyone know if I'm even on the right track? I'm struggling to understand the django REST API documentation so I reckon there's a big chance I'm making some dumb mistakes. So: any feedback is greatly appreciated.

答案1

得分: 0

以下是您要翻译的内容:

In order to retrieve or filter data you need to store it somewhere. Not necessarily a database. It can be in memory, for instance:

database.py
```python
database = {
    "articles": 
    [
        {
            "title": "Prepopulated Article",
            "url": "http://prepopulated.example.com",
            "keywords": ["prepopulated", "stuff"]
        }
    ],
}

serializers.py

class ArticleSerializer(serializers.Serializer):
    title = serializers.CharField()
    url = serializers.URLField()
    keywords = serializers.ListField()

views.py

from rest_framework.decorators import api_view
from rest_framework.response import Response
from myapp.api.serializers import ArticleSerializer
from myapp.database import database

@api_view(['POST'])
def article_create(request): 
    """ Endpoint for creating articles """
    if request.method == 'POST':
        serializer = ArticleSerializer(data=request.data)
        if serializer.is_valid():
            database['articles'].append(serializer.data)

    return Response(serializer.data, status=status.HTTP_201_CREATED)

@api_view(['GET', 'POST'])
def article_list(request): 
    """ Endpoint for listing Articles """

    if request.method == 'POST':
        data = []
        keywords = request.data.pop('keywords', None)

        # Would be equivalent to filtering a QuerySet
        if keywords and isinstance(keywords, list):
            for key in keywords:
                for obj in database['articles']:
                    if key in obj['keywords'] and obj not in data:
                        data.append(obj)

        serializer = ArticleSerializer(data=data, many=True)
        if serializer is_valid(raise_exception=True):
            return Response(serializer.data, status=status.HTTP_200_OK)
    else:
        print(database['articles'])
        serializer = ArticleSerializer(data=database['articles'], many=True)
        if serializer.is_valid(raise_exception=True):
            return Response(serializer.data, status=status.HTTP_200_OK)

If we send the following payload to create endpoint:

{
    "title": "Article One",
    "url": "http://article-one.example.com",
    "keywords": ["new", "stuff"]
}

And this payload to list endpoint. Then it returns the new created article:

{
    "keywords": ["new"]
}

Whereas the one below would return both articles.

{
    "keywords": ["stuff"]
}

A few notes:

  1. Using keywords as a list to improve the filtering (instead of string).
  2. The pseudo-database will reset every time you reload the server. So objects you create using the endpoint will be deleted.

<details>
<summary>英文:</summary>

In order to retrieve or filter data you need to store it somewhere. Not necessarily a database. It can be in memory, for instance:

database.py
```python
database = {
    &quot;articles&quot;: 
    [
        {
            &quot;title&quot;: &quot;Prepopulated Article&quot;,
            &quot;url&quot;: &quot;http://prepropulated.example.com&quot;,
            &quot;keywords&quot;: [&quot;prepopulated&quot;, &quot;stuff&quot;]
        }
    ],
}

serializers.py

class ArticleSerializer(serializers.Serializer):
    title = serializers.CharField()
    url = serializers.URLField()
    keywords = serializers.ListField()

views.py

from rest_framework.decorators import api_view
from rest_framework.response import Response
from myapp.api.serializers import ArticleSerializer
from myapp.database import database

@api_view([&#39;POST&#39;])
def article_create(request): 
    &quot;&quot;&quot; Endpoint for creating articles &quot;&quot;&quot;
    if request.method == &#39;POST&#39;:
        serializer = ArticleSerializer(data=request.data)
        if serializer.is_valid():
            database[&#39;articles&#39;].append(serializer.data)

    return Response(serializer.data, status=status.HTTP_201_CREATED)

@api_view([&#39;GET&#39;, &#39;POST&#39;])
def article_list(request): 
    &quot;&quot;&quot; Endpoint for listing Articles &quot;&quot;&quot;

    if request.method == &#39;POST&#39;:
        data = []
        keywords = request.data.pop(&#39;keywords&#39;, None)

        # Would be equivalent to filtering a QuerySet
        if keywords and isinstance(keywords, list):
            for key in keywords:
                for obj in database[&#39;articles&#39;]:
                    if key in obj[&#39;keywords&#39;] and obj not in data:
                        data.append(obj)

        serializer = ArticleSerializer(data=data, many=True)
        if serializer.is_valid(raise_exception=True):
            return Response(serializer.data, status=status.HTTP_200_OK)
    else:
        print(database[&#39;articles&#39;])
        serializer = ArticleSerializer(data=database[&#39;articles&#39;], many=True)
        if serializer.is_valid(raise_exception=True):
            return Response(serializer.data, status=status.HTTP_200_OK)

If we send the following payload to create endpoint:

{
    &quot;title&quot;: &quot;Article One&quot;,
    &quot;url&quot;: &quot;http://article-one.example.com&quot;,
    &quot;keywords&quot;: [&quot;new&quot;, &quot;stuff&quot;]
}

And this payload to list endpoint. Then it returns the new created article:

{
    &quot;keywords&quot;: [&quot;new&quot;]
}

Whereas the one below would return both articles.

{
    &quot;keywords&quot;: [&quot;stuff&quot;]
}

A few notes:

  1. Using keywords as a list to improve the filtering (instead of string).
  2. The pseudo-database will reset every time you reload the server. So objects you create using the endpoint will be deleted.

huangapple
  • 本文由 发表于 2023年2月26日 23:13:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/75572931.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定