Столбец Django throws не может быть нулевой ошибкой при отправке POST в REST Framework

Django REST Framework сообщает об ошибке, что значение равно null, хотя я отправляю значение при отправке данных.

Django сообщает об ошибке:

django.db.utils.IntegrityError: (1048, "Column 'owner_id' cannot be null")
[04/Apr/2016 18:40:58] "POST /api/items/ HTTP/1.1" 500 226814

Код Angular 2, который отправляет POST в Django REST Framework API:

    let body = JSON.stringify({ url: 'fred', item_type: 'P', owner_id: 2 });

    let headers = new Headers();
    headers.append('Content-Type', 'application/json');

    this.http.post('http://127.0.0.1:8000/api/items/',
        body, {
        headers: headers
      })
      .subscribe(
        data => {
          alert(JSON.stringify(data));
        },
        err => alert('POST ERROR: '+err.json().message),
        () => alert('POST Complete')
      );

Мое представление API Django выглядит так:

class ItemViewSet(viewsets.ModelViewSet):
    queryset = Item.objects.all().order_by('-date_added')
    serializer_class = ItemSerializer

    """
        Use the API call query params to determing what to return

        API params can be:

        ?user=<users_id>&num=<num_of_items_to_return>&from=<user_id_of_items_to_show>
    """

    def get_queryset(self):
        this_user = self.request.query_params.get('user', None)
        restrict_to_items_from_user_id = self.request.query_params.get('from', None)
        quantity = self.request.query_params.get('num', 20)

        if restrict_to_items_from_user_id is not None:
            queryset = Item.objects.filter(owner=restrict_to_items_from_user_id, active=True).order_by('-date_added')[0:int(quantity)]
        elif this_user is not None:
            queryset = Item.objects.filter(active=True, credits_left__gt=0).exclude(pk__in=Seen.objects.filter(user_id=this_user).values_list('item_id', flat=True))[0:int(quantity)]
        else:
            queryset = Item.objects.filter(active=True, credits_left__gt=0)[0:int(quantity)]

        print("User id param is %s  and quantity is %s" % (user_id,quantity))

        return queryset

Ассоциированная модель:

class Item(models.Model):

    ITEM_TYPES = (
        ('V', 'Vine'),
        ('Y', 'YouTube'),
        ('P', 'Photo'),         # Photo is stored by us on a CDN somewhere
        ('F', 'Flickr'),
        ('I', 'Instagram'),
        ('D', 'DeviantArt'),
        ('5', '500px'),
    )
    owner           = models.ForeignKey(User, on_delete=models.CASCADE)     # Id of user who owns the item
    title           = models.CharField(max_length=60, default='')           # URL of where item resides (e.g. Vine or YouTube url)
    url             = models.CharField(max_length=250, default='')          # URL of where item resides (e.g. Vine or YouTube url)
    item_type       = models.CharField(max_length=1, choices=ITEM_TYPES)    # Type of item (e.g. Vine|YoutTube|Instagram|etc.)
    keywords        = models.ManyToManyField(Keyword, related_name='keywords')
                                                                            # E.g. Art, Travel, Food, etc.
    credits_applied = models.IntegerField(default=10, help_text='Total number of credits applied to this item including any given by VeeU admin')
                                                                            # Records the total number of credits applied to the Item
    credits_left    = models.IntegerField(default=10, help_text='The number of credits still remaining to show the item')
                                                                            # Number of credits left (goes down each time item is viewed
    credits_gifted  = models.IntegerField(default=0, help_text='The number of credits this item has been gifted by other users')
                                                                            # Number of credits users have gifted to this item
    date_added      = models.DateTimeField(auto_now_add=True)               # When item was added
    liked           = models.IntegerField(default=0)                        # Number of times this item has been liked
    disliked        = models.IntegerField(default=0)                        # Number of times this item has been disliked
    active          = models.BooleanField(default=True, help_text='If you mark this item inactive please say why in the comment field. E.g. "Inapproriate content"')
                                                                            # True if item is available for showing
    comment         = models.CharField(max_length=100, blank=True)          # Comment to be applied if item is inactive to say why

    # Add defs here for model related functions

    # This to allow url to be a clickable link
    def item_url(self):
        return u'<a href="%s">%s</a>' % (self.url, self.url)
    item_url.allow_tags = True

    def __str__(self):
        return '%s: Title: %s, URL: %s' % (self.owner, self.title, self.url)

Я не вижу, что не так с моим вызовом POST или кодом Django.

EDIT: добавлен код сериализатора Вот связанный сериализатор

class ItemSerializer(serializers.HyperlinkedModelSerializer):
    username = serializers.SerializerMethodField()

    def get_username(self, obj):
        value = str(obj.owner)
        return value

    def get_keywords(self, obj):
        value = str(obj.keywords)
        return value

    class Meta:
        model = Item
        fields = ('url', 'item_type', 'title', 'credits_applied', 'credits_left', 'credits_gifted', 'username', 'liked', 'disliked')


person Bill Noble    schedule 04.04.2016    source источник


Ответы (4)



Вам нужно передать URI ресурса для поля, которое является внешним ключом, здесь владельцем является FK, поэтому

ownerIns = User.objects.get(id=2)
let body = JSON.stringify({ url: 'fred', item_type: 'P', owner: ownerIns, owner_id: ownerIns.id });
person Surajano    schedule 20.03.2017

Я столкнулся с аналогичной проблемой, используя Angular и Flask. Это может быть связано с тем, что ваши заголовки CORS неправильно настроены для вашего приложения Django, из-за чего вашему приложению Angular не разрешено отправлять сообщения в серверную часть. В Flask я исправил это с помощью этого кода:

@app.after_request
def after_request(response):
    response.headers.add('Access-Control-Allow-Origin', '*')
    response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
    response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
    return response

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

person Jaron Thatcher    schedule 04.04.2016
comment
Спасибо Джарон. В настоящее время я просто работаю с тем же источником (для тестирования), но мои настройки CORS соответствуют вашему примеру. - person Bill Noble; 04.04.2016
comment
Черт побери, по крайней мере, тогда ты можешь вычеркнуть это из списка. Я не уверен, что может пойти не так. Я посмотрю еще раз и дам вам знать, если я что-нибудь увижу. - person Jaron Thatcher; 04.04.2016
comment
Может быть, это как-то связано с тем, что владелец является внешним ключом? - person Bill Noble; 04.04.2016

Ваш код ItemSerializer правильный? Остальное мне кажется нормально.

Я думаю, у вас должен быть «owner_id» в полях вашего сериализатора.

Взгляните на этот ответ, добавьте соответствующие поля таким образом.

https://stackoverflow.com/a/20636415/5762482

person utkarshmail2052    schedule 04.04.2016
comment
Я добавил связанный сериализатор в свою публикацию. - person Bill Noble; 04.04.2016
comment
Я думаю, у вас должен быть «owner_id» в полях вашего сериализатора. - person utkarshmail2052; 04.04.2016
comment
Если я добавлю «owner_id» в сериализатор, я получу следующую ошибку во время выполнения. Имя поля owner_id недопустимо для модели Item. В моей модели поле называется owner, но в базе данных это owner_id. - person Bill Noble; 04.04.2016