Django Model self reference OneToOne, Can't set link while bulk_create
Контекст
Пожалуйста, не обижайтесь на меня, так как я новичок в Django. У меня есть модель Account
, на которую я хочу ссылаться сам, в отношениях один-к-одному. Account
также имеет отношения один ко многим с Activities
.
Гол
- При сохранении аккаунта сохранять linked_account_id как self fk
- Возможность получения всех действий, связанных с обоими счетами или только с одним
Проблема стеки ошибок:
- не может сохранить 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 aauto_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 inModelForm
s by default.
Примечание: обычно названия полей в модели Django записываются в snake_case, а не PascalCase, поэтому должно быть:
account_number
вместо.accountNumber