0

I'm using Python 3.9 and Django 3.2. I have this model with a ManyToMany field ...

class Account(models.Model):    
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    active = models.BooleanField(default=True)
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
    )
    vendor = models.ForeignKey(Vendor, on_delete=models.DO_NOTHING)
    crypto_currencies = models.ManyToManyField(CryptoCurrency)

    def __init__(self, user, vendor, crypto_currencies_arr, max_transactions=DEFAULT_MAX_BUY_TRANSACTIONS):
        self.crypto_currencies.set( set() )
        for cc in crypto_currencies_arr:
            self.crypto_currencies.add(cc)
        super().__init__(
            user=user,
            vendor=vendor,
            crypto_currencies=self.crypto_currencies
        )

I'm having trouble figuring out how to initialize my many-to-many field with an array. The above results in this error

>>> account = Account(user=u, vendor=v, crypto_currencies_arr=[c])
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    account = Account(user=u, vendor=v, crypto_currencies_arr=[c])
  File "/Users/davea/Documents/workspace/cbapp/cbapp/models/account.py", line 47, in __init__
    self.crypto_currencies.set( set() )
  File "/Users/davea/Documents/workspace/cbapp/venv/lib/python3.9/site-packages/django/db/models/fields/related_descriptors.py
", line 536, in __get__
    return self.related_manager_cls(instance)
  File "/Users/davea/Documents/workspace/cbapp/venv/lib/python3.9/site-packages/django/db/models/fields/related_descriptors.py
", line 846, in __init__
    self.core_filters[core_filter_key] = getattr(instance, rh_field.attname)
  File "/Users/davea/Documents/workspace/cbapp/venv/lib/python3.9/site-packages/django/db/models/query_utils.py", line 142, in
 __get__
    val = self._check_parent_chain(instance)
  File "/Users/davea/Documents/workspace/cbapp/venv/lib/python3.9/site-packages/django/db/models/query_utils.py", line 158, in
 _check_parent_chain
    return getattr(instance, link_field.attname)
AttributeError: 'NoneType' object has no attribute 'attname'

How do I properly set my many-to-many field with the values from my array?

Edit: Per the advice given, I tried creating a separate method for creating the account and then the set, but this

def create_account(self, user, vendor, crypto_currencies_arr=[], max_transactions=DEFAULT_MAX_BUY_TRANSACTIONS):
    
    a = Account(
        user=user,
        vendor=vendor,
        max_transactions=max_transactions
    )
    a.save()
    cc_set = set()
    for cc in crypto_currencies_arr:
        cc_set(cc)
    a.crypto_currencies = cc_set
    a.save()

results in the error

cc_set(cc)
TypeError: 'set' object is not callable
Dave
  • 15,639
  • 133
  • 442
  • 830
  • You can't. Django first needs a primary key of both items before it can link these in a ManyToManyField. – Willem Van Onsem Nov 07 '21 at 18:26
  • The array I'm passing in contains fully-initialized objects with primary keys. Maybe I'm misunderstanding what you're describing though – Dave Nov 07 '21 at 18:56
  • He means the account model must be saved first. Just refer to the many to many documentation - https://docs.djangoproject.com/en/3.2/topics/db/examples/many_to_many/ – user1849962 Nov 07 '21 at 20:45
  • Edited my question to reflect doing it the second way ,but still getting some errors. – Dave Nov 23 '21 at 17:27
  • arrays? you mean a list, right? To add a list of M2M related objects, use a splat with add() (see here: https://stackoverflow.com/questions/4959499/how-to-add-multiple-objects-to-manytomany-relationship-at-once-in-django). Alternatively, use set() (see here: https://docs.djangoproject.com/en/dev/ref/models/relations/#django.db.models.fields.related.RelatedManager.set) – gregory Nov 24 '21 at 18:32

1 Answers1

4

From your edit, if crypto_currencies_arr contains a list of CryptoCurrency instances with primary keys, then you can just do:

def create_account(self, user, vendor, crypto_currencies_arr=[], max_transactions=DEFAULT_MAX_BUY_TRANSACTIONS):
    a = Account.objects.create(
        user=user,
        vendor=vendor,
        max_transactions=max_transactions,
    )
    a.crypto_currencies.set(crypto_currencies_arr)
Brian Destura
  • 11,487
  • 3
  • 18
  • 34