Django DRF Foreign Key - PullRequest
       5

Django DRF Foreign Key

0 голосов
/ 11 октября 2018

Этот вопрос или многие подобные ему задавались несколько раз, но по какой-то причине я не могу найти ответ.

У меня это работает до такой степени, что если вы переходите на страницы API, он без проблем рендерит, создает и обновляет.Проблема заключается в отображении поля (заголовка) из вложенного объекта, а не только первичного ключа в интерфейсе.

Некоторый фон перед тем, как войти в код:

Гонки - это конечный список (например, Race1, Race2, Race3) и интерфейс не имеет возможности добавлять больше.

Карты не являются конечными, но каждая карта должна связываться с существующей расой (в настоящее время это делается с помощью первичного ключа).

Внешний интерфейс должен отображать текст_карты и название расы связанной расы.У него также есть возможность добавить новую карту, но это прекрасно работает.

У меня была эта работа с отдельными сериализаторами для чтения и создания / обновления, где чтение имеет «глубину = 1», чтобы пролистать всюобъект, но не создание / обновление, и вы затем анализируете объект и отправляете первичный ключ обратно (я не мог найти способ сделать это в сериализаторе, это возможно?).

Так что в основномМой вопрос заключается в том, хотите ли вы передать весь объект и проанализировать его с помощью метода POST, или вы передаете первичный ключ и извлекаете связанные объекты (Races) и используете первичный ключ в качестве индекса (например, Races [card_race]).Кроме того, почему «connected_race» не проходит через интерфейс?

Я понимаю, что почти ответил на свой вопрос, но, поскольку я новичок в Django, я ищу правильные соглашения и кто знает, это может сэкономить время при поиске того же ответа.

urls.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

models.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',)

serializers.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 extract (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>

1 Ответ

0 голосов
/ 12 октября 2018

Ваша первая «проблема» связана с моделью 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, и оно должно работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...