Django Model self reference OneToOne, Can't set link while bulk_create

Контекст

Пожалуйста, не обижайтесь на меня, так как я новичок в Django. У меня есть модель Account, на которую я хочу ссылаться сам, в отношениях один-к-одному. Account также имеет отношения один ко многим с Activities.

Гол

  1. При сохранении аккаунта сохранять linked_account_id как self fk
  2. Возможность получения всех действий, связанных с обоими счетами или только с одним

Проблема стеки ошибок:

  1. не может сохранить linked_account_id (string_value), ожидается тип Account

Также возможно, что связанный счет еще не был сохранен, поэтому при попытке сохранить объект с помощью linked_account_id

не возвращается сущность.

Вот данные, которые я пытаюсь сохранить с помощью bulk_create

for data in filteredList:
        account_data = {
            'accountNumber': data['id'],
            'status': data['status'],
            'last_synced': parse_datetime(data['last_synced_at']),
            'created_at': parse_datetime(data['created_at']),
            'updated_at': parse_datetime(data['updated_at']),
            'current_balance': data['current_balance']['amount'],
            'net_deposits': data['net_deposits']['amount'],
            'linked_account_id': data['linked_account_id'], (FK)
            'currency': data['base_currency'],
            'type': data['account_type'],
        }

вот мой код модели

class Account (models.Model):
    accountNumber = models.CharField(default=0, max_length=20,primary_key=True)
    type = models.CharField(default='', max_length=20)
    current_balance = models.DecimalField(default=0, max_digits=20, decimal_places=0)
    net_deposits = models.DecimalField(default=0, max_digits=20, decimal_places=0)
    currency = models.CharField(default='', max_length=10)
    last_synced = models.DateTimeField(default=timezone.now)
    is_primary = models.BooleanField(default=False)
    linked_account_id = models.OneToOneField('self', on_delete=models.SET_NULL, null=True, blank=True)
    created_at = models.DateTimeField( default=timezone.now)
    updated_at = models.DateTimeField(default=timezone.now)
    status = models.CharField(default='', max_length=10)
    def __str__(self):
        return self.type  # Or whatever you want to represent your Account instance with

    def set_linked_account(self, other_account_number):
        try:
            related_account = Account.objects.get(accountNumber=other_account_number)
            self.linked_account_id = related_account
            self.save()
        except Account.DoesNotExist:
            print("The related account does not exist.")

    def get_all_linked_activities(self):
        if self.linked_account_id:
            return Activity.objects.filter(models.Q(account=self) | models.Q(account=self.linked_account_id))
        else:
            return Activity.objects.filter(account=self)

Это основная причина, по которой вам лучше не определять ForeignKey и OneToOneField, которые заканчиваются суффиксом _id, поскольку они работают не с id, а с Account напрямую.

С данной моделью вы можете использовать:

for data in filteredList:
    account_data = {
        'accountNumber': data['id'],
        'status': data['status'],
        'last_synced': parse_datetime(data['last_synced_at']),
        'created_at': parse_datetime(data['created_at']),
        'updated_at': parse_datetime(data['updated_at']),
        'current_balance': data['current_balance']['amount'],
        'net_deposits': data['net_deposits']['amount'],
        'linked_account_id_id': data['linked_account_id'],  # (FK)
        'currency': data['base_currency'],
        'type': data['account_type'],
    }

но сделайте себе одолжение и переименуйте поле в linked_acount:

class Account(models.Model):
    # …
    linked_account = models.OneToOneField(
        'self', on_delete=models.SET_NULL, null=True, blank=True
    )
    # …

и работать с:

for data in filteredList:
    account_data = {
        'accountNumber': data['id'],
        'status': data['status'],
        'last_synced': parse_datetime(data['last_synced_at']),
        'created_at': parse_datetime(data['created_at']),
        'updated_at': parse_datetime(data['updated_at']),
        'current_balance': data['current_balance']['amount'],
        'net_deposits': data['net_deposits']['amount'],
        'linked_account_id': data['linked_account_id'],  # (FK)
        'currency': data['base_currency'],
        'type': data['account_type'],
    }

Note: Django's DateTimeField [Django-doc] has a auto_now_add=… parameter [Django-doc] to work with timestamps. This will automatically assign the current datetime when creating the object, and mark it as non-editable (editable=False), such that it does not appear in ModelForms by default.


Примечание: обычно названия полей в модели Django записываются в snake_case, а не PascalCase, поэтому должно быть: account_number вместо accountNumber.

Вернуться на верх