当前位置: 首页 > news >正文

使用的电脑做网站的服务器站长之家站长工具

使用的电脑做网站的服务器,站长之家站长工具,政府网站如何建立,嘉兴做网站建设TL;DR 永远不要相信 makemigrations! migrate 之前一定好好看看 migrate 了啥东西,必要时手动修改生成的 migrate 文件。 最好把db的更新与服务代码更新解耦 场景 先描述下场景: 现在有两个表,一个是 question,一…

TL;DR

永远不要相信 makemigrations!

migrate 之前一定好好看看 migrate 了啥东西,必要时手动修改生成的 migrate 文件。

最好把db的更新与服务代码更新解耦

场景

先描述下场景:

现在有两个表,一个是 question,一个是 choice,其中 question 和 choice 是一对多的关系,其中 choice 表中会记录 question_id(此时不是外键约束)。

class Question(models.Model):content = models.CharField(max_length=256, blank=True, default='')class Choice(models.Model):content = models.CharField(max_length=256, default='')question_id = models.IntegerField(null=True)

现在我想把 question_id 改为外键,所以很自然的改写 model:

class Question(models.Model):content = models.CharField(max_length=256, blank=True, default='')class Choice(models.Model):content = models.CharField(max_length=256, default='')question = models.ForeignKey(Question, on_delete=models.DO_NOTHING) 

然后快乐地执行 makemigration -> migrate,然后 choice 里面的 question_id 就全没了(实际上我还手贱加了个 default,导致都关联到 default 的 question 上了),然后第二天因为左脚先进办公室被开了。。。

原因

在自己的 demo 上复现了下。

问题出在 makemigrate 生成的文件上,解析出来的 operations 是先把 question_id 列 remove 掉(RemoveField),然后再加上(AddField)。。。

这样设计的思路我不是很懂,可能是有些 engine(比如SQLite)不支持对现有的表加外键?

解决

修改 migration 文件,把先 remove 再 add 的逻辑调整一下。

需要用到 migration.RunPython,migration 文件应该长成下边这样:

from django.db import migrations, models
import django.db.models.deletiondef duplicate_question_id(apps, schema_editor):Choice = apps.get_model("polls", "Choice")for c in Choice.objects.all():Question = apps.get_model("polls", "Question")q = Question.objects.get(id=c.question_id)c.question_cpy = qc.save()class Migration(migrations.Migration):# 一些必要的依赖,这里大概率不用改dependencies = []operations = [migrations.AddField(model_name="choice",name="question_cpy",# question_cpy 先把 question_id 列的数据 copy 过来field=models.ForeignKey(null=True,on_delete=django.db.models.deletion.DO_NOTHING,to="polls.question",),),migrations.RunPython(code=duplicate_question_id,reverse_code=migrations.RunPython.noop,# reverse_code 是 migrate 回退时会执行的操作# noop 方法是为了支持回退的空方法),migrations.RemoveField(model_name="choice",name="question_id",),migrations.RenameField(model_name="choice",old_name="question_cpy",new_name="question",),]

注意:你需要根据实际情况编写合适的代码,上面仅提供思路。

如果你是在sqlite上测试,可以正常 migrate,但是外键不会生效(因为 sqlite 默认关闭外键)。

如果在 mysql 上测试,应该是可以成功的(待验证)。

除了 RunPython 之外还可以用RunSQL,然后仔细确定SQL的合法性,个人感觉会更安全一些,毕竟直接操作 DB 的部分,普遍会认为潜在风险较高,会对相应动作有更高的敏感度。(不过最关键的还是要感知 makemigrations 其实不是个靠谱的东西)

又跟了下这个问题,发现在 AlterField 里面指定外键的 db_column,然后再 rename 成 model 里面指定的 name 即可实现上述需求,类似:

		migrations.AlterField(model_name="choice",name="question_id",field=models.ForeignKey(name='question',to='polls.question',on_delete=django.db.models.deletion.DO_NOTHING,db_column='question_id',null=False),),migrations.RenameField(model_name="choice",old_name="question_id",new_name="question",)

这里还有些需要注意的地方,migration 整体上是通过 DDL 事务执行的,但是有些 SQL 引擎不支持DDL 事务(比如 MySQL),所以可能会出现 migrate 不成功然后无法回滚的情况(一个 migration 可能会对应两条 SQL 语句),需要关注。

避免

永远不要相信 makemigrations!

最好把db的更新与服务代码更新解耦

Django 还提供了 sqlmigrate 这个命令,可以看对应的 migrations 动作具体会解析成哪些 sql 语句执行,可以在 merge 之前把对应的 sql 语句进行一次 review。

推荐

migrate 其实分 code state 和 db state 两部分,可以把这两部分开设置:change field name with no db impact

http://www.hkea.cn/news/316829/

相关文章:

  • 做网站找哪个部门吸引人的推广标题
  • 网站制作软件名字线做竞价推广代运营公司
  • avada如何做中英文网站沈阳百度推广排名优化
  • 做网站品长沙网络营销公司排名
  • b2b商贸网站环球网最新消息疫情
  • wordpress next主题什么是seo教程
  • 如何规划一个网站快手秒赞秒评网站推广
  • 中国网站开发网站seo需要用到哪些工具
  • 织梦做的网站首页出现空白网页平台做个业务推广
  • 备案做电影网站吗yandx引擎入口
  • 网站双倍浮动百度账号登陆入口
  • 聊城市网站建设网站推广排名
  • 帝国新闻网站模板百度seo推广怎么做
  • 预约做港澳证的网站网站排名在线优化工具
  • 罗湖实惠的网站建设费用成都官网seo厂家
  • 建设部官方网站有哪些优帮云排名优化
  • 天津做网站找谁新东方在线教育平台官网
  • 南宁做网站在哪了日本预测比分
  • 咋样查看网站用什么编程语言做的9个广州seo推广神技
  • 网站链接太多怎么做网站地图谷歌广告
  • 网站关键词更新临汾网络推广
  • 个人做网站靠什么盈利免费网站建设模板
  • 网站开发 打标签aso优化怎么做
  • 教育校园网站建设方案seo每天一贴
  • 怎么看网站的建设时间推广公司品牌
  • 营销型网站有什么特点英语培训机构
  • 学院网站的系统建设方式宝鸡网站seo
  • 网站客户端怎么做的百度一下了你就知道官网
  • 有什么推广方法优化大师电脑版官方
  • 自己做网站的服务器上海网站建设公司排名