为了实现REST风格的Web API,我最近开始使用Django REST框架(以及Django和Python--我是一个RTOS /嵌入式系统人员!)。目前还没有任何问题无法用Google解决,但是这个问题让我现在陷入了几个小时的困境。Django REST框架 - 发布包含自然键的外键字段?
我有一个嵌入式系统,用于监听与一系列设备相关的事件 - 类似于拨打电话的电话,这是我在这里为简洁起见而讨论的。一个电话有一个号码和一大堆呼叫(它已经)与之相关联。呼叫具有关联的电话(发起呼叫的电话)和创建时间。发生呼叫时,应将其发送到API。我有一个嵌入式系统,用于监听呼叫及其始发电话号码,并将它们提交给API。由于嵌入式系统知道电话号码,我希望它提交:{"srcPhone":12345678}
而不是{"srcPhone":"http://host/phones/5"}
。这样可以避免我的嵌入式系统需要知道每个电话的主键(或每次拨打电话时都按编号获取电话)。
Google和Django文档建议我可以用自然键实现这一点。我尝试如下:
models.py
from django.db import models
from datetime import datetime
from pytz import timezone
import pytz
from django.contrib.auth.models import User
# Create your models here.
def zuluTimeNow():
return datetime.now(pytz.utc)
class PhoneManager(models.Manager):
def get_by_natural_key(self, number):
return self.get(number=number)
class Phone(models.Model):
objects = PhoneManager()
number = models.IntegerField(unique=True)
#def natural_key(self):
# return self.number
class Meta:
ordering = ('number',)
class Call(models.Model):
created = models.DateTimeField(default=zuluTimeNow, blank=True)
srcPhone = models.ForeignKey('Phone', related_name='calls')
class Meta:
ordering = ('-created',)
views.py
# Create your views here.
from radioApiApp.models import Call, Phone
from radioApiApp.serializers import CallSerializer, PhoneSerializer
from rest_framework import generics, permissions, renderers
from rest_framework.reverse import reverse
from rest_framework.response import Response
from rest_framework.decorators import api_view
@api_view(('GET',))
def api_root(request, format=None):
return Response({
'phones': reverse('phone-list', request=request, format=format),
'calls': reverse('call-list', request=request, format=format),
})
class CallList(generics.ListCreateAPIView):
model = Call
serializer_class = CallSerializer
permission_classes = (permissions.AllowAny,)
class CallDetail(generics.RetrieveDestroyAPIView):
model = Call
serializer_class = CallSerializer
permission_classes = (permissions.AllowAny,)
class PhoneList(generics.ListCreateAPIView):
model = Phone
serializer_class = PhoneSerializer
permission_classes = (permissions.AllowAny,)
class PhoneDetail(generics.RetrieveDestroyAPIView):
model = Phone
serializer_class = PhoneSerializer
permission_classes = (permissions.AllowAny,)
serializers.py
from django.forms import widgets
from rest_framework import serializers
from radioApiApp import models
from radioApiApp.models import Call, Phone
class CallSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Call
fields = ('url', 'created', 'srcPhone')
class PhoneSerializer(serializers.HyperlinkedModelSerializer):
calls = serializers.ManyHyperlinkedRelatedField(view_name='call-detail')
class Meta:
model = Phone
fields = ('url', 'number', 'calls')
ŧ o测试,我创建了一个号码为123456的电话。然后我POST {“srcPhone”:123456}到http://host/calls/
(在urls.py中配置它来运行CallList视图)。这在/ calls/- 'int'对象的AttributeError中没有属性'startswith'。 rest_framework/relations.py中出现异常(第355行)。可以发布整个跟踪,如果它会有所帮助。在阅读关系.py时,它看起来像REST框架没有按数字查找电话,而是像处理URL一样处理srcPhone属性。这通常是真实的,但我希望它通过自然键来查找电话,而不是提供URL。我在这里错过了什么?
谢谢!
谢谢你汤姆 - 现在我只能提交一个整数srcPhone号码的呼叫。 – EwanC
刚刚找到了这个答案,并解决了我的问题!非常好解释 – zeroliu