簡體   English   中英

Django 在管理 model 時嘗試添加現有字段

[英]Django trying to add an existing field when making a model managed

在管理 model 時,如何阻止 Django 2.2.4 嘗試創建已經存在的數據庫列?

我有 2 個模型,票證和消息,它們連接到第三方數據庫中的表,因此模型是使用managed=False創建的。 我正在遠離第三方工具。 票證 model 不久前被其他人更改為managed=True ,現在我正在嘗試對消息 model 執行相同的操作。

這些是 model 的相關部分:

from django.db import models

class Message(models.Model):
    mid = models.BigAutoField(db_column='MID', primary_key=True)
    ticket = models.ForeignKey('Ticket', on_delete=models.CASCADE, db_column='TID')
    author = models.CharField(db_column='AUTHOR', max_length=32)
    date = models.DateTimeField(db_column='DATE')
    internal = models.CharField(db_column='INTERNAL', max_length=1)
    isoper = models.CharField(db_column='ISOPER', max_length=1)
    headers = models.TextField(db_column='HEADERS')
    msg = models.TextField(db_column='MSG')

    class Meta:
        # managed = False
        db_table = 'messages'
        permissions = (
            ("can_change_own_worked_time", "Can change own worked time"),
            ("can_change_own_recently_worked_time", "Can change own recently worked time"),
            ("can_change_subordinate_worked_time", "Can change subordinate worked time"),
        )

這是通過注釋掉managed=False生成的遷移:

# Generated by Django 2.2.4 on 2020-06-18 20:56 (0017_auto_20200618_1656)

from django.db import migrations


class Migration(migrations.Migration):

    dependencies = [
        ('troubleticket', '0016_auto_20200511_1644'),
    ]

    operations = [
        migrations.AlterModelOptions(
            name='message',
            options={'permissions': (('can_change_own_worked_time', 'Can change own worked time'), ('can_change_own_recently_worked_time', 'Can change own recently worked time'), ('can_change_subordinate_worked_time', 'Can change subordinate worked time'))},
        ),
    ]
# Generated by Django 2.2.4 on 2020-06-18 21:14 (0018_message_ticket)

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    dependencies = [
        ('troubleticket', '0017_auto_20200618_1656'),
    ]

    operations = [
        migrations.AddField(
            model_name='message',
            name='ticket',
            field=models.ForeignKey(db_column='TID', default=1, on_delete=django.db.models.deletion.CASCADE, to='troubleticket.Ticket'),
            preserve_default=False,
        ),
    ]

當我嘗試應用這些遷移時,我收到此錯誤:

django.db.utils.OperationalError: (1060, "Duplicate column name 'TID'")

初始遷移不包括 TID 列,后續遷移也不包括任何后續遷移,所以我理解為什么 Django 認為這是一個新列。 但這不是一個新專欄(model 自從第一次提交給 git 回購以來就擁有它)所以我也明白為什么 MySQL 會拋出錯誤。

這是初始遷移:

# Generated by Django 2.0.8 on 2018-08-20 14:43 (0001_initial)

from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Message',
            fields=[
                ('mid', models.BigAutoField(db_column='MID', primary_key=True, serialize=False)),
                ('author', models.CharField(db_column='AUTHOR', max_length=32)),
                ('date', models.DateTimeField(db_column='DATE')),
                ('internal', models.CharField(db_column='INTERNAL', max_length=1)),
                ('isoper', models.CharField(db_column='ISOPER', max_length=1)),
                ('headers', models.TextField(db_column='HEADERS')),
                ('msg', models.TextField(db_column='MSG')),
            ],
            options={
                'managed': False,
                'db_table': 'messages',
            },
        ),
        migrations.CreateModel(
            name='Ticket',
            fields=[
                ('id', models.BigIntegerField(db_column='ID', primary_key=True, serialize=False)),
                ('accesskey', models.CharField(db_column='ACCESSKEY', max_length=64)),
                ('open', models.DateTimeField(db_column='OPEN')),
                ('updated', models.DateTimeField(db_column='UPDATED')),
                ('closed', models.DateTimeField(db_column='CLOSED', null=True)),
                ('status', models.CharField(db_column='STATUS', max_length=3)),
                ('oper', models.CharField(db_column='OPER', max_length=32)),
                ('email', models.CharField(db_column='EMAIL', max_length=128)),
                ('name', models.CharField(db_column='NAME', max_length=128)),
                ('subject', models.CharField(db_column='SUBJECT', max_length=255)),
                ('lname', models.CharField(db_column='LNAME', max_length=50)),
                ('company', models.CharField(db_column='C0', max_length=255)),
                ('type', models.CharField(db_column='C1', max_length=255)),
                ('c2', models.CharField(db_column='C2', max_length=255)),
                ('c3', models.DecimalField(db_column='C3', decimal_places=2, max_digits=6)),
                ('c4', models.CharField(db_column='C4', max_length=255)),
                ('pending', models.CharField(db_column='C5', max_length=255)),
                ('c6', models.CharField(db_column='C6', max_length=255)),
                ('c7', models.CharField(db_column='C7', max_length=255)),
                ('c8', models.CharField(db_column='C8', max_length=255)),
                ('cc', models.CharField(db_column='C9', max_length=255)),
                ('grp', models.CharField(db_column='GRP', max_length=10)),
                ('item', models.CharField(db_column='ITEM', max_length=255)),
            ],
            options={
                'managed': False,
                'db_table': 'tickets',
            },
        ),
    ]

寫完評論后 2 秒,我想出了解決問題的方法。

當從另一個 ORM“遷移”到 Django 時,請始終考慮以下方面。 以下是我的順序建議,但我仍在學習如何使用 django 遷移,所以請記住這一點。

1.考慮django目前已知model的哪些字段

需要注意的是,在計算要添加或更改哪些列時,數據庫的實際內容與 django 無關。 這意味着,在 django 模型的初始遷移中, managed仍然是=False ,列是由 django “創建”和注冊的。 當 makemigrations 計算要添加哪些列時,它只將初始遷移中提到的列作為給定。 不是數據庫的實際內容。

知道了這一點,我們現在可以 go 字段為字段並根據第 2 點決定每個字段。

2.考慮model的哪些字段應該或不應該由django創建

現在,一般來說,當設置 Model managed=True 字段時,將分為 3 類。

2.1 該字段目前在model定義,數據庫中,也是在初始提交中。

對於這種情況,無需采取任何措施。

2.2 該字段目前在model定義,數據庫中,但不在初始提交中。

對於這種情況,必須將字段定義添加到原始初始遷移腳本中。 因此,migrations.CreateModel 調用可能如下所示:

...
('field_already_present', models.FloatField(blank=True, null=True)),
...

2.3 該字段當前在數據庫中,但不在model定義或初始提交中

如果 django 應用程序中不需要該字段,則可以省略該字段。 如果在某些時候需要它,則必須將其添加到 model 以及第一次初始遷移中。 這樣,django makemigrations 將不會嘗試創建該字段。

3.設置管理=真

現在設置 managed=True 並進行遷移。 這樣做兩次! 第一次,makemigrations 會將 model 設置為 managed,然后它會添加初始提交中沒有的字段。

在此之后,model 可以被視為與正常創建和從頭開始管理的 django model 相同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM