【问题标题】:Sending a Python Dictionary Through a Single POST method in Django REST Framework通过 Django REST Framework 中的单个 POST 方法发送 Python 字典
【发布时间】:2020-06-26 13:03:14
【问题描述】:

我一直在尝试用几种方法来实现这个方法,看起来应该很简单。我有一个网络爬虫,它可以抓取股票数据并将其存储到 Python 脚本中的 Python 字典中。然后,这会向我的 Django API 发出一个发布请求,该请求在我的视图下使用GenericAPIView 处理。这个发布请求发送一个QueryDict,我可以发布一个实例,但不能同时发布多个。

是的,我在我的序列化程序上设置了many=True 并试图覆盖这些方法。我所做的每一个解决方案都是低效的,我很沮丧没有找到一个清晰而简单的解决方案。这是我第一次使用 Django Rest 框架,请多多包涵,并提前感谢您的帮助!

CryptoView(主要遵循 Medium.com 上的教程来改进我的方法)

class CryptoView(ListCreateAPIView):
    queryset = Crypto.objects.all()
    serializer_class = CryptoSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

class SingleCryptoView(RetrieveUpdateDestroyAPIView):
    queryset = Crypto.objects.all()
    serializer_class = CryptoSerializer

Cryptotest.py

crypto = []


# For Loop - Yahoo Finance requires us to crawl through specific
# attributes to find data
for listing in soup.find_all('tr', attrs={'class':'simpTblRow'}):
    listing_dict = {}
    for name in listing.find_all('td', attrs={'aria-label':'Name'}):
        listing_dict["name"] = name.text
    for price in listing.find_all('td', attrs={'aria-label':'Price (Intraday)'}):
        listing_dict["price"] = price.text.replace(',', '')
    for change in listing.find_all('td', attrs={'aria-label':'Change'}):
        listing_dict["change"] = change.text
    for percentChange in listing.find_all('td', attrs={'aria-label':'% Change'}):
        listing_dict["percentChange"] = percentChange.text.replace('%', '')
    index += 1

    crypto.append(listing_dict)

headers = {'Content-type': 'application/json'}
requests.post(url=API_ENDPOINT, json=json.dumps(crypto), headers=headers)

CryptoSerializer(使用 init 进行测试,接受很多)

class CryptoSerializer(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):
        many = kwargs.pop('many', True)
        super(CryptoSerializer, self).__init__(many=many, *args, **kwargs)

    class Meta:
        model = Crypto
        fields = ('name', 'price', 'change', 'percentChange')

    def create(self, validated_data):
        return Crypto.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.name = validated_data.get('name', instance.name)
        instance.price = validated_data.get('price', instance.price)
        instance.change = validated_data.get('change', instance.change)
        instance.volume = validated_data.get('percentChange', instance.volume)

        instance.save()
        return instance

更新: 能够将数据作为 JSON 数组发送到 post 方法。现在从serializer.is_valid() 检查失败的序列化程序中得到Bad Request 的错误。如果我删除了raise_exception=True,那么我的 create() 没有传入任何数据。这就是我的 JSON 数组的格式是否正确我不知道:[{"id": 0, "name": "Bitcoin USD", "price": "5314.87", "change": "+54.02", "percentChange": "+1.03"}, 再次感谢您的帮助,非常感谢,因为我很高兴能继续改进这个项目!

更新(2): 根据要求,这里是使用 create() 方法传递给序列化程序的确切 JSON 数据。这不是所有数据,但它是准确的格式[{"id": 107, "name": "FirstCoin USD", "price": "0.0017", "change": "-0.0012", "percentChange": "-41.52"}, {"id": 108, "name": "MCAP USD", "price": "0.0046", "change": "0.0000", "percentChange": "0.00"}, {"id": 109, "name": "ATBCoin USD", "price": "0.0011", "change": "+0.0002", "percentChange": "+17.10"}, {"id": 110, "name": "Exchange Union USD", "price": "0.6857", "change": "+0.0026", "percentChange": "+0.38"}]Bad Request: /crypto/ 在我的序列化程序中尝试 print(request.data) 时,此数据不存在。返回的只是{}。这是我的加密模型 模型.py

# Template Model
class Crypto(models.Model):
    name = models.CharField(max_length=30)           # Name of the stock
    price = models.FloatField()                        # Opening stock price
    change = models.FloatField()                      # Closing stock price
    percentChange = models.FloatField()                     # Amount of sales

    def __str__(self):
        return self.name

【问题讨论】:

  • 请将 CryptoSerializer sn-p 添加到您的问题中
  • @MahmoudAdel 更新

标签: python django rest post django-rest-framework


【解决方案1】:

好的,先读this example to know more about creating multiple at once.

您的问题只是您传递给 post 的格式。

在 JSON 中,当您传递多个对象时,我们会期待这样的结果

[
  {
    "name":"John",
    "age":30,
    "cars":[ "Ford", "BMW", "Fiat" ]
  },

  {
    "name":"Matt",
    "age":25,
    "cars":["BMW", "Fiat" ]
  },
]

如您所见,它是一个 JSON 数组。

在 DRF 中,当您创建序列化程序时,您会编写一些内容以将 JSON 转换为 一个模型 实例,反之亦然。因此,当我们有多个像上面的例子一样的对象并且我们想用它做任何事情时,我们将关键字many=True 添加到我们的序列化程序中,这样它就知道传递的数据有很多对象,而不仅仅是一个,所以它会循环它并为每一个转换。

让我们回到您创建的数据:

crypto = {
    "id": [],
    "name": [],
    "price": [],
    "change": [],
    "percentChange": []
}

这是一个字典,每个键都有一个数组,您现在可以看到为什么它根本不起作用,因为它与序列化程序的期望不匹配

当然,如果这是您想要传递的格式,我们可以在序列化程序上工作并编写一些代码并更改其字段以便处理它,但我觉得将数据构造为 JSON 数组和通过吧。

您可以使用zip() 同时在两个或更多列表上循环,这样您就可以一次创建完整的对象,或者您想要的任何方式都太多了。

更新: 作为建议,您可以做的最简单的字典数组是,

crypto = []


# For Loop - Yahoo Finance requires us to crawl through specific
# attributes to find data
for listing in soup.find_all('tr', attrs={'class':'simpTblRow'}):
    listing_dic={}
    for name in listing.find_all('td', attrs={'aria-label':'Name'}):
        listing_dic["name"] = name.text
    for price in listing.find_all('td', attrs={'aria-label':'Price (Intraday)'}):
        listing_dic["price"] = price.text.replace(',', '')
    for change in listing.find_all('td', attrs={'aria-label':'Change'}):
        listing_dic["change"] = change.text
    for percentChange in listing.find_all('td', attrs={'aria-label':'% Change'}):
        listing_dic["percentChange"] = percentChange.text.replace('%', ''))
    crypto.append(listing_dic)

注意:我假设每个孩子for loop 只跑一次,因为它是一排,因为我不是汤专家,我会让你处理这个。

然后你可以传递数据或使用json.dump() 或其他任何东西,它现在可以使用了

更新 2: 在循环内的每个字典上应用json.dump(),然后在数组上再次应用它。

crypto.append(json.dump(listing_dic))

然后data=json.dump(stocks)

【讨论】:

  • 好的,我知道了,我遇到过这种情况,但我认为我可以在序列化程序中处理它,但它一直很痛苦。那么您对实现 JSON 数组有什么建议吗?我是否应该简单地在我的字典上做一个 json.dumps 我还没有非常多地使用 JSON 数据。
  • 请再次检查我的答案,我已添加更新
  • 感谢您的建议,我遵循了您所做的工作,并且字典数组很好地填充了。但是,在执行data=stocks 的 POST 中单独发送此数据会给我错误ValueError: too many values to unpack expected 2。当我使用json.dump() 时,不支持该类型。
  • 请检查我的最新更新..遇到一个新错误但进展顺利
  • 看来我总是以某种方式遇到此错误:AttributeError: Got AttributeError when attempting to get a value for field 'name' on serializer 'CryptoSerializer'. The serializer field might be named incorrectly and not match any attribute or key on the 'str' instance. Original exception text was: 'str' object has no attribute 'name'.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-21
  • 2022-06-10
  • 1970-01-01
  • 2020-11-23
  • 2015-06-28
  • 2015-08-04
相关资源
最近更新 更多