Gần đây tôi đã bắt đầu sử dụng khung REST Django (và Django, và Python - tôi là một người hệ thống RTOS/nhúng!) Để thực hiện một RESTful Web API. Chưa có bất kỳ vấn đề nào chưa được giải quyết với Google, nhưng điều này đã khiến tôi bối rối trong một vài giờ.Khung hình Django REST - Đăng trường khóa ngoại có chứa khóa tự nhiên?
Tôi có một hệ thống nhúng lắng nghe các sự kiện được liên kết với một loạt các thiết bị - tương tự như một cuộc gọi điện thoại, đó là những gì tôi sẽ thảo luận ở đây ngắn gọn. Một điện thoại có một số và rất nhiều cuộc gọi (mà nó đã thực hiện) liên kết với nó. Một cuộc gọi có một điện thoại liên quan (điện thoại đã thực hiện cuộc gọi) và một thời gian sáng tạo. Khi một cuộc gọi xảy ra, nó sẽ được gửi đến API. Tôi có một hệ thống nhúng lắng nghe các cuộc gọi và số điện thoại gốc của họ và gửi chúng đến API. Vì hệ thống nhúng biết số điện thoại, tôi muốn gửi số điện thoại: {"srcPhone":12345678}
thay vì {"srcPhone":"http://host/phones/5"}
. Điều này tránh sự cần thiết cho hệ thống nhúng của tôi để biết khóa chính của mỗi điện thoại (hoặc để nhận được điện thoại theo số mỗi khi nó muốn gửi một cuộc gọi).
Google và tài liệu Django đề xuất tôi có thể đạt được điều này bằng các khóa tự nhiên. nỗ lực của tôi sau:
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')
T o kiểm tra, tôi tạo một Điện thoại với số 123456. Sau đó, tôi POST {"srcPhone": 123456} đến http://host/calls/
(được cấu hình trong urls.py để chạy chế độ xem Danh sách cuộc gọi). Điều này cho một đối tượng AttributeError tại/calls/- 'int' không có thuộc tính 'startswith'. Ngoại lệ xảy ra trong rest_framework/relations.py (dòng 355). Có thể đăng toàn bộ dấu vết nếu nó sẽ hữu ích. Khi đọc relations.py, có vẻ như khung REST không tra cứu điện thoại theo số, nhưng xử lý thuộc tính srcPhone như thể nó là một URL. Điều này thường đúng, nhưng tôi muốn nó tìm kiếm Điện thoại bằng khóa tự nhiên, thay vì cung cấp URL. Tôi đã bỏ lỡ điều gì ở đây?
Cảm ơn!
Cảm ơn Tom - bây giờ tôi có thể gửi các cuộc gọi chỉ với số srcPhone số nguyên. – EwanC
Chỉ tìm thấy câu trả lời này và giải quyết vấn đề của tôi! Rất tốt đẹp giải thích – zeroliu