ОШИБКА: невозможно создать экземпляр Meal с экземпляром FK Store в views.py (Django и Django Rest Framework) - PullRequest
0 голосов
/ 28 апреля 2020

Я делаю REST API доставки, используя Django и Django Rest Framework.

В приложении Meal есть ОШИБКА, которая была в течение нескольких дней, и я не могу ее решить. Я не знаю, как это исправить.

Заранее спасибо.

Это ошибка , показанная в почтальоне:

{
    "store": {
        "non_field_errors": [
            "Invalid data. Expected a dictionary, but got Store."
        ]
}

Питание /models/meals.py

class Meal(models.Model):
    '''Meals models.'''

    store = models.ForeignKey(
        Store, 
        on_delete=models.CASCADE,
        )

    name = models.CharField(max_length=120)
    slugname = models.SlugField(
        unique=True,
        max_length=120,
        )
    description = models.TextField(max_length=300, blank=True)
    price = models.DecimalField(
        'meal price',
        max_digits=5,
        decimal_places=2
        )
    picture = models.ImageField(
        'meal picture',
        upload_to='meals/pictures/',
        blank=True,
        null=True,
        help_text="Price max up to $999.99"
    )

    # Status
    is_available = models.BooleanField(
        'Meal available in menu',
        default=True,
        help_text='Show is the items is available for customers'
    )

    # Stats
    rating = models.FloatField(
        default=5.0,
        help_text="Meal's rating based on client califications"
    )

Питание / просмотры / foods.py

class MealViewSet(mixins.ListModelMixin,
                    mixins.CreateModelMixin,
                    mixins.RetrieveModelMixin,
                    mixins.DestroyModelMixin,
                    viewsets.GenericViewSet):
    '''Meals view set.
    '''

    serializer_class = MealModelSerializer
    lookup_field = 'slugname'
    search_fields = ('slugname', 'name')


    # Method call every time this MealViewSet is instanced
    def dispatch(self, request, *args, **kwargs):
        '''Verify that the store exists.
        Add the URL input <store_slugname> to the Meal model field store(FK).
        '''

        store_slugname = kwargs['store_slugname']
        self.store = get_object_or_404(Store, store_slugname=store_slugname)

        return super(MealViewSet, self).dispatch(request, *args, **kwargs)


    def get_queryset(self):
        '''Get Store's available meals'''

        return Meal.objects.filter(
            store=self.store,
            is_available=True
        )

    def create(self, request, *args, **kwargs):
        '''Assign Meal to a Store (received in the URL input <store_slugname>)
        '''
        store = self.store # Got from the dispatcher
        request.data['store'] = store
        serializer = MealModelSerializer(
            store,
            data=request.data
        )
        # import pdb; pdb.set_trace()
        serializer.is_valid(raise_exception=True)
        serializer.save()
        data = serializer.data
        return Response(data, status=status.HTTP_201_CREATED)

и Питание / сериализаторы / foods.py

class MealModelSerializer(serializers.ModelSerializer):
    '''Meal model serializer.'''

    store = StoreModelSerializer()

    class Meta:
        """Meta class."""

        model = Meal
        fields = (
            'store',
            'name',
            'slugname',
            'description',
            'price',
            'picture',
            'rating'
        )
        read_only_fields = (
            'rating',
        )

Отладчик в терминале показывает это: (Store = dominospizza является действительным и предыдущий магазин создан)

Pdb) store
<Store: dominospizza>
(Pdb) store.__dict__
{'_state': <django.db.models.base.ModelState object at 0x7fd539882c10>, 'id': 1, 'name': 'Peperoni large pizza', 'store_slugname': 'dominospizza', 'about': '', 'picture': '', 'pickup_address': 'Urdesa cerca de casa de Agapito', 'is_active': True, 'is_open': True, 'orders_dispatched': 0, 'reputation': 5.0}
(Pdb) request.data
{'name': 'Peperoni large pizza', 'slugname': 'LPizzaPeperoni', 'price': '9.00', 'store': <Store: dominospizza>}

Ответы [ 2 ]

0 голосов
/ 29 апреля 2020

Прежде всего,

Старайтесь как можно больше следовать за REST. Если вы хотите фильтровать бэкэнд-сущности на основе значения поля, укажите их в параметрах запроса. Вы можете автоматизировать фильтрацию, используя django -фильтры. См. this .

Во-вторых,

Вам не нужно переопределять метод создания ViewSet для достижения этой цели. Сериализаторы созданы для этого. Измените код сериализатора, как показано ниже:

class MealModelSerializer(serializers.ModelSerializer):
    '''Meal model serializer.'''

    store = StoreModelSerializer()
    store_id = models.PrimaryKeyRelatedField(
        queryset=models.Store.objects.all(),
        write_only=True,
        source="store",
        required=False
    )
    store_slogname = models.SlugRelatedField(
        queryset=models.Store.objects.all(),
        write_only=True,
        slug_field="store_slugname"
        source="store",
        required=False
    )

    class Meta:
        """Meta class."""
        model = Meal
        fields = (
            'store',
            'name',
            'slugname',
            'description',
            'price',
            'picture',
            'rating'
        )
        read_only_fields = (
            'rating',
        )

Но помните, стандартная практика - передавать идентификаторы вместо имен. Убедитесь, что поле Store store_slugname уникально.

Из внешнего интерфейса вы можете передать store_id или store_slugname в теле POST, PUT, PATCH. Сериализатор автоматически просматривает БД и проверяет данные. Вам не нужно переопределять какой-либо метод.

Редактировать # 1:

Вы можете использовать django -rest-framework-filters Функция AllLookupsFilter для предоставления всех типов фильтрации на уровне интерфейса.

Пример:

/api/{version}/meals/?store__store_slugname=<value>
/api/{version}/meals/?store__store_slugname__contains=<value>
/api/{version}/meals/?store__store_slugname__in=<value1,value2,value3>

Подводя итог, ваш набор будет выглядеть примерно так:

class MealViewSet(
    mixins.ListModelMixin,
    mixins.CreateModelMixin,
    mixins.RetrieveModelMixin,
    mixins.DestroyModelMixin,
    viewsets.GenericViewSet
):
    '''Meals view set.'''

    serializer_class = MealModelSerializer
    lookup_field = 'slugname'
    search_fields = ('slugname', 'name')
    filter_class = MealFilter

Надеюсь, это поможет!

0 голосов
/ 28 апреля 2020

пожалуйста, попробуйте изменить это в MealViewSet.create:

request.data['store'] = store

следующим образом:

request.data['store'] = store.id

Это потому, что я думаю, что по умолчанию ModelSerializer fks решаются как первичное связанное с ключом поле, тогда ожидается, что pk не экземпляр.

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