<i id='2ucCZ'><tr id='2ucCZ'><dt id='2ucCZ'><q id='2ucCZ'><span id='2ucCZ'><b id='2ucCZ'><form id='2ucCZ'><ins id='2ucCZ'></ins><ul id='2ucCZ'></ul><sub id='2ucCZ'></sub></form><legend id='2ucCZ'></legend><bdo id='2ucCZ'><pre id='2ucCZ'><center id='2ucCZ'></center></pre></bdo></b><th id='2ucCZ'></th></span></q></dt></tr></i><div id='2ucCZ'><tfoot id='2ucCZ'></tfoot><dl id='2ucCZ'><fieldset id='2ucCZ'></fieldset></dl></div>

    1. <legend id='2ucCZ'><style id='2ucCZ'><dir id='2ucCZ'><q id='2ucCZ'></q></dir></style></legend>

          <bdo id='2ucCZ'></bdo><ul id='2ucCZ'></ul>
        <tfoot id='2ucCZ'></tfoot>

        <small id='2ucCZ'></small><noframes id='2ucCZ'>

      1. 使用 south 重构具有继承的 Django 模型

        时间:2023-10-19
          <tbody id='ikctc'></tbody>
          <legend id='ikctc'><style id='ikctc'><dir id='ikctc'><q id='ikctc'></q></dir></style></legend>

          <small id='ikctc'></small><noframes id='ikctc'>

              <i id='ikctc'><tr id='ikctc'><dt id='ikctc'><q id='ikctc'><span id='ikctc'><b id='ikctc'><form id='ikctc'><ins id='ikctc'></ins><ul id='ikctc'></ul><sub id='ikctc'></sub></form><legend id='ikctc'></legend><bdo id='ikctc'><pre id='ikctc'><center id='ikctc'></center></pre></bdo></b><th id='ikctc'></th></span></q></dt></tr></i><div id='ikctc'><tfoot id='ikctc'></tfoot><dl id='ikctc'><fieldset id='ikctc'></fieldset></dl></div>
                <bdo id='ikctc'></bdo><ul id='ikctc'></ul>

                  <tfoot id='ikctc'></tfoot>
                  本文介绍了使用 south 重构具有继承的 Django 模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

                  问题描述

                  我想知道使用 Django south 是否可以进行以下迁移并且仍然保留数据.

                  I was wondering if the following migration is possible with Django south and still retain data.

                  我目前有两个应用,一个叫 tv,一个叫电影,每个都有一个 VideoFile 模型(此处简化):

                  I currently have two apps, one called tv, one called movies, each with a VideoFile model (simplified here):

                  tv/models.py:

                  class VideoFile(models.Model):
                      show = models.ForeignKey(Show, blank=True, null=True)
                      name = models.CharField(max_length=1024, blank=True)
                      size = models.IntegerField(blank=True, null=True)
                      ctime = models.DateTimeField(blank=True, null=True)
                  

                  movies/models.py:

                  class VideoFile(models.Model):
                      movie = models.ForeignKey(Movie, blank=True, null=True)
                      name = models.CharField(max_length=1024, blank=True)
                      size = models.IntegerField(blank=True, null=True)
                      ctime = models.DateTimeField(blank=True, null=True)
                  

                  之后:

                  因为这两个 videofile 对象非常相似,我想摆脱重复并在一个名为 media 的单独应用程序中创建一个新模型,该应用程序包含一个通用 VideoFile 类并使用继承来扩展它:

                  After:

                  Because the two videofile objects are so similar I want to get rid of duplication and create a new model in a separate app called media that contains a generic VideoFile class and use inheritance to extend it:

                  media/models.py:

                  class VideoFile(models.Model):
                      name = models.CharField(max_length=1024, blank=True)
                      size = models.IntegerField(blank=True, null=True)
                      ctime = models.DateTimeField(blank=True, null=True)
                  

                  tv/models.py:

                  class VideoFile(media.models.VideoFile):
                      show = models.ForeignKey(Show, blank=True, null=True)
                  

                  movies/models.py:

                  class VideoFile(media.models.VideoFile):
                      movie = models.ForeignKey(Movie, blank=True, null=True)
                  

                  所以我的问题是,我如何使用 django-south 完成此任务并仍然维护现有数据?

                  So my question is, how can I accomplish this with django-south and still maintain existing data?

                  所有这三个应用程序都已由 south 迁移管理,根据 south 文档,将架构和数据迁移结合起来是一种不好的做法,他们建议应该分几步完成.

                  All three these apps are already managed by south migrations and according to the south documentation it is bad practice to combine a schema and data migration and they recommend it should be done in a few steps.

                  我认为可以使用像这样的单独迁移来完成(假设 media.VideoFile 已经创建)

                  I think it could be done using separate migrations like this (assuming media.VideoFile is already created)

                  1. 架构迁移以重命名 tv.VideoFile 和 movies.VideoFile 中的所有字段,这些字段将移动到新的 media.VideoFile 模型,可能是 old_name、old_size 等
                  2. 架构迁移到 tv.VideoFile 和 movies.VideoFile 以从 media.VideoFile 继承
                  3. 将 old_name 复制到 name、old_size 到 size 等的数据迁移
                  4. 计划迁移以移除 old_ 字段

                  在我完成所有这些工作之前,你认为这会奏效吗?有没有更好的办法?

                  Before I go through all that work, do you think that will work? Is there a better way?

                  如果您有兴趣,该项目在此处托管:http://code.google.com/p/medianav/

                  If you're interested, the project is hosted here: http://code.google.com/p/medianav/

                  推荐答案

                  查看下面 Paul 的回复,了解与新版本 Django/South 的兼容性的一些说明.

                  这似乎是一个有趣的问题,而且我正在成为 South 的忠实粉丝,所以我决定稍微研究一下.我根据您上面描述的摘要构建了一个测试项目,并已成功使用 South 执行您所询问的迁移.在我们进入代码之前,这里有几点说明:

                  This seemed like an interesting problem, and I'm becoming a big fan of South, so I decided to look into this a bit. I built a test project on the abstract of what you've described above, and have successfully used South to perform the migration you are asking about. Here's a couple of notes before we get to the code:

                  • South 文档建议将架构迁移和数据迁移分开进行.我也照做了.

                  • The South documentation recommends doing schema migrations and data migrations separate. I've followed suit in this.

                  在后端,Django 通过在继承模型上自动创建 OneToOne 字段来表示继承表

                  On the backend, Django represents an inherited table by automatically creating a OneToOne field on the inheriting model

                  了解这一点,我们的 South 迁移需要手动正确处理 OneToOne 字段,但是,在试验中,South(或者可能是 Django 本身)似乎无法在多个继承的同名表上创建 OneToOne.因此,我将电影/电视应用程序中的每个子表重命名为与其自己的应用程序相对应(即 MovieVideoFile/ShowVideoFile).

                  Understanding this, our South migration needs to properly handle the OneToOne field manually, however, in experimenting with this it seems that South (or perhaps Django itself) cannot create a OneToOne filed on multiple inherited tables with the same name. Because of this, I renamed each child-table in the movies/tv app to be respective to it's own app (ie. MovieVideoFile/ShowVideoFile).

                  在实际的数据迁移代码中,South 似乎更喜欢先创建 OneToOne 字段,然后将数据分配给它.在创建期间将数据分配给 OneToOne 字段会导致 South 阻塞.(对南方所有凉爽的公平妥协).

                  In playing with the actual data migration code, it seems South prefers to create the OneToOne field first, and then assign data to it. Assigning data to the OneToOne field during creation cause South to choke. (A fair compromise for all the coolness that is South).

                  说了这么多,我试着记录控制台命令的发布.我会在必要时插入评论.最终代码在底部.

                  So having said all that, I tried to keep a log of the console commands being issued. I'll interject commentary where necessary. The final code is at the bottom.

                  django-admin.py startproject southtest
                  manage.py startapp movies
                  manage.py startapp tv
                  manage.py syncdb
                  manage.py startmigration movies --initial
                  manage.py startmigration tv --initial
                  manage.py migrate
                  manage.py shell          # added some fake data...
                  manage.py startapp media
                  manage.py startmigration media --initial
                  manage.py migrate
                  # edited code, wrote new models, but left old ones intact
                  manage.py startmigration movies unified-videofile --auto
                  # create a new (blank) migration to hand-write data migration
                  manage.py startmigration movies videofile-to-movievideofile-data 
                  manage.py migrate
                  # edited code, wrote new models, but left old ones intact
                  manage.py startmigration tv unified-videofile --auto
                  # create a new (blank) migration to hand-write data migration
                  manage.py startmigration tv videofile-to-movievideofile-data
                  manage.py migrate
                  # removed old VideoFile model from apps
                  manage.py startmigration movies removed-videofile --auto
                  manage.py startmigration tv removed-videofile --auto
                  manage.py migrate
                  

                  为了篇幅,由于模型最终看起来总是一样的,我将只使用电影"应用程序进行演示.

                  For space sake, and since the models invariably look the same in the end, I'm only going to demonstrate with 'movies' app.

                  from django.db import models
                  from media.models import VideoFile as BaseVideoFile
                  
                  # This model remains until the last migration, which deletes 
                  # it from the schema.  Note the name conflict with media.models
                  class VideoFile(models.Model):
                      movie = models.ForeignKey(Movie, blank=True, null=True)
                      name = models.CharField(max_length=1024, blank=True)
                      size = models.IntegerField(blank=True, null=True)
                      ctime = models.DateTimeField(blank=True, null=True)
                  
                  class MovieVideoFile(BaseVideoFile):
                      movie = models.ForeignKey(Movie, blank=True, null=True, related_name='shows')
                  

                  movies/migrations/0002_unified-videofile.py(架构迁移)

                  from south.db import db
                  from django.db import models
                  from movies.models import *
                  
                  class Migration:
                  
                      def forwards(self, orm):
                  
                          # Adding model 'MovieVideoFile'
                          db.create_table('movies_movievideofile', (
                              ('videofile_ptr', orm['movies.movievideofile:videofile_ptr']),
                              ('movie', orm['movies.movievideofile:movie']),
                          ))
                          db.send_create_signal('movies', ['MovieVideoFile'])
                  
                      def backwards(self, orm):
                  
                          # Deleting model 'MovieVideoFile'
                          db.delete_table('movies_movievideofile')
                  

                  movies/migration/0003_videofile-to-movievideofile-data.py(数据迁移)

                  from south.db import db
                  from django.db import models
                  from movies.models import *
                  
                  class Migration:
                  
                      def forwards(self, orm):
                          for movie in orm['movies.videofile'].objects.all():
                              new_movie = orm.MovieVideoFile.objects.create(movie = movie.movie,)
                              new_movie.videofile_ptr = orm['media.VideoFile'].objects.create()
                  
                              # videofile_ptr must be created first before values can be assigned
                              new_movie.videofile_ptr.name = movie.name
                              new_movie.videofile_ptr.size = movie.size
                              new_movie.videofile_ptr.ctime = movie.ctime
                              new_movie.videofile_ptr.save()
                  
                      def backwards(self, orm):
                          print 'No Backwards'
                  

                  南方太棒了!

                  好的标准免责声明:您正在处理实时数据.我在这里给了你工作代码,但是请使用 --db-dry-run 来测试你的模式.在尝试任何事情之前务必进行备份,并且通常要小心.

                  South is awesome!

                  Ok standard disclaimer: You're dealing with live data. I've given you working code here, but please use the --db-dry-run to test your schema. Always make a backup before trying anything, and generally be careful.

                  兼容性声明

                  我将保持原始消息不变,但 South 已将命令 manage.py startmigration 更改为 manage.py schemamigration.

                  I'm going to keep my original message intact, but South has since changed the command manage.py startmigration into manage.py schemamigration.

                  这篇关于使用 south 重构具有继承的 Django 模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                  上一篇:如何使 Django 自定义管理命令参数不需要? 下一篇:您打算如何处理向 Python 3 的迁移?

                  相关文章

                  <i id='8GMIW'><tr id='8GMIW'><dt id='8GMIW'><q id='8GMIW'><span id='8GMIW'><b id='8GMIW'><form id='8GMIW'><ins id='8GMIW'></ins><ul id='8GMIW'></ul><sub id='8GMIW'></sub></form><legend id='8GMIW'></legend><bdo id='8GMIW'><pre id='8GMIW'><center id='8GMIW'></center></pre></bdo></b><th id='8GMIW'></th></span></q></dt></tr></i><div id='8GMIW'><tfoot id='8GMIW'></tfoot><dl id='8GMIW'><fieldset id='8GMIW'></fieldset></dl></div>
                  • <bdo id='8GMIW'></bdo><ul id='8GMIW'></ul>
                      <tfoot id='8GMIW'></tfoot>

                      <small id='8GMIW'></small><noframes id='8GMIW'>

                    1. <legend id='8GMIW'><style id='8GMIW'><dir id='8GMIW'><q id='8GMIW'></q></dir></style></legend>