Как переопределить метод сохранения django для динамического обновления некоторых полей?

Здесь у меня есть две модели. В этих моделях я хочу сделать значение amount_to_pay динамическим в модели Ledger. Например, у меня есть две разные формы для этих двух моделей, и при сохранении формы расходов, если пользователь выбирает payment_option, который исходит из модели ledger и дает некоторое значение для поля amount_to_pay, тогда, если только ledger.id и expense.payment_option_id совпадают, значение amount_to_pay в модели леджера следует заменить этим значением. как я могу это сделать?

модели.py

     class Expense(models.Model):
        pay_from = models.CharField(max_length=200)
        payment_option = models.ForeignKey('Ledger', on_delete=models.CASCADE)
        amount_to_pay = models.IntegerField(default=0)
        expense_date = models.DateField(default=datetime.date.today)
        expense_type = models.ForeignKey(ExpenseType, on_delete=models.CASCADE)
        note = models.TextField()
        created = models.DateTimeField(auto_now_add=True)
        updated = models.DateTimeField(auto_now=True)
        slug = AutoSlugField(unique_with='id', populate_from='expense_type')

        def get_amount_to_pay(self):
            return self.amount_to_pay


    class Ledger(models.Model):
        name = models.CharField(max_length=200)
        account_number = models.CharField(max_length=250, unique=True)
        account_type = models.CharField(max_length=200)
        opening_balance = models.IntegerField(default=0)
        amount_to_pay = models.IntegerField(default=0, blank=True, null=True)
        current_balance = models.IntegerField(default=0, blank=True, null=True)
        created = models.DateTimeField(auto_now_add=True)
        updated = models.DateTimeField(auto_now=True)
        slug = AutoSlugField(unique_with='id', populate_from='name')

        def save(self, *args, **kwargs):
             self.amount_to_pay = Expense.get_amount_to_pay(self)

