Python 如何思考Django';s普通的基于类的视图与使用REST API的视图

Python 如何思考Django';s普通的基于类的视图与使用REST API的视图,python,angularjs,django,rest,django-rest-framework,Python,Angularjs,Django,Rest,Django Rest Framework,我一直在用Django编写一个网络应用程序,以取代我和一些朋友玩的笨拙的、基于电子表格的运动选秀游戏。我学到了很多,并且花了很长时间了解Django以及如何从头开始构建类似的东西 我最近意识到,我想在前端使用更强大的东西(余烬、Angular等),最终目标是一个单页应用程序。为此,我安装了Django REST框架(DRF),并开始阅读文档和学习教程。这非常有趣,我终于开始明白为什么带有API的客户机-服务器模型是实现平滑交互的唯一途径,而这一切现在都结束了 我试图将我的一个基于类的视图实现为A

我一直在用Django编写一个网络应用程序,以取代我和一些朋友玩的笨拙的、基于电子表格的运动选秀游戏。我学到了很多,并且花了很长时间了解Django以及如何从头开始构建类似的东西

我最近意识到,我想在前端使用更强大的东西(余烬、Angular等),最终目标是一个单页应用程序。为此,我安装了Django REST框架(DRF),并开始阅读文档和学习教程。这非常有趣,我终于开始明白为什么带有API的客户机-服务器模型是实现平滑交互的唯一途径,而这一切现在都结束了

我试图将我的一个基于类的视图实现为API端点,但在概念化它时遇到了很多困难。我想我应该从一个简单的、只能获取的端点开始——下面是我试图以API形式复制的简单CBV:

class MatchupDetail(DetailView):
  template_name = 'app/matchups.html'
  context_object_name = 'pick_sheet'

  def get_object(self):
    #logic to find and return object

  def get_opponent(self,username,schedule,week, **kwargs):
    #logic to find and return the opponent in the matchup

  def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    #logic to pull the opponents details and set them in the context
我觉得我对这个流有一个控制柄——用户单击一个链接,这个视图检索请求页面中心的对象,在上下文中用内容补充它,然后呈现它

当我开始考虑将其转换为API端点时,它没有什么意义。我应该将所有与用户相关的数据放在一个JSON响应中吗?或者前端应该基本上处理这个逻辑流,而API只是由一组端点组成——例如,一个用于检索对象,一个或多个用于检索当前在上下文中传递的内容

促使我发表这篇文章的原因是,我对上述视图的(super basic)API实现遇到了一些问题:

class MatchupDetailApi(generics.ListAPIView):

  queryset = Sheet.objects.all()
  serializer_class = SheetSerializer
使用序列化程序:

class SheetSerializer(serializers.ModelSerializer):
  user = serializers.ReadOnlyField()

  class Meta:
    model = Sheet
当我注意到没有用户字段时,返回的序列化工作表对象实际上就是数据库中的行——一个整数ID,用户对象的整数外键,等等。使用“传统”CBV,整个对象都会返回到模板,因此访问相关字段非常直观,而使用Django,也可以轻松遍历对象关系

REST实现提供了同样的功能吗?从我所读到的内容来看,似乎我需要对DRF(django rest multiple models)进行扩展,以便在一个响应中返回多个模型,这让我认为我应该为每个模型创建端点,并将表示逻辑留给我处理前端时使用。这是典型的吗或者让一个API端点返回像一个对象和几个相关对象这样的东西是可行的吗?

注意:当我将用户添加到SheetSerializer时,上面的基本端点停止工作。我意识到我也应该有一个UserSerializer,它是:

class UserSerializer(serializers.HyperlinkedModelSerializer):
  class Meta:
    model = User
然而,当我尝试浏览API时,我得到一个TypeError,即第一个用户不可序列化。具体来说:
不是可序列化的JSON
。这不是UserSerializer的作用吗

有一个返回如下内容的API端点可行吗 一个对象和几个相关对象

对!

听起来你有了一个很好的开始。我会这样构造它:

class UserSerializer(serializers.ModelSerializer):
    """serializes a user"""
    class Meta:
        model = User
        fields = ('id', 'first_name', 'last_name',)


class SheetSerializer(serializers.ModelSerializer):
    """serializes a sheet, and nests user relationship"""
    user = UserSerializer(read_only=True)

    class Meta:
        model = Sheet
        fields = ('id', 'sheet_name', 'user',)

我不认为您需要django rest多个模型来实现您想要实现的目标。在我的草图(我猜的是字段名)中,您将序列化工作表以及关联的用户对象。

您可以使用源属性从另一个相关模型添加字段

例如:

class SheetSerializer(serializers.ModelSerializer):
  user_id = serializers.ReadOnlyField(source='user.user_id')
  username = serializers.ReadOnlyField(source='user.username')

  class Meta:
    model = Sheet

在这里,序列化程序将从与图纸模型相关的用户模型返回信息。

非常感谢!这就更有意义了——我不知道为什么我没有将用户设置为使用UserSerializer。再次感谢-我现在不觉得很失落!后续问题:如果我想将其视为在端点返回的对象,我必须按照您所示设置所有关系-正确吗?和中一样,我需要添加每个外键关系,以便包含相关的“对象”。我在想一个为什么没有人会这么做的原因——我想一定有什么原因。是的,没错。如果您使用像Ember这样的东西,您可以只返回相关id,而不是序列化用户对象,您可以使用
user=[1,2,3]
哪个Ember连接在一起。太棒了-谢谢。在研究前端框架时,我将研究类似的有用内容。最后一个问题,我保证。我现在一直在使用Django模型表单和表单集来完成一些事情,但是一旦编写了API,这是没有意义的吗?表单将位于前端,但我觉得将它们作为可由服务器解析的新/现有模型的集合发布到端点是有意义的。这有意义吗?将这些数据发布到端点而不是使用django模型表单肯定有意义。顺便说一下,我不确定在前端生成表单的最有效方式,但ember(和主干网等)可以轻松地将数据发布/同步到端点