Adds one or more of ``instances`` to the relation. If it is already added, it will be silently ignored. :raises OperationalError: If Object to add is not saved.
(self, *instances: MODEL, using_db: BaseDBAsyncClient | None = None)
| 175 | self.instance = instance |
| 176 | |
| 177 | async def add(self, *instances: MODEL, using_db: BaseDBAsyncClient | None = None) -> None: |
| 178 | """ |
| 179 | Adds one or more of ``instances`` to the relation. |
| 180 | |
| 181 | If it is already added, it will be silently ignored. |
| 182 | |
| 183 | :raises OperationalError: If Object to add is not saved. |
| 184 | """ |
| 185 | if not instances: |
| 186 | return |
| 187 | if not self.instance._saved_in_db: |
| 188 | raise OperationalError(f"You should first call .save() on {self.instance}") |
| 189 | db = using_db or self.remote_model._meta.db |
| 190 | pk_formatting_func = type(self.instance)._meta.pk.to_db_value |
| 191 | related_pk_formatting_func = type(instances[0])._meta.pk.to_db_value |
| 192 | pk_b = pk_formatting_func(self.instance.pk, self.instance) |
| 193 | pks_f: list = [] |
| 194 | for instance_to_add in instances: |
| 195 | if not instance_to_add._saved_in_db: |
| 196 | raise OperationalError(f"You should first call .save() on {instance_to_add}") |
| 197 | pk_f = related_pk_formatting_func(instance_to_add.pk, instance_to_add) |
| 198 | pks_f.append(pk_f) |
| 199 | through_table = Table(self.field.through, schema=self.field.through_schema) |
| 200 | backward_key, forward_key = self.field.backward_key, self.field.forward_key |
| 201 | backward_field, forward_field = through_table[backward_key], through_table[forward_key] |
| 202 | select_query = ( |
| 203 | db.query_class.from_(through_table).where(backward_field == pk_b).select(forward_key) |
| 204 | ) |
| 205 | criterion = forward_field == pks_f[0] if len(pks_f) == 1 else forward_field.isin(pks_f) |
| 206 | select_query = select_query.where(criterion) |
| 207 | |
| 208 | _, already_existing_relations_raw = await db.execute_query( |
| 209 | *select_query.get_parameterized_sql() |
| 210 | ) |
| 211 | already_existing_forward_pks = { |
| 212 | related_pk_formatting_func(r[forward_key], self.instance) |
| 213 | for r in already_existing_relations_raw |
| 214 | } |
| 215 | |
| 216 | if pks_f_to_insert := set(pks_f) - already_existing_forward_pks: |
| 217 | query = db.query_class.into(through_table).columns(forward_field, backward_field) |
| 218 | for pk_f in pks_f_to_insert: |
| 219 | query = query.insert(pk_f, pk_b) |
| 220 | await db.execute_query(*query.get_parameterized_sql()) |
| 221 | |
| 222 | async def clear(self, using_db: BaseDBAsyncClient | None = None) -> None: |
| 223 | """ |