# here how can i save the amount_to_pay from expense form if the ledger.id and expense.payment_option.id matches??
#i got stuck here.           
 self.current_balance = self.opening_balance - self.amount_to_pay

            super(Ledger, self).save(*args, **kwargs)
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
9
0
6 762
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Лучше всего, если вы переопределите вызов метода сохранения в любом случае, если у вас есть foreginkey.

    def save(self, *args, **kwargs):
        #self.date_created = timezone.now()
        # YOUR LOGIC HERE
        super(YOUR_OVERRIDING_MODEL , self).save(*args, **kwargs

необходимо указать сумму_к_оплате и текущий_баланс

arjun 28.05.2019 11:42
amount_to_pay = Expense.objects.get(id=form.cleaned_data['amount_to_pay_id']‌​) распечатать это значение
Clifton Avil D'Souza 28.05.2019 11:46
amount_to_pay_id к amount_to_pay
Clifton Avil D'Souza 28.05.2019 11:52

проверьте, есть ли у Ledger дочерний элемент, а затем обновите его:

class Expense(models.Model):    
        def save(self, *args, **kwargs):
                self.payment_option.amount_to_pay = self.payment_option.amount_to_pay + self.amount_to_pay
                self.payment_option.save()
            super(Expense, self).save(*args, **kwargs)

self.ledger_payment_option.amount_to_pay = 1000 что он делает?? я хочу сохранить его динамическим. Если только пользователь дает значение из формы модели расходов, а идентификатор как payment_option, так и бухгалтерской книги совпадает, тогда значение amount_to_pay в таблице бухгалтерской книги должно быть заменено данными, введенными пользователем

arjun 30.05.2019 12:48

если вы хотите обновить Ledger.amount_to_pay из модели Expense, у вас есть ответ.

katoozi 30.05.2019 13:04
Ответ принят как подходящий

Решение первое:

Я думаю, что вместо изменения модели Ledger вам следует изменить модель Expense, например:

class Expense(models.Model):
    ...
    def save(self, *args, **kwargs):
       self.payment_option.amount_to_pay = self.payment_option.amount_to_pay + self.amount_to_pay
       self.payment_option.save()
       super(Expense, self).save(*args, **kwargs)

Решение второе:

Но если честно, Решение первое мне не кажется хорошим. Причина в том, что вы сохраняете одни и те же данные в двух местах (как в расходах, так и в книге). Вместо этого это должно быть один раз, тогда значение amount_to_pay в Ledger должно рассчитываться динамически. Так:

from django.db.models import Sum

class Ledger(...):

     @property
     def amount_to_pay(self):
         # I am using a property method to show the amount_to_pay value.
         # FYI: in this way, you need to remove amount_to_pay field from Ledger model
         return self.opening_balance - self.expense_set.all().aggregate(a_sum=Sum('amount_to_pay')).get('a_sum', 0)

Таким образом, для каждой книги значение amount_to_pay будет динамически рассчитываться во время выполнения. Например:

 for l in Ledger.objects.all():
     l.amount_to_pay

Решение третье:

Если вы опасаетесь попадания в БД с каждым l.amount_to_pay (поскольку он динамически вычисляет сумму_к_платежу из БД) из предыдущего решения, вы всегда можете annotate значение. Так:

Для этого решения вам нужно изменить модель Expense и добавить related_name:

class Expense(models.Model):
    pay_from = models.CharField(max_length=200)
    payment_option = models.ForeignKey('Ledger', on_delete=models.CASCADE, related_name='expenses')

Затем используйте этот related_name в запросе следующим образом (к вашему сведению: вы не можете сохранить метод def amount_to_pay(...) в модели Леджер для следующего примера использования):

from django.db.models import Sum, F, ExpressionWrapper, IntegerField

ledgers = Ledger.objects.all().annotate(expense_sum=Sum('expenses__amount_to_pay')).annotate(amount_to_pay=ExpressionWrapper(F('opening_balance') - F('expense_sum'), output_field=IntegerField()))

# usage one
for l in ledgers:
   l.amount_to_pay

# usage two
ledgers.values('amount_to_pay')

Переопределить метод сохранения и динамически обновить некоторые поля в django

В моем случае я хотел динамически обновлять столбец «Готово» в модели ответов, когда я комментирую ответ, он должен возвращать true, а не False. Итак, в моем примере я проверяю, является ли тот столбец, который является логическим, False, и если он False, я меняю его статус на True, используя объект ответа из комментария, а затем сохраняю объект ответа, см. подробнее об полях обновления и вставки https://docs.djangoproject.com/en/3.2/ref/models/instances/

class Answer(models.Model):
    user = models.ForeignKey("User", on_delete=models.CASCADE, blank=True, null=True)
    username = models.CharField(max_length=250)
    codeAnswer = models.CharField(max_length=250)
    girAnswer = models.CharField(max_length=250)
    correct = models.BooleanField(default=False)
    firebaseToken = models.CharField(max_length=250)
    done = models.BooleanField(default=False)
    created_at = models.DateTimeField()
    updated_at = models.DateTimeField(auto_now=True)

    def __unicode__(self):
        return "{0}: {1}".format(self.username, self.value)

    def __str__(self):
        return "%s" % (self.codeAnswer)

# So here i override the save method in the Comment model to do what i want as below.

class Comment(models.Model):
    answer = models.ForeignKey("Answer", on_delete=models.CASCADE, blank=False , related_name = "comments")
    writerName = models.CharField(max_length=250)
    content = models.CharField(max_length=250)
    deleted = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return "%s" % (self.writerName)

    def save(self, *args, **kwargs):
        if self.answer.done is False:
            self.answer.done = True
            self.answer.save()
        super(Comment, self).save(*args, **kwargs)

Надеюсь, это ответ на вопрос выше, спасибо

Если у вас есть новый вопрос, задайте его, нажав кнопку Задать вопрос. Включите ссылку на этот вопрос, если это помогает обеспечить контекст. - Из обзора

matt5784 14.09.2021 00:31

Как сейчас написано, ваш ответ неясен. Пожалуйста, редактировать, чтобы добавить дополнительную информацию, которая поможет другим понять, как это относится к заданному вопросу. Дополнительную информацию о том, как писать хорошие ответы, можно найти в справочном центре.

Community 14.09.2021 00:47

Другие вопросы по теме