tortoise / tortoise-orm

Familiar asyncio ORM for python, built with relations in mind
https://tortoise.github.io
Apache License 2.0
4.66k stars 387 forks source link

No IF NOT EXISTS on `through` table #168

Closed isac322 closed 5 years ago

isac322 commented 5 years ago

Describe the bug

When creating a table using Tortoise.generate_schemas(), IF NOT EXISTS was not added to the table created by through of fields.ManyToManyField.

To Reproduce

just run

python main.py

and it prints tortoise.exceptions.OperationalError: (1050, "Table 'event_team' already exists")

And I have found that the generated query is

CREATE TABLE IF NOT EXISTS `team` (
    `id`   INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
    `name` TEXT         NOT NULL
);
CREATE TABLE IF NOT EXISTS `tournament` (
    `id`   INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
    `name` TEXT         NOT NULL
);
CREATE TABLE IF NOT EXISTS `event` (
    `id`            INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
    `name`          TEXT         NOT NULL,
    `tournament_id` INT          NOT NULL REFERENCES `tournament`(`id`) ON DELETE CASCADE
);
CREATE TABLE `event_team` (
    `event_id` INT NOT NULL REFERENCES `event`(`id`) ON DELETE CASCADE,
    `team_id`  INT NOT NULL REFERENCES `team`(`id`) ON DELETE CASCADE
);

models.py (same as example on README of this project)

from tortoise import fields
from tortoise.models import Model

class Tournament(Model):
    id = fields.IntField(pk=True)
    name = fields.TextField()

    def __str__(self):
        return self.name

class Event(Model):
    id = fields.IntField(pk=True)
    name = fields.TextField()
    tournament = fields.ForeignKeyField('models.Tournament', related_name='events')
    participants = fields.ManyToManyField('models.Team', related_name='events', through='event_team')

    def __str__(self):
        return self.name

class Team(Model):
    id = fields.IntField(pk=True)
    name = fields.TextField()

    def __str__(self):
        return self.name

main.py

import tortoise

from tortoise import Tortoise

async def test():
    await Tortoise.init({
        'connections': {
            'default': {
                'engine': tortoise.backends.mysql.__name__,
                'credentials': {
                    # some data
                }
            },
        },
        'apps': {
            'models': {
                'models': ['models'],
            }
        }
    })

    await Tortoise.generate_schemas()
    await Tortoise.close_connections()

tortoise.run_async(test())
tortoise.run_async(test())

Expected behavior IF NOT EXISTS should be added to the generated query.

Additional context

tortoise-orm==0.12.8 aiomysql==0.0.20

MySQL is 8.0.7 Python is 3.7.4

grigi commented 5 years ago

Ah, good catch. I was just working on fixing up schema generation. Will add a test case for safe creation. It should be fixed for 0.13.0 release.

grigi commented 5 years ago

Turns out this issue only reflected on MySQL. It should be fixed on #169

Could you test if that resolved your issue (and everything works fine)? An easy way would be to pip install https://github.com/tortoise/tortoise-orm/archive/fix_safe_m2m.zip

isac322 commented 5 years ago

Thanks it works!