简体   繁体   中英

Django REST Framework serializer - access existing foreign key

I am using Django Rest Framework in my app, and I need to create new model instances which contain foreign keys. These refer to existing objects in another table, so I don't want new instances of these foreign objects to be created. Also I cannot access these objects via their primary keys, as that information is not submitted (I need to filter on certain fields which are included in the POST request).

How do I do this? This question seems to address the same issue, though it's not clear to me that the accepted answer actually solves the problem. Suppose I have two models, Category and Item , with a ForeignKey field in the latter specifying the category:

class Category(models.Model):
    name = models.TextField()
    format = models.TextField()
    page = models.IntegerField(default=1)
    order = models.IntegerField(default=1)

class Item(models.Model):
    username = models.TextField()
    title = models.TextField()
    category = models.ForeignKey('Category', null=True)
    data = JSONField(null=True, blank=True)

The body of the POST request consists of a JSON payload, with the category defined as an object specifying the format, page and order fields:

POST /api/items
{
  "username" : "test",
  "title" : "foo",
  "category" : {
    "format" : "A",
    "page" : 2,
    "order" : 1
  },
  "data" : [1,2,3,4,5]
}

Then I suppose I might define my Item serializer as follows, overriding create so that it retrieves the right Category instance by filtering on the appropriate fields, and setting it into the returned Item instance:

class ItemSerializer(serializers.ModelSerializer):
    category = CategorySerializer()
    data = serializers.ListField()

    class Meta:
        model = Item
        fields = ('username', 'title', 'category', 'data')

    def create(self, validated_data):
        category_dict = validated_data.pop('category')
        item = Item.objects.create(**validated_data)
        format = category_dict.format
        page = category_dict.page
        order = category_dict.order
        item.category = Category.objects.get(format=format, page=page, order=order)
        return item

Is this the right way to do it?

It will be like

try:
    category = Category.objects.get(format=format, page=page, order=order)
except Category.DoesNotExist:
    # either make it None or create new category, depends on your requirement
    category = None
    # or create new category
except Category.MultipleObjectsReturned:
    category = category.first() # it depends on your requirement
item.category = category

At least there is one error,you should use get to get only one category as you item's category instead of use filter to get queryset .

class ItemSerializer(serializers.ModelSerializer):
    category = CategorySerializer()
    data = serializers.ListField()

    class Meta:
        model = Item
        fields = ('username', 'title', 'category', 'data')

    def create(self, validated_data):
        category_dict = validated_data.pop('category')
        item = Item.objects.create(**validated_data)
        format = category_dict.format
        page = category_dict.page
        order = category_dict.order
        try:
            item.category = Category.objects.get(format=format, page=page, order=order)
        except  Category.DoesNotExist:
            pass
        except  Category.MultipleObjectsReturned:
            pass
        return item

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM