# Buggy code
async def add(self, *instances, using_db=None) -> None:
    """
    Adds one or more of ``instances`` to the relation.

    If it is already added, it will be silently ignored.
    """
    if not instances:
        return
    if self.instance.pk is None:
        raise OperationalError(
            "You should first call .save() on {model}".format(model=self.instance)
        )
    db = using_db if using_db else self.model._meta.db
    pk_formatting_func = type(self.instance)._meta.pk.to_db_value
    related_pk_formatting_func = type(instances[0])._meta.pk.to_db_value
    through_table = Table(self.field.through)
    select_query = (
        db.query_class.from_(through_table)
        .where(
            getattr(through_table, self.field.backward_key)
            == pk_formatting_func(self.instance.pk, self.instance)
        )
        .select(self.field.backward_key, self.field.forward_key)
    )
    query = db.query_class.into(through_table).columns(
        getattr(through_table, self.field.forward_key),
        getattr(through_table, self.field.backward_key),
    )

    if len(instances) == 1:
        criterion = getattr(
            through_table, self.field.forward_key
        ) == related_pk_formatting_func(instances[0].pk, instances[0])
    else:
        criterion = getattr(through_table, self.field.forward_key).isin(
            [related_pk_formatting_func(i.pk, i) for i in instances]
        )

    select_query = select_query.where(criterion)

    already_existing_relations_raw = await db.execute_query(str(select_query))
    already_existing_relations = {
        (r[self.field.backward_key], r[self.field.forward_key])
        for r in already_existing_relations_raw
    }

    insert_is_required = False
    for instance_to_add in instances:
        if instance_to_add.pk is None:
            raise OperationalError(
                "You should first call .save() on {model}".format(model=instance_to_add)
            )
        if (self.instance.pk, instance_to_add.pk) in already_existing_relations:
            continue
        query = query.insert(
            related_pk_formatting_func(instance_to_add.pk, instance_to_add),
            pk_formatting_func(self.instance.pk, self.instance),
        )
        insert_is_required = True
    if insert_is_required:
        await db.execute_query(str(query))


# Traceback (asyncpg.exceptions.PostgresSyntaxError)
DEBUG:asyncio:Using selector: EpollSelector
INFO:tortoise:Tortoise-ORM startup
connections: {'default': {'engine': 'tortoise.backends.asyncpg', 'credentials': {'port': 5432, 'database': 'postgres', 'host': '172.20.0.2', 'user': 'postgres', 'password': 'postgres'}}}
apps: {'models': {'models': ['__main__'], 'default_connection': 'default'}}
DEBUG:db_client:Created connection <asyncpg.connection.Connection object at 0x7fd621f828b8> with params: {'host': '172.20.0.2', 'port': 5432, 'user': 'postgres', 'database': 'postgres'}
DEBUG:db_client:CREATE TABLE IF NOT EXISTS "modela" ("id" UUID NOT NULL PRIMARY KEY); CREATE TABLE IF NOT EXISTS "modelb" ("id" UUID NOT NULL PRIMARY KEY); CREATE TABLE IF NOT EXISTS "modelb_modela" ("modelb_id" UUID NOT NULL REFERENCES "modelb" (id) ON DELETE CASCADE,"modela_id" UUID NOT NULL REFERENCES "modela" (id) ON DELETE CASCADE);
DEBUG:db_client:INSERT INTO "modela" ("id") VALUES ($1): ['075c03a6-b777-4044-876e-d5877478318d']
DEBUG:db_client:INSERT INTO "modelb" ("id") VALUES ($1): ['8a5ad9d6-fc30-4aba-a41b-377595cddb5f']
DEBUG:db_client:SELECT "modelb_id","modela_id" FROM "modelb_modela" WHERE "modelb_id"='8a5ad9d6-fc30-4aba-a41b-377595cddb5f' AND "modela_id"='075c03a6-b777-4044-876e-d5877478318d'
DEBUG:db_client:INSERT INTO "modelb_modela" ("modela_id","modelb_id") VALUES ('075c03a6-b777-4044-876e-d5877478318d','8a5ad9d6-fc30-4aba-a41b-377595cddb5f')
INFO:root:asyncpg result [<Record _backward_relation_key=UUID('075c03a6-b777-4044-876e-d5877478318d') id=UUID('8a5ad9d6-fc30-4aba-a41b-377595cddb5f')>]
DEBUG:db_client:SELECT "id" FROM "modela" WHERE "id"='075c03a6-b777-4044-876e-d5877478318d' LIMIT 2
DEBUG:db_client:SELECT "sq0"."_backward_relation_key" "_backward_relation_key","modelb"."id" "id" FROM "modelb" JOIN (SELECT "modela_id" "_backward_relation_key","modelb_id" "_forward_relation_key" FROM "modelb_modela" WHERE "modela_id" IN (075c03a6-b777-4044-876e-d5877478318d)) "sq0" ON "sq0"."_forward_relation_key"="modelb"."id"
Traceback (most recent call last):
File "/home/nik/.virtualenvs/tortoise-pk-error/lib/python3.7/site-packages/tortoise/backends/asyncpg/client.py", line 63, in translate_exceptions_
return await func(self, *args)
File "/home/nik/.virtualenvs/tortoise-pk-error/lib/python3.7/site-packages/tortoise/backends/asyncpg/client.py", line 30, in retry_connection_
return await func(self, *args)
File "/home/nik/.virtualenvs/tortoise-pk-error/lib/python3.7/site-packages/tortoise/backends/asyncpg/client.py", line 174, in execute_query
return await connection.fetch(query)
File "/home/nik/.virtualenvs/tortoise-pk-error/lib/python3.7/site-packages/asyncpg/connection.py", line 421, in fetch
return await self._execute(query, args, 0, timeout)
File "/home/nik/.virtualenvs/tortoise-pk-error/lib/python3.7/site-packages/asyncpg/connection.py", line 1414, in _execute
query, args, limit, timeout, return_status=return_status)
File "/home/nik/.virtualenvs/tortoise-pk-error/lib/python3.7/site-packages/asyncpg/connection.py", line 1422, in __execute
return await self._do_execute(query, executor, timeout)
File "/home/nik/.virtualenvs/tortoise-pk-error/lib/python3.7/site-packages/asyncpg/connection.py", line 1434, in _do_execute
stmt = await self._get_statement(query, None)
File "/home/nik/.virtualenvs/tortoise-pk-error/lib/python3.7/site-packages/asyncpg/connection.py", line 329, in _get_statement
statement = await self._protocol.prepare(stmt_name, query, timeout)
File "asyncpg/protocol/protocol.pyx", line 163, in prepare
asyncpg.exceptions.PostgresSyntaxError: syntax error at or near "c03a6"

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "main.py", line 50, in <module>
asyncio.run(main())
File "/usr/lib64/python3.7/asyncio/runners.py", line 43, in run
return loop.run_until_complete(main)
File "/usr/lib64/python3.7/asyncio/base_events.py", line 584, in run_until_complete
return future.result()
File "main.py", line 47, in main
await a.fetch_related("b_models")
File "/home/nik/.virtualenvs/tortoise-pk-error/lib/python3.7/site-packages/tortoise/models.py", line 422, in fetch_related
await db.executor_class(model=self.__class__, db=db).fetch_for_list([self], *args)
File "/home/nik/.virtualenvs/tortoise-pk-error/lib/python3.7/site-packages/tortoise/backends/base/executor.py", line 284, in fetch_for_list
await self._execute_prefetch_queries(instance_list)
File "/home/nik/.virtualenvs/tortoise-pk-error/lib/python3.7/site-packages/tortoise/backends/base/executor.py", line 267, in _execute_prefetch_queries
await self._do_prefetch(instance_list, field, related_query)
File "/home/nik/.virtualenvs/tortoise-pk-error/lib/python3.7/site-packages/tortoise/backends/base/executor.py", line 259, in _do_prefetch
return await self._prefetch_m2m_relation(instance_id_list, field, related_query)
File "/home/nik/.virtualenvs/tortoise-pk-error/lib/python3.7/site-packages/tortoise/backends/base/executor.py", line 201, in _prefetch_m2m_relation
raw_results = await self.db.execute_query(query.get_sql())
File "/home/nik/.virtualenvs/tortoise-pk-error/lib/python3.7/site-packages/tortoise/backends/asyncpg/client.py", line 65, in translate_exceptions_
raise OperationalError(exc)
tortoise.exceptions.OperationalError: syntax error at or near "c03a6"

# Fixed code
async def add(self, *instances, using_db=None) -> None:
    """
    Adds one or more of ``instances`` to the relation.

    If it is already added, it will be silently ignored.
    """
    if not instances:
        return
    if not self.instance._saved_in_db:
        raise OperationalError(
            "You should first call .save() on {model}".format(model=self.instance)
        )
    db = using_db if using_db else self.model._meta.db
    pk_formatting_func = type(self.instance)._meta.pk.to_db_value
    related_pk_formatting_func = type(instances[0])._meta.pk.to_db_value
    through_table = Table(self.field.through)
    select_query = (
        db.query_class.from_(through_table)
        .where(
            getattr(through_table, self.field.backward_key)
            == pk_formatting_func(self.instance.pk, self.instance)
        )
        .select(self.field.backward_key, self.field.forward_key)
    )
    query = db.query_class.into(through_table).columns(
        getattr(through_table, self.field.forward_key),
        getattr(through_table, self.field.backward_key),
    )

    if len(instances) == 1:
        criterion = getattr(
            through_table, self.field.forward_key
        ) == related_pk_formatting_func(instances[0].pk, instances[0])
    else:
        criterion = getattr(through_table, self.field.forward_key).isin(
            [related_pk_formatting_func(i.pk, i) for i in instances]
        )

    select_query = select_query.where(criterion)

    # TODO: This is highly inefficient. Should use UNIQUE index by default.
    #  And optionally allow duplicates.
    already_existing_relations_raw = await db.execute_query(str(select_query))
    already_existing_relations = {
        (
            pk_formatting_func(r[self.field.backward_key], self.instance),
            related_pk_formatting_func(r[self.field.forward_key], self.instance),
        )
        for r in already_existing_relations_raw
    }

    insert_is_required = False
    for instance_to_add in instances:
        if not instance_to_add._saved_in_db:
            raise OperationalError(
                "You should first call .save() on {model}".format(model=instance_to_add)
            )
        pk_f = related_pk_formatting_func(instance_to_add.pk, instance_to_add)
        pk_b = pk_formatting_func(self.instance.pk, self.instance)
        if (pk_b, pk_f) in already_existing_relations:
            continue
        query = query.insert(pk_f, pk_b)
        insert_is_required = True
    if insert_is_required:
        await db.execute_query(str(query))