【问题标题】:Django-Rest-Framework updating a foreign key BY IdDjango-Rest-Framework 通过 Id 更新外键
【发布时间】:2013-10-24 21:10:58
【问题描述】:

我正在使用 django-rest-framework 来构建后端。我的列表运行良好,但是(使用 django-rest-framework 管理屏幕)我无法仅使用外键对象的 Id 字段来创建对象。我希望我的配置不正确,但如果我必须写一些代码,我愿意:) 我正在从 .NET 和 Java 背景学习 django/python,并且可能已经被这个新堆栈宠坏了。

编辑:我试图不使用两个不同的模型类——我不应该这样做吗?

提前致谢。

来自 Chrome - 请求的关键位

Request URL:http://127.0.0.1:8000/rest/favorite_industries/ 
Request Method:POST 
_content_type:application/json
_content:{
    "user_id": 804    ,"industry_id": 20 }

回应

HTTP 400 BAD REQUEST
Vary: Accept
Content-Type: text/html; charset=utf-8
Allow: GET, POST, HEAD, OPTIONS

{
    "user": [
        "This field is required."
    ]
}

呃。以下是 django 的关键类:

class FavoriteIndustry(models.Model):
    id = models.AutoField(primary_key=True)
    user = models.ForeignKey(User, related_name='favorite_industries')
    industry = models.ForeignKey(Industry)

    class Meta:
        db_table = 'favorites_mas_industry'

class FavoriteIndustrySerializer(WithPkMixin, serializers.HyperlinkedModelSerializer):
    class Meta:
        model = myModels.FavoriteIndustry
        fields = (
            'id'
            , 'user'
            , 'industry'
        )

编辑添加视图集:

class FavoriteIndustriesViewSet(viewsets.ModelViewSet):
    #mixins.CreateModelMixin, viewsets.GenericViewSet):
    paginate_by = 1
    queryset = myModels\
        .FavoriteIndustry\
        .objects\
        .select_related()
    print 'SQL::FavoriteIndustriesViewSet: ' + str(queryset.query)
    serializer_class = mySerializers.FavoriteIndustrySerializer

get/list 功能生成不错的 JSON:

{“计数”:2,“下一个”: "http://blah.com/rest/favorite_industries/?page=2&format=json", “上一个”:空,“结果”:[{“id”:1,“用户”: “http://blah.com/rest/users/804/”、“行业”:{“行业 ID”: 2、“industry_name”:“Consumer Discretionary”、“parent_industry_name”: "Consumer Discretionary", "category_name": "Industries"}}]}

【问题讨论】:

  • 请分享您用于 API 的查看代码。
  • 共享这就是我使用 django-rest-framework 的所有代码。等待有 viewSet 但我不明白它有多重要。基本上 url 被路由到 viewSet 并且 REST 很神奇:)
  • 您是否尝试过传递user 而不是user_id

标签: django django-rest-framework


【解决方案1】:

这样就可以了。但我认为 django-rest-framework 应该为我提供这种管道,所以请跟进任何更好的答案

class FavoriteIndustriesViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    paginate_by = 1
    queryset = myModels\
        .FavoriteIndustry\
        .objects\
        .select_related()
    print 'SQL::FavoriteIndustriesViewSet: ' + str(queryset.query)
    serializer_class = mySerializers.FavoriteIndustrySerializer

    def create(self, request):
        print(request.DATA)
        user_id = request.DATA['user_id']
        industry_id = request.DATA['industry_id']
        favorite = myModels.FavoriteIndustry(user_id=user_id, industry_id=industry_id)
        favorite.save()
        responseData = {
            'user_id': user_id
            , 'industry_id': industry_id
            , 'message': 'FavoriteIndustry saved.'
        }
        return Response(responseData)

【讨论】:

  • 您正在解决自己创建的问题。传递user_idindustry_id 是主要问题,你的这个实现可以按照你想要的方式工作,但这不是DRF 开箱即用的方式。如果你想看魔术,请通过 userindustry
  • “我明白了”,盲人说。我没有将用户对象存储在客户端上,我确实保留了 user_id。
  • 您不需要实际的对象,您需要将 URL 传递给该对象,因为您使用的是HyperlinkedModelSerializer,即"user": "http://blah.com/rest/users/804/"
【解决方案2】:

我已经为您的应用创建了一个简化的模型。

models.py:

from django.db import models
from django.contrib.auth.models import User

class Industry(models.Model):
    name = models.CharField(max_length=128)

class FavoriteIndustry(models.Model):
    user = models.ForeignKey(User, related_name='favorite_industries')
    industry = models.ForeignKey(Industry)

views.py:

from rest_framework import viewsets
from models import FavoriteIndustry
from serializers import FavoriteIndustrySerializer

class FavoriteIndustriesViewSet(viewsets.ModelViewSet):
    queryset = FavoriteIndustry.objects.all()
    serializer_class = FavoriteIndustrySerializer

serializers.py:

from rest_framework import serializers
from models import FavoriteIndustry, Industry

class FavoriteIndustrySerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = FavoriteIndustry
        fields = ('id', 'user', 'industry')

urls.py:

from django.conf.urls import patterns, include, url
from core.api import FavoriteIndustriesViewSet

favorite_industries_list = FavoriteIndustriesViewSet.as_view({
    'get': 'list',
    'post': 'create'
})

urlpatterns = patterns('',
    url(r'^favorite_industries/$', favorite_industries_list, name='favorite-industries-list'),
    url(r'^users/(?P<pk>[0-9]+)/$', favorite_industries_list, name='user-detail'),
    url(r'^industries/(?P<pk>[0-9]+)/$', favorite_industries_list, name='industry-detail'),
)

这里有一些测试:

>>> 
>>> import json
>>> from django.test import Client
>>> from core.models import Industry
>>> 
>>> industry = Industry(name='candy')
>>> industry.save()
>>> 
>>> c = Client()
>>> 
>>> response = c.get('http://localhost:8000/favorite_industries/')
>>> response.content
'[]'
>>> 
>>> data = {
...     'user': 'http://localhost:8000/users/1/',
...     'industry': 'http://localhost:8000/industries/1/'
... }
>>> 
>>> response = c.post('http://localhost:8000/favorite_industries/', json.dumps(data), 'application/json')
>>> response.content
'{"id": 1, "user": "http://testserver/users/1/", "industry": "http://testserver/industries/1/"}'
>>> 
>>> response = c.get('http://localhost:8000/favorite_industries/')
>>> response.content
'[{"id": 1, "user": "http://testserver/users/1/", "industry": "http://testserver/industries/1/"}]'
>>> 

Django REST Framework 需要 userindustry 字段作为 URL 而不是 id,因为您使用的是 HyperlinkedModelSerializer


使用 ID

如果您需要使用对象 id 而不是 URL,请使用 ModelSerializer 而不是 HyperlinkedModelSerializer 并将 id 传递给 userindustry

serializers.py:

from rest_framework import serializers
from models import FavoriteIndustry, Industry

class FavoriteIndustrySerializer(serializers.ModelSerializer):
    class Meta:
        model = FavoriteIndustry
        fields = ('id', 'user', 'industry')

和测试:

>>> 
>>> import json
>>> from django.test import Client
>>> from core.models import Industry
>>> 
>>> #industry = Industry(name='candy')
>>> #industry.save()
>>> 
>>> c = Client()
>>> 
>>> response = c.get('http://localhost:8000/favorite_industries/')
>>> response.content
'[{"id": 1, "user": 1, "industry": 1}, {"id": 2, "user": 1, "industry": 1}]'
>>> 
>>> data = {
...     'user': 1,
...     'industry': 1
... }
>>> 
>>> response = c.post('http://localhost:8000/favorite_industries/', json.dumps(data), 'application/json')
>>> response.content
'{"id": 3, "user": 1, "industry": 1}'
>>> 
>>> response = c.get('http://localhost:8000/favorite_industries/')
>>> response.content
'[{"id": 1, "user": 1, "industry": 1}, {"id": 2, "user": 1, "industry": 1}, {"id": 3, "user": 1, "industry": 1}]'
>>> 

【讨论】:

  • 我实际上并没有关注 HyperlinkSerializer 中的超链接,因此我想知道是否有更好的序列化程序可以使用。我可能有一些阅读要做。
  • 使用ModelSerializer 方法更新了答案。
  • 感谢您的回答!如果可以将包含“class FavoriteIndustriesViewSet(viewsets.ModelViewSet):”的代码片段更新为“views.py:”而不是“urls.py”,那将非常有帮助。否则,很棒的帖子。
猜你喜欢
  • 2017-08-15
  • 2016-01-09
  • 2014-03-24
  • 1970-01-01
  • 2017-04-14
  • 2021-06-25
  • 2014-07-30
  • 2016-01-29
  • 2019-02-12
相关资源
最近更新 更多