Search code examples
pythondjangodjango-rest-frameworkdjango-serializer

Django Rest Framework: How to get instance of related foreign key


Note: IF INFORMATION BELOW IS NOT CLEAR TO UNDERSTAND - PLEASE ASK ME, I WILL UPDATE AND POST INFORMATION YOU NEED | It is important for me


In Warehouse(models.Model) I have amount attribute and

in ChosenProduct(models.Model) - quantity

I'm trying to get amount in Warehouse through chosen_products instance in App_formSerializer to add the quantity of chosen_product

But I can not get the chosen_products objects from instance --> below Out:

class WarehouseSerializer(serializers.ModelSerializer):
    category_name = serializers.ReadOnlyField(
        source='category_product.category_name')
    posted_user = serializers.ReadOnlyField(
        source='posted_user.username')
    class Meta:
        model = Warehouse
        fields = ['id', 'category_product', 'category_name', 'condition',
                  'product_name', 'amount', 'barcode', 'f_price', 'created_at', 'updated_at', 'posted_user']

class ChosenProductSerializer(serializers.ModelSerializer):
    product_info = WarehouseSerializer(source='product', read_only=True)
    period_info = Product_periodSerializer(source='period', read_only=True)
    class Meta:
        model = ChosenProduct
        exclude = ('app_form',)

class App_formSerializer(serializers.ModelSerializer):
    chosen_products = ChosenProductSerializer(many=True)

    def update(self, instance, validated_data):
        instance.terminated = validated_data.get('terminated', instance.terminated)
        
        if instance.terminated == True :
              
            print('-----------TRUE--------------------')
            print(instance.chosen_products)
            print('-----------PRINT--------------------')

        instance.save()
        return instance

    class Meta:
        model = App_form
        fields = '__all__'

Out

-----------TRUE--------------------
creditapi.ChosenProduct.None
-----------PRINT--------------------

QUESTION UPDATED


models.py

    class Warehouse(models.Model):
        category_product = models.ForeignKey(
            Category_product, on_delete=models.CASCADE)
        product_name = models.CharField(max_length=200, unique=True)
        condition = models.BooleanField(default=False)
        amount = models.IntegerField()
        barcode = models.BigIntegerField()
        f_price = models.CharField(max_length=255, null=True)
        created_at = models.DateTimeField(auto_now_add=True)
        updated_at = models.DateTimeField(auto_now=True)
        posted_user = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
    
        def __str__(self):
            return self.product_name
    
    class App_form(models.Model):
        phone_regex = RegexValidator(regex=r'^\+?1?\d{9,12}$', message="Phone number must be entered in the format: '998981234567'. Up to 12 digits allowed.")
        terminated = models.BooleanField(default=False)
        name = models.CharField(max_length=150)
        phone_number = models.CharField(validators=[phone_regex], max_length=13)
        
        def __str__(self):
            return self.surname
    
    class ChosenProduct(models.Model):
        product = models.ForeignKey(Warehouse, on_delete=models.CASCADE)
        quantity = models.IntegerField()
        app_form = models.ForeignKey(App_form, on_delete=models.CASCADE, related_name='chosen_products')
    
        def __str__(self):
            return self.product.product_name

Solution

  • If you write instance.chose_products you access the manager, not the QuerySet that contains the items. You can use .all() to obtain the QuerySet with all the objects:

    print(instance.chosen_products.all())

    If you access a ForeignKey in reverse, you have a manager, since zero, one, or more elements can refer to the instance.

    You can for example aggregate over the chose_products, for example if you want to retrieve the number of related chose_products, you can use:

    print(instance.chosen_products.count())

    I would however advise not store (aggregated) data in the App_form, but aggregate data when you need it. Data duplication is an anti-pattern, and it turns out it is hard to keep data in sync.