Отправка словаря Python с помощью одного метода POST в Django REST Framework - PullRequest
1 голос
/ 15 марта 2020

Я пытался реализовать этот метод несколькими способами, в которых кажется, что он должен быть довольно простым. У меня есть веб-скребок, который собирает данные о запасах и сохраняет их в словаре Python в сценарии python. Затем он отправляет запрос на мой Django API, который обрабатывается в моих представлениях с использованием GenericAPIView. Этот почтовый запрос отправляет QueryDict, и я могу опубликовать один экземпляр, но не несколько одновременно.

Да, я установил many=True на моем сериализаторе и попытался переопределить эти методы. Каждое решение, которое я принял, неэффективно, и я разочарован тем, что не нашел ясного и простого решения. Я впервые работаю с Django Rest Framework, так что будьте терпеливы и заранее благодарим вас за вашу помощь!

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 (тестировал с инициалом, принимающим много)

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. Теперь получаю ошибку Bad Request от сериализатора, которая не проходит проверку serializer.is_valid(). Если я удаляю raise_exception=True, тогда мой create () не получает никаких переданных данных. Вот как форматируется мой массив JSON, если он правильный, я не знаю: [{"id": 0, "name": "Bitcoin USD", "price": "5314.87", "change": "+54.02", "percentChange": "+1.03"}, Еще раз спасибо за помощь, он очень ценится. как я рад продолжать совершенствовать этот проект!

UPDATE (2): В соответствии с запросом, здесь приведены точные данные JSON, переданные в сериализатор методом create(). Это не все данные, но это точный формат [{"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) в моем сериализаторе. Все, что возвращается, это {}. Вот моя модель Crypto Models.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

1 Ответ

0 голосов
/ 16 марта 2020

ОК, сначала прочитайте этот пример, чтобы узнать больше о создании нескольких одновременно.

Ваша проблема заключается просто в формате, который вы передали в публикацию.

В 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() до l oop в двух или более списках одновременно, поэтому вы создаете Завершить объект сразу, или что вы хотите, есть слишком много способов.

ОБНОВЛЕНИЕ: Как совет, самое простое, что вы можете сделать для создания массива словарей, это

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)

Нет te : я предположил, что каждый ребенок for loop работает только один раз, потому что это одна строка, так как я не эксперт по супам, я позволю вам справиться с этим.

Тогда вы можете передать данные или использовать json.dump() или что-то еще, он читается для использования сейчас

ОБНОВЛЕНИЕ 2 : примените json.dump() к каждому dict внутри l oop, затем примените его еще раз к массиву.

crypto.append(json.dump(listing_dic))

затем data=json.dump(stocks)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...