ошибка получения объекта ‘tuple’ без атрибута ‘value’

#django-rest-framework

#django-rest-framework

Вопрос:

 class budgetSerializer(serializers.ModelSerializer):
       
    budget_used        = serializers.SerializerMethodField()
    budget_remain      = serializers.SerializerMethodField()
    total_budget       = serializers.IntegerField(default=250000)


    def get_budget_used (self,obj):
            budget_used=budget.objects.filter(user=obj.user).aggregate(Sum('budget_stord__bytes'))
            data = []
            for val in budget_used.items():
                if val.value > total_budget :
                    raise serializers.ValidationError('you exceed the total budget limit')
           
            return f'budget : {(budget_used/1000)} '

    def get_total_budget(self,obj):
            total_budget = 250000
            return f'total_budget: {(total_budget/1000)} '   
    def get_remain(self,obj):
            remain = (total_budget) - (budget_used)   
            return remain

    class Meta:
        model  = budget_u
        fields = ("budget_used","total_budget","budget_remain")
  
 MODEl 

class budget_u(CreatedModel, UUIDPKModel):
    budget_stord = models.ForeignKey('bud.Store', on_delete=models.SET_NULL, null=True, blank=True)
    user = models.ForeignKey('user.user', on_delete=models.SET_NULL, null=False, blank=False)
  

Мне нужен вывод, подобный

 {
    " budget_used": "100",
    "remain": "150G",
    "total_budget": "250"
} 
  

получение
Ошибка атрибута: объект ‘tuple’ не имеет атрибута ‘value’

Комментарии:

1. budget_used.items() возвращает повторяющийся кортеж из двух

Ответ №1:

Вы не обращаетесь к значению с помощью .value , .items() возвращает итерацию из 2-х кортежей, поэтому вы можете использовать итеративную распаковку в for цикле. Но здесь вы можете просто использовать подписку для доступа к значению:

 def get_budget_used(self, obj):
    budget_used = budget_u.objects.filter(
        user=obj.user
    ).aggregate(total=Sum('budget_stord__bytes'))['total'] or 0
    if budget_used > 250000:
        return 'you exceed the total budget limit'
    return f'budget : {(budget_used/1000)}'  

При этом довольно странно каждый раз возвращать строки. Часто сериализаторы возвращают числовые данные, поскольку их проще обрабатывать, например, с помощью скрипта JavaScript на стороне браузера или интеграции клиента.

Комментарии:

1. Спасибо, Виллем Ван Онсем, когда я использовал ваш код, я получаю эту ошибку TypeError: ‘>’ не поддерживается между экземплярами ‘NoneType’ и ‘int’

2. Ошибка типа: ‘>’ не поддерживается между экземплярами ‘NoneType’ и ‘int’

3. @user1007061: я полагаю, это потому, что нет связанного budget_u объекта? В этом случае вы можете использовать or 0 .

4. привет, в приведенном выше коде, когда я запускаю код, который я получаю для своего remain. def get_remain(self, obj): remain = (self.context.get(total_budget)) — (self.context.get(budget_used)) возвращает ошибку remain remain = (self.context.get(total_budget)) — (self.context.get(budget_used)) Ошибка типа: неподдерживаемые типы операндов для -: ‘NoneType’ и ‘NoneType’

5.Но self.context не имеет ни total_budget , ни budget_used . context содержит только объекты, которые вы сами передаете сериализатору. Даже если бы у него было это, это не сработало бы, поскольку ваши методы возвращают stringы, а не числа, следовательно, вычитание невозможно. Это одна из (многих) причин, по которой использование строк в качестве ответа не является хорошей идеей.