Search code examples
pythondjangoapidjango-rest-framework

How should I send a Post request to create an object that has a foreign key relationship


hey yall im trying to learn the Django rest framework and im getting stuck trying to create a new product in my db via a POST request

i have a model called Product which has a bunch of fields for all the product details, one of those fields (brand) is a foreign key to another table containing all my brands

when sending a post request to create a new product i want to be able to pass in an id for a brand and it should save

the serializer for the product model has the brand nested in it and i cant figure out how to properly structure the product info in the post request

serializers.py

class ProductSerializer(serializers.ModelSerializer):
    brand = BrandSerializer(required=False, read_only=False)
    vendors = VendorSerializer(many=True, required=False)

    class Meta:
        model = Product
        fields = "__all__"

    def create(self, validated_data):
        product_brand = validated_data.pop("brand")
        print(product_brand)
        product_instance = Product.objects.create(**validated_data)
        Brand.objects.create(product_brand)
        return product_instance

models.py

class Brand(models.Model):
    name = models.CharField(max_length=50)

    def __str__(self):
        return self.name


class Product(models.Model):
    name = models.CharField(max_length=200)
    description = models.CharField(max_length=500)
    sku = models.CharField(max_length=50)
    brand = models.ForeignKey(
        Brand,
        on_delete=models.CASCADE,
        null=True,
        blank=True
    )
    added = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.name + ": " + self.description

example JSON of POST request

{
        "id": 1,
        "brand": {
            "id": 2,
            "name": "Dewalt"
        },
        "name": "Product1",
        "description": "the first product",
        "sku": "111111111",
        "added": "2022-12-28T19:09:30.007480Z",
        "updated": "2022-12-29T15:10:36.432685Z"
}

i dont even know if i should be using nested serializers or if there is a better way to do this. i want that when i make a request to get a product, the brand info should be contained in it and not just the ID

i read somewhere that i have to override the default create() method but im not sure what thats supposed to be doing

i dont want to create a new brand when i do a post, i just want to be able to choose an existing brand when creating a new product

if someone can point me in the right direction that would be incredible


Solution

  • I did it this way but following in case a better explanation/answer is there

    class ProductSerializer(serializers.ModelSerializer):
        brand = BrandSerializer()
    
        class Meta:
            model = Product
            fields = ('id', 'name', 'description', 'sku', 'brand', 'added', 'updated')
    
        def create(self, validated_data):
            brand_data = validated_data.pop('brand')
    
            # get/(create if not exists) brand
            brand, _ = Brand.objects.get_or_create(
                name=brand_data['name']
            )
    
            # print(brand_data) # OrderedDict([('name', 'adgg')])
            product = Product.objects.create(brand=brand, **validated_data)
    
            return product