angularjs - Django DRF 外键
问题描述
这个问题或许多类似的问题已被多次询问,但由于某种原因我无法找到答案。
我确实有这个工作方式,如果你继续访问 api 页面,它会毫无问题地呈现、创建和更新。问题是显示嵌套对象中的字段(标题),而不仅仅是前端的主键。
在进入代码之前的一些背景:
Races 是一个有限列表(例如 Race1、Race2、Race3),前端没有能力添加更多。
卡片不是有限的,但每张卡片都必须链接到现有的种族(目前通过主键这样做)。
前端应显示链接比赛的 card_text 和比赛标题。它还可以添加新卡,但这很好用。
我已经使用单独的序列化程序进行读取和创建/更新,其中读取具有“深度 = 1”以拉动整个对象,但创建/更新没有,然后您解析对象并将主键发送回(我在序列化程序中找不到这样做的方法,有可能吗?)。
所以基本上我的问题是,你是打算传递整个对象并在 POST 方法上解析它,还是传递主键并拉入链接对象(Races)并使用主键作为索引(例如 Races [card_race])。另外,为什么“linked_race”没有进入前端?
我意识到我几乎已经回答了自己的问题,但是由于我是 Django 新手,我正在寻找正确的约定,谁知道呢,在寻找相同答案时可能会节省其他人的时间。
网址.py
from .api import CardViewSet, RaceViewSet
from rest_framework.routers import DefaultRouter
from django.conf.urls import url, include
from .views import landing
router = DefaultRouter()
router.register(r'cards', CardViewSet)
router.register(r'races', RaceViewSet)
urlpatterns = [
url(r'^$', landing),
url(r'^api/', include(router.urls)),
]
api.py
from rest_framework.viewsets import ModelViewSet
from .serializers import CardSerializer, RaceSerializer
from .models import Card, Race
class CardViewSet(ModelViewSet):
queryset = Card.objects.filter(active=True)
def get_serializer_class(self):
return CardSerializer
def perform_create(self, serializer):
serializer.save(creator=self.request.user)
class RaceViewSet(ModelViewSet):
queryset = Race.objects.filter(active=True)
serializer_class = RaceSerializer
模型.py
from django.db import models
from django.conf import settings
User = settings.AUTH_USER_MODEL
class Race(models.Model):
id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=30, blank=False)
active = models.BooleanField(default=True)
def __str__(self):
return "{}".format(self.title)
def __unicode__(self):
return self.title
class Card(models.Model):
card_text = models.CharField(max_length=100, blank=False)
card_description = models.CharField(max_length=100, blank=True)
card_race = models.ForeignKey(Race, related_name='linked_race', on_delete=models.CASCADE)
creator = models.ForeignKey('auth.User', on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
active = models.BooleanField(default=True)
def __str__(self):
return self.card_text
class Meta:
ordering = ('created',)
序列化程序.py
from rest_framework import serializers
from .models import Card, Race
class RaceSerializer(serializers.ModelSerializer):
class Meta:
model = Race
fields = '__all__'
class CardSerializer(serializers.ModelSerializer):
linked_race = RaceSerializer(read_only=True, many=True)
class Meta:
model = Card
fields = 'id', 'card_text', 'card_description', 'card_race', 'linked_race',
Javascript 提取 (AngularJS)
$http.get('/api/races/').then(function (response) {
$scope.races = response.data;
$scope.selectedOption = $scope.races[0];
});
$scope.cards = [];
$http.get('/api/cards/').then(function (response) {
$scope.cards = orderBy(response.data, 'created', true);
});
html 提取(AngularJS)
<div class="races--row" ng-repeat="c in cards | filter : card_filter |
orderBy : sortVal : sortDir" ng-class-odd="'odd'" ng-click="openModal(c)">
<div class="races--cell race">{{ c.card_race.title }}</div>
<div class="races--cell card-text">{{ c.card_text }}</div>
</div>
解决方案
您的第一个“问题”与Card
模型有关(我说问题是因为我认为您不打算这样做)。您正在related_name='linked_race'
为该card_race
领域定义。这related_name
是您用来指代来自种族的卡片的名称。
我建议您将其忽略并使用 Django 已经提供给我们的默认值(即my_race.card_set.all()
在这种情况下)。因此,将模型中的该字段更改Card
为:
class Card(models.Model):
...
card_race = models.ForeignKey(Race, on_delete=models.CASCADE)
...
让我们将卡序列化程序更改为:
class CardSerializer(serializers.ModelSerializer):
# no more linked_race
class Meta:
model = Card
fields = ('id', 'card_text', 'card_description', 'card_race')
好的,这是一个不同的基本模型序列化程序,您还不会看到比赛的详细信息。所以现在让我们来解决您想要的主要问题:
- 查看卡片相关种族的详细信息
- 使用相同的序列化程序执行创建/获取/更新/删除操作
为此,让我们进一步更改CardSerializer
以包含另一个名为 的字段race_detail
:
class CardSerializer(serializers.ModelSerializer):
race_detail = RaceSerializer(source='card_race', read_only=True)
class Meta:
model = Card
fields = ('id', 'card_text', 'card_description', 'card_race', 'race_detail')
我们为同一个模型字段定义了两个序列化器字段。注意source
和read_only
属性。这使得该字段在您获取卡片时可用(这是我们想要的),但在您执行 POST 或 PUT 时不可用(这避免了发送整个比赛对象和解析等问题)。您可以只发送该card_race
字段的比赛 ID,它应该可以工作。
推荐阅读
- android - 尝试在空对象引用上调用虚拟方法“java.lang.String com.register.register.file.User.getName()”
- java - 如何在Java编程中循环代码块
- php - 如何在 Angular、mysql、php 和 node 中制作 Web 应用程序的安装程序
- html - 使用 BootStrap 的 HTML 选项卡
- swift - 如何在特定的视图控制器中以编程方式(swift)隐藏状态栏?
- javascript - Axios - 防止 .then() 在 http 错误上执行
- python - 使用 skip_header 时在 genfromtxt 中获取标题
- mysql - 在 MySQL 中创建和更新列
- bash - 终端查找具有最新补丁号的文件
- ruby-on-rails - rspec 中是否有“非”等价物,例如“and_return”的逻辑非