在Django中使用Rest API

时间:2018-01-06 20:09:38

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

是否可以创建一个使用REST API作为外键的模型字段?

我有两个项目。第一个项目在models.py中有这个模型:

from django.db import models
from django_countries.fields import CountryField
from django.urls import reverse

class Currency(models.Model):
    name = models.CharField(max_length = 50)
    country = CountryField()
    code = models.CharField(max_length = 3)
    base = models.BooleanField()

    class Meta:
        ordering = ['code']

    def __str__(self):
        return (self.code)

    def get_absolute_url(self):
        return reverse('currency_detail', args = [str(self.id)])

我使用serializers.py中的以下代码序列化了模型:

from rest_framework import serializers
from currencies . models import Currency

class CurrencySerializer(serializers.ModelSerializer):
    class Meta:
        model = Currency
        fields = ('name', 'code')

我创建了以下views.py:

from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser

from currencies . models import Currency
from . serializers import CurrencySerializer


def currency_list(request):
    currency = Currency.objects.all()
    serializer = CurrencySerializer(currency, many = True)
    return JsonResponse(serializer.data, safe = False)

并在urls.py中提供以下内容:

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^currencies/$', views.currency_list),
]

URL以JSON格式传递信息ok。没有身份验证(我还不够好)。当我使用请求库并发出get请求时,它返回以下内容:

[{"name": "Krone", "code": "DKK"}, {"name": "Pound Sterling", "code": "GBP"}, {"name": "Cedi", "code": "GHS"}]

我想在新项目中使用此信息,该项目将使用以下模型具有不同的数据库和帖子记录:

class JournalEntry(models.Model):
    date = DateField()
    currency = ForeignKey(consuming the json data so it renders as a dropdown menu in html)
    value = IntegerField()

有没有办法做这样的事情?我还没有找到任何可以帮助我正确理解这一点的回复。这也是为了帮助我学习。我打算用这种基于API的方法实现更复杂的项目。谢谢。

1 个答案:

答案 0 :(得分:1)

你必须用API改变你的思维方式。 API是一个数据源,您必须问自己,您将如何使用此数据源以及您接收的数据类型。

您将如何实施API取决于答案。在许多情况下,API充当数据库。您不是查询数据库而是查询API,而是从这个角度来看,将这些数据存储在另一个数据库中然后从那里查询相同的数据并没有多大意义。然而,当API仅提供当前数据而非历史数据时,您也希望获得历史数据。在这种情况下,将数据存储在数据库中是完全合理的。还有其他情况,但这两种情况可能是最常见的情况。

如果您将其转换为您的案例,则可以首选使用数据而不进行存储,因为您可能希望用户只能选择当前可用的货币。这种情况下的代码是:

models.py

class JournalEntry(models.Model):
    date = DateField()
    currency = CharField(max_length=4)
    value = IntegerField()

forms.py

class JournalEntryForm(forms.ModelForm):
    class Meta:
        model = JournalEntry
        fields = '__all__'

views.py

def currency(request):
    form = JournalEntryForm()
    r = requests.get('currencies_url')
    currencies = r.json()
    if form.is_valid():
        form.save()

    return render(request, 'currency.html', {'currencies': currencies, 'form': form})

currency.html

<html>
  <body>
    <form method="POST">{% csrf_token %}
      {% for field in form %}
      <p>{{ field.date }}</p>
      <p>
        <select name="currency" id="id_currency" required="">
          {% for currency in currencies %}
          <option value="{{ currency.code }}">{{ currency.name }}</option>
          {% endfor %}
        </select>
      </p>
      <p>{{ field.value }}</p>
      <input type="submit" value="Save">
    </form>
  </body>
</html>

如果您希望将货币日期保存在数据库中,无论出于何种原因,您首先需要创建包含从API接收的数据的条目。代码想要这样的东西:

models.py

class Currency(models.Model):
    name = models.CharField(max_length=50)
    code = models.CharField(max_lenght=4)

class JournalEntry(models.Model):
    date = DateField()
    currency = ForeignKey(Currency)
    value = IntegerField()

forms.py

... same as before ...

views.py

def get_currencies(request):
    r = requests.get('currencies_url')
    currencies = r.json()
    currency_data = []
    for currency in currencies:
        c = Currency()
        c.name = currency['name']
        c.code = currency['code']
        currency_data.append(c)

   if len(currency_data) > 0:
       bulk_create  = Currency.objects.bulk_create(currency_data)

   return HttpResponse('Done!')

def currency(request):
    form = JournalEntryForm()
    if form.is_valid():
        form.save()

    return render(request, 'currency.html', {'form': form})

currency.html

<html>
  <body>
    <form method="POST">{% csrf_token %}
      {{ form.as_p }}
      <input type="submit" value="Save">
    </form>
  </body>
</html>

代码有点简化,但显示了一个基本原则。我使用bulk_create来保存从API接收的货币数据,因为它只有1个查询以有效的方式插入对象列表。其余的应该是不言自明的。