Ekaterina Premudraya
Ekaterina Premudraya

Reputation: 139

Signal post_save in Django and models

I have function with signal:

@receiver(post_save, sender=Task)
def my_handler():
    executor = User.objects.filter(user_type='Executer')
    executor.balance += Task.money
    executor.save()

My function should add money to executor after task added. But it gives mistake like:

Internal Server Error: /api/v1/tasks/
Traceback (most recent call last):
  ...
  File "/home/k/pro/freelance-django/free/lib/python3.5/site-packages/django/db/models/fields/__init__.py", line 1853, in get_prep_value
    return int(value)
ValueError: invalid literal for int() with base 10: 'Executer'
[20/Sep/2017 14:00:30] "POST /api/v1/tasks/ HTTP/1.1" 500 188088

User class looks like:

   from __future__ import unicode_literals

from django.db import models
from django.contrib.auth.models import AbstractUser


class User(AbstractUser):
    CUSTOMER = 1
    EXECUTER = 2

    USER_TYPES = (
        (CUSTOMER, 'Customer'),
        (EXECUTER, 'Executer'),
    )

    user_type = models.IntegerField(choices=USER_TYPES, default=EXECUTER, verbose_name='Тип пользователя')
    balance = models.DecimalField(decimal_places=2, max_digits=7, default=0, verbose_name='Баланс')


    def __str__(self):
        return self.username

Task class from task.models is:

class Task(models.Model):
    title = models.CharField(max_length=255, verbose_name='Заголовок')
    description = models.CharField(max_length=255, verbose_name='Описание')
    money = models.DecimalField(max_digits=7, decimal_places=2, default=0, verbose_name='Цена')
    assignee = models.ForeignKey('users.User', related_name='assignee', null=True, verbose_name='Исполнитель')
    created_by = models.ForeignKey('users.User', related_name='created_by', verbose_name='Кем был создан')

How should I make it work?

Upvotes: 1

Views: 937

Answers (1)

Thaian
Thaian

Reputation: 1245

U don't have one object but objects so you need literal on them or do update(). The best option is use F expression which has a good performance because its executed on DB:

from django.db.models import F    

@receiver(post_save, sender=Task)
def my_handler(sender, instance, **kwargs):
    User.objects.filter(user_type=User.EXECUTER).update(balance=F('balance') + instance.money)

This update all records where user_type is Executer and update them balance in one query.

Django docs update

F expressions

Your user_type field is IntegerField and in your choices you have string value so u need change it to something like this:

class User(AbstractUser):
    CUSTOMER = 1
    EXECUTER = 2

    USER_TYPES = (
        (CUSTOMER, 'Customer'),
        (EXECUTER, 'Executer'),
    )

    user_type = models.IntegerField(choices=USER_TYPES, default=EXECUTER, verbose_name='Тип пользователя')
    balance = models.DecimalField(decimal_places=2, max_digits=7, default=0, verbose_name='Баланс')

Upvotes: 3

Related Questions