【发布时间】:2016-09-14 14:04:50
【问题描述】:
我正在创建一个 Django (1.8) 网络应用程序,用于保存赛车圈速和记分牌。该数据库是使用使用 Django Rest Framework 构建的 API 填充的。这是我第一次尝试使用 rest 框架构建适当的 api。
模型概览:
- 活动,赛车活动/周末
- 会议,单场比赛/练习/资格赛 - FK 赛事
- 汽车,参加会话的汽车 - FK 会话
- 圈数,特定汽车的圈数 - FK 车
事件是手动创建的,但其余的应该是“动态的”(获取或创建)
现在我正在尝试使用我的 API 创建一辆新车,但我被卡住了。为了获得汽车事件和会话,我正在尝试使用 url; /api/results/skrotbilsracet-29042016/r1/cars/
这个想法是将数据发布到这个 url 并“获取或创建”一个新的汽车对象。 要为新车会话 FK 获取正确的会话对象,我需要使用一个自定义函数来获取 kwargs 并尝试查找会话。
我越了解如何解决这个问题,我就越困惑。
有人能把我推向正确的方向吗?
这是我解决这个问题的最新尝试,它只给了我“{“session”:[“This field is required.”]}”
models.py
class Session(models.Model):
session_types = (
('p', 'Practice'),
('q', 'Qualification'),
('r', 'Race')
)
event_id = models.ForeignKey(Event, related_name='sessions')
name = models.CharField(max_length=2, blank=True)
current_session = models.BooleanField(default=True)
session_type = models.CharField(max_length=2,
choices=session_types)
started = models.DateTimeField(auto_now_add=True)
ended = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['started']
def save(self):
if not self.name:
# Get number of sessions
session_count = Session.objects.filter(event_id=self.event_id)\
.filter(session_type=self.session_type)\
.count()
session_count += 1
self.name = self.session_type + str(session_count)
super(Session, self).save()
def __unicode__(self):
string = self.started.strftime("%d-%m-%Y %H:%M") + ' - '
string += self.name.upper()
return(string)
class Car(models.Model):
session = models.ForeignKey(Session, related_name='cars')
number = models.IntegerField()
full_name = models.CharField(max_length=256, blank=True)
short_name = models.CharField(max_length=256, blank=True)
race_class = models.CharField(max_length=50, blank=True)
best_lap = models.IntegerField(blank=True, null=True)
best_lap_time = models.CharField(max_length=20, blank=True)
best_sector1 = models.CharField(max_length=20, blank=True)
best_sector2 = models.CharField(max_length=20, blank=True)
best_sector3 = models.CharField(max_length=20, blank=True)
best_speed = models.IntegerField(blank=True, null=True)
pitstops = models.IntegerField(blank=True, null=True)
total_time = models.CharField(max_length=20, blank=True)
transponder = models.CharField(max_length=50, blank=True)
apiUrls.py
urlpatterns = [
url(r'^raceslug/$', raceSlugView.as_view(), name='race-slug'),
url(r'^events/$', eventsView.as_view(), name='event-list'),
url(r'^session/$', getSessionView.as_view(), name='session-pk'),
url(r'^(?P<event_id>[a-z0-9\-]+)/$', eventView.as_view(), name='event-detail'),
url(r'^(?P<event_id>[a-z0-9\-]+)/(?P<name>[a-z0-9\-]+)/$', sessionView.as_view(), name='session-detail'),
url(r'^(?P<event_id>[a-z0-9\-]+)/(?P<name>[a-z0-9\-]+)/cars/$', carsView.as_view(), name='car-list'),
url(r'^(?P<event_id>[a-z0-9\-]+)/(?P<name>[a-z0-9\-]+)/(?P<number>[0-9]+)/$', carView.as_view(), name='car-detail'),
]
urlpatterns = format_suffix_patterns(urlpatterns)
api.py
class carsView(generics.ListCreateAPIView):
serializer_class = carSerializer
def get_session(self, event_id, name):
print('Getting session')
# Get event object
try:
event = Event.objects.get(event_id=event_id)
print('Found event')
except ObjectDoesNotExist:
print('Did not find event')
return
# Get session object
try:
session = event.sessions.get(name=name)
print('Found session: ', session)
return session
except ObjectDoesNotExist:
print('Did not find session')
return
def get_queryset(self):
print('Getting queryset')
print('event_id: ' + self.kwargs['event_id'])
print('name: ' + self.kwargs['name'])
session = self.get_session(self.kwargs['event_id'], self.kwargs['name'])
return(Car.objects.filter(session=session.pk))
def perform_create(self, serializer):
print('Creating new car')
session = self.get_session(self.kwargs['event_id'], self.kwargs['name'])
serializer.save(session=session)
serializers.py
class carSerializer(serializers.ModelSerializer):
laps = lapSerializer(many=True, read_only=True)
class Meta:
model = Car
fields = (
'session',
'number',
'full_name',
'short_name',
'race_class',
'best_lap',
'best_lap_time',
'best_sector1',
'best_sector2',
'best_sector3',
'best_speed',
'pitstops',
'total_time',
'transponder',
'laps')
解决方案:
这是我实际更改以使其正常工作的内容。
api.py
from rest_framework.serializers import ValidationError
class carsView(generics.ListCreateAPIView):
...
def perform_create(self, serializer):
print('Creating new car')
session = self.get_session(self.kwargs['event_id'], self.kwargs['name'])
number = self.request.POST.get('number')
car = session.cars.filter(number=number)
if car.exists():
raise ValidationError('Car already exists')
serializer.save(session=session)
serializers.py
class carSerializer(serializers.ModelSerializer):
laps = lapSerializer(many=True, read_only=True)
session = serializers.StringRelatedField(required=False)
...
【问题讨论】:
-
在您的汽车模型中添加空白=True,或在发布汽车时提供会话 ID(或超链接,如果它是 HyperlinedModelSerializer)。
-
这是我的实际问题,提供从 url 中提取的会话 id 的工作方式是什么(可能使用我的 get_session 函数)?该会话是必需的,否则我只会让汽车物体漂浮在周围,而不会与任何实际比赛相关。
-
您使用什么来访问您的 API?任何API客户端或smth?还是 DRF 的 API 浏览器?如果是 DRF 的浏览器,那么应该有一个张贴表格,您应该可以在那里看到它。如果某些客户端,例如 Pycharm 的客户端或 Postman,那么您必须将其添加到 POST 参数中(在 Postman 中,当您选择 POST 方法时,它位于 Body 中
-
我更新了我的答案。我将其添加到答案中是因为我想在那里粘贴代码
标签: django django-rest-framework