Django Datetime TypeError: fromisoformat: аргумент должен быть str

У меня такая ошибка при использовании django. Я пытаюсь получить дату, когда произошла одна транзакция, но получаю эту ошибку:

Вот код, который вызывает ошибку:

class Transaction(models.Model):

TRANSACTION_TYPES = (
    ('income', 'Income'),
    ('expense', 'Expense'),
)

RECURRENCE_TYPES = (
    ('daily', 'Daily'),
    ('weekly', 'Weekly'),
    ('biweekly', 'Bi-Weekly'),
    ('monthly', 'Monthly'),
)

user = models.ForeignKey(User, on_delete=models.CASCADE)
transaction_type = models.CharField(max_length=7, choices=TRANSACTION_TYPES)
amount = models.DecimalField(max_digits=10, decimal_places=2)
description = models.CharField(max_length=255)
category = models.CharField(max_length=255, blank=True, null=True)  # Optional category field
recurrence = models.CharField(max_length=10, choices=RECURRENCE_TYPES, blank=True, null=True)  # Recurrence rule
next_due_date = models.DateField(blank=True, null=True)  # The next date when this transaction will be added
transaction_date = models.DateTimeField(default=timezone.now)


def __str__(self):
    # Check if transaction_date is set and valid before formatting
    if self.transaction_date:
        return f"{self.transaction_type} of {self.amount} on {self.transaction_date}"
    else:
        return f"{self.transaction_type} of {self.amount}"
    
def save(self, *args, **kwargs):
    print(f"Saving transaction_date: {self.transaction_date}")
    if self.recurrence and not self.next_due_date:
        # Set the next_due_date based on the recurrence type
        if self.recurrence == 'daily':
            self.next_due_date = self.transaction_date.date() + timedelta(days=1)
        elif self.recurrence == 'weekly':
            self.next_due_date = self.transaction_date.date() + timedelta(weeks=1)
        elif self.recurrence == 'biweekly':
            self.next_due_date = self.transaction_date.date() + timedelta(weeks=2)
        elif self.recurrence == 'monthly':
            self.next_due_date = self.transaction_date.date().replace(month=self.transaction_date.month+1)  # Simplified monthly logic
    super().save(*args, **kwargs)

Вот также мои уже сделанные сделки:

[{"id":1,"user":1,"transaction_type":"expense","amount":"33.00","description":"Cosmote","category":null,"recurrence":null,"next_due_date":null,"transaction_date":"2025-03-26T14:03:02.430961Z"},{"id":2,"user":1,"transaction_type":"income","amount":"1000.00","description":".","category":"Salary","recurrence":"monthly","next_due_date":"2025-03-03","transaction_date":"2025-03-26T14:03:02.430961Z"},{"id":3,"user":1,"transaction_type":"income","amount":"1000.00","description":".","category":"Salary","recurrence":"monthly","next_due_date":"2025-03-03","transaction_date":"2025-03-26T14:03:02.430961Z"},{"id":4,"user":1,"transaction_type":"income","amount":"450.00","description":"Rent","category":"Rent","recurrence":"biweekly","next_due_date":"2025-03-01","transaction_date":"2025-03-26T14:03:02.430961Z"}]

Последняя вот миграция 0004 выглядит так:

    # Generated by Django 5.1.6 on 2025-02-20 12:43

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('finance', '0003_rename_amount_investment_purchase_price_and_more'),
    ]

    operations = [
        migrations.AddField(
            model_name='investment',
            name='pnl',
            field=models.DateTimeField(default=0.0),
        ),
        migrations.AddField(
            model_name='investment',
            name='total_worth',
            field=models.DateTimeField(default=0.0),
        ),
    ]

Последняя миграция, которую я сделал:

    # Generated by Django 5.1.6 on 2025-03-26 14:21

import django.utils.timezone
from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('finance', '0028_transaction_transaction_date'),
    ]

    operations = [
        migrations.AlterField(
            model_name='transaction',
            name='transaction_date',
            field=models.DateTimeField(default=django.utils.timezone.now),
        ),
    ]

Я не могу понять, почему это происходит, я пробовал использовать непосредственно timezone.now():

transaction_date = timezone.now()

instead of transaction_date = models.DateTimeField(default=timezone.now) but it got the same error, also tries using if else statement to check in the str function but nothing last i tried using this format in str

return f"{self.transaction_type} of {self.amount} on {self.transaction_date}"
return f"{self.transaction_type} of {self.amount} on {self.transaction_date.strftime('%B %d, %Y')}"

any idea why may this is happening?

update: here is also the code of class investment where i tried to calculate the investment a user has made live using api i have created a total_worth and pnl field that in reality i did not need so i commented it out but at first i made the migration and after i commented i also migrate again.

class Investment(models.Model):
    name = models.CharField(max_length=100)  # e.g., Bitcoin, Tesla
    symbol = models.CharField(max_length=10, unique=True)  # e.g., BTC, TSLA
    quantity = models.DecimalField(max_digits=10, decimal_places=4 , default=0.0)  # Number of shares/coins
    purchase_price= models.DecimalField(max_digits=10, decimal_places=2)  # Price at purchase
    current_price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)  # Real-time price
    investment_type = models.CharField(max_length=20, choices=[('Stock', 'Stock'), ('Crypto', 'Crypto')])
    
    last_updated = models.DateTimeField(default=timezone.now,  null=True , blank=True)
    
    #total_worth = models.DecimalField(max_digits=15 , decimal_places=4 , default=0.0)
    #pnl = models.DecimalField(max_digits=15 ,decimal_places=4 , default=0.0)
    
    def __str__(self):
        return f"{self.name} ({self.symbol}) - {self.quantity} units"


    def total_worth(self):
        """Total worth of this investment"""
        return self.quantity * self.current_price if self.current_price else Decimal('0.0')

    def pnl(self):
        """Profit and Loss calculation"""
        return (self.current_price - self.purchase_price) * self.quantity if self.current_price else Decimal('0.0')
    
    # Automatically calculate total worth and PnL when saving
    """def update_total_worth(self):
        self.total_worth = self.amount_invested * self.current_price
        self.save()
    """
    def save(self, *args, **kwargs):
        #self.total_worth = self.current_price * self.quantity if self.current_price else 0.0
        #self.pnl = self.total_worth - (self.purchase_price * self.quantity)
        super().save(*args, **kwargs)  # Call the original save method

you are setting a DateTimeField with a default value of 0.0, which is a float. Django expects a valid datetime or callable like timezone.now

secondly, you initially added pnl and total_worth fields as DateTimeField but later you commented them out django still tracks these fields in migrations and they may be causing inconsistencies

fix the migration in /0004_investment_pnl_investment_total_worth.py file.

field=models.DecimalField(max_digits=15, decimal_places=4, default=0.0),

remove these lines if you dont need them

operations = [
    # remove these lines if you don't need them


    # migrations.AddField(
    #     model_name='investment',
    #     name='pnl',
    #     field=models.DecimalField(max_digits=15, decimal_places=4, default=0.0),
    # ),
    # migrations.AddField(
    #     model_name='investment',
    #     name='total_worth',
    #     field=models.DecimalField(max_digits=15, decimal_places=4, default=0.0),
    # ),
]

then run

docker-compose exec web python manage.py migrate finance 0003
docker-compose exec web python manage.py makemigrations
docker-compose exec web python manage.py migrate

additionally

You don't need django automatically assigns the default timezone.now

transaction_date = timezone.now()

change it to

transaction_date = models.DateTimeField(default=timezone.now)
Вернуться на верх