当前位置: 首页 > 面试题库 >

使用South重构具有继承性的Django模型

陶修洁
2023-03-14
问题内容

我在想,如果以下迁移是可能的Django的南部和仍然保留的数据。

之前:
我目前有两个应用程序,一个叫做电视,一个叫做电影,每个都有一个VideoFile模型(在这里简化):

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类并使用继承对其进行扩展:

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做到这一点并仍然维护现有数据?

所有这三个应用程序都已经由南迁移管理,根据南文档,将模式迁移和数据迁移结合起来是不明智的做法,他们建议应分几步完成。

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

  1. 模式迁移以重命名tv.VideoFile和movie.VideoFile中的所有字段,这些字段将移动到新的media.VideoFile模型中,也许重命名为old_name,old_size等
  2. 架构迁移到tv.VideoFile和movie.VideoFile以从media.VideoFile继承
  3. 数据迁移以将old_name复制到名称,将old_size复制到大小,等等
  4. 方案迁移以删除old_字段
    在我完成所有工作之前,你认为这行得通吗?有没有更好的办法?

问题答案:

我确实尝试遍历了T Stone概述的解决方案,尽管我认为这是一个了不起的入门,并解释了应该如何做,但我遇到了一些问题。

我认为大多数情况下,你不再需要为父类创建表条目,即你不需要

new_movie.videofile_ptr = orm['media.VideoFile'].objects.create()

不再。Django现在会自动为你执行此操作(如果你有非null字段,则以上内容对我不起作用,并给我一个数据库错误)。

我认为这可能是由于django和south的变化所致,这是一个适用于Django 1.2.3和south 0.7.1的ubuntu 10.10的版本。这些模型有些不同,但是你将获得要点:

初始设置
post1 / models.py:

class Author(models.Model):
    first = models.CharField(max_length=30)
    last = models.CharField(max_length=30)

class Tag(models.Model):
    name = models.CharField(max_length=30, primary_key=True)

class Post(models.Model):
    created_on = models.DateTimeField()
    author = models.ForeignKey(Author)
    tags = models.ManyToManyField(Tag)
    title = models.CharField(max_length=128, blank=True)
    content = models.TextField(blank=True)

post2 / models.py:

class Author(models.Model):
    first = models.CharField(max_length=30)
    middle = models.CharField(max_length=30)
    last = models.CharField(max_length=30)

class Tag(models.Model):
    name = models.CharField(max_length=30)

class Category(models.Model):
    name = models.CharField(max_length=30)

class Post(models.Model):
    created_on = models.DateTimeField()
    author = models.ForeignKey(Author)
    tags = models.ManyToManyField(Tag)
    title = models.CharField(max_length=128, blank=True)
    content = models.TextField(blank=True)
    extra_content = models.TextField(blank=True)
    category = models.ForeignKey(Category)

显然有很多重叠之处,因此我想将通用性分解为通用的后期模型,而只保留其他模型类中的差异。

新设置:

genpost / models.py:

class Author(models.Model):
    first = models.CharField(max_length=30)
    middle = models.CharField(max_length=30, blank=True)
    last = models.CharField(max_length=30)

class Tag(models.Model):
    name = models.CharField(max_length=30, primary_key=True)

class Post(models.Model):
    created_on = models.DateTimeField()
    author = models.ForeignKey(Author)
    tags = models.ManyToManyField(Tag)
    title = models.CharField(max_length=128, blank=True)
    content = models.TextField(blank=True)

post1 / models.py:

import genpost.models as gp

class SimplePost(gp.Post):
    class Meta:
        proxy = True
post2 / models.py:

import genpost.models as gp

class Category(models.Model):
    name = models.CharField(max_length=30)

class ExtPost(gp.Post):
    extra_content = models.TextField(blank=True)
    category = models.ForeignKey(Category)

如果你想继续前进,首先需要将这些模型推向南方:

$./manage.py schemamigration post1 --initial
$./manage.py schemamigration post2 --initial
$./manage.py migrate

迁移数据
怎么做呢?首先编写新的应用程序genpost,然后向南进行初始迁移:

$./manage.py schemamigration genpost --initial

(我$用来表示shell提示符,所以请不要键入。)

接下来,分别在post1 / models.py和post2 / models.py中创建新类SimplePost和ExtPost(请不要删除其余的类)。然后也为这两个创建schemamigrations:

$./manage.py schemamigration post1 --auto
$./manage.py schemamigration post2 --auto

现在我们可以应用所有这些迁移:

$./manage.py migrate

让我们开始讨论,将数据从post1和post2迁移到genpost:

$./manage.py datamigration genpost post1_and_post2_to_genpost --freeze post1 --freeze post2

然后编辑genpost / migrations / 0002_post1_and_post2_to_genpost.py:

class Migration(DataMigration):

    def forwards(self, orm):

        # 
        # Migrate common data into the new genpost models
        #
        for auth1 in orm['post1.author'].objects.all():
            new_auth = orm.Author()
            new_auth.first = auth1.first
            new_auth.last = auth1.last
            new_auth.save()

        for auth2 in orm['post2.author'].objects.all():
            new_auth = orm.Author()
            new_auth.first = auth2.first
            new_auth.middle = auth2.middle
            new_auth.last = auth2.last
            new_auth.save()

        for tag in orm['post1.tag'].objects.all():
            new_tag = orm.Tag()
            new_tag.name = tag.name
            new_tag.save()

        for tag in orm['post2.tag'].objects.all():
            new_tag = orm.Tag()
            new_tag.name = tag.name
            new_tag.save()

        for post1 in orm['post1.post'].objects.all():
            new_genpost = orm.Post()

            # Content
            new_genpost.created_on = post1.created_on
            new_genpost.title = post1.title
            new_genpost.content = post1.content

            # Foreign keys
            new_genpost.author = orm['genpost.author'].objects.filter(\
                    first=post1.author.first,last=post1.author.last)[0]

            new_genpost.save() # Needed for M2M updates
            for tag in post1.tags.all():
                new_genpost.tags.add(\
                        orm['genpost.tag'].objects.get(name=tag.name))

            new_genpost.save()
            post1.delete()

        for post2 in orm['post2.post'].objects.all():
            new_extpost = p2.ExtPost() 
            new_extpost.created_on = post2.created_on
            new_extpost.title = post2.title
            new_extpost.content = post2.content

            # Foreign keys
            new_extpost.author_id = orm['genpost.author'].objects.filter(\
                    first=post2.author.first,\
                    middle=post2.author.middle,\
                    last=post2.author.last)[0].id

            new_extpost.extra_content = post2.extra_content
            new_extpost.category_id = post2.category_id

            # M2M fields
            new_extpost.save()
            for tag in post2.tags.all():
                new_extpost.tags.add(tag.name) # name is primary key

            new_extpost.save()
            post2.delete()

        # Get rid of author and tags in post1 and post2
        orm['post1.author'].objects.all().delete()
        orm['post1.tag'].objects.all().delete()
        orm['post2.author'].objects.all().delete()
        orm['post2.tag'].objects.all().delete()


    def backwards(self, orm):
        raise RuntimeError("No backwards.")

现在应用这些迁移:

$./manage.py migrate

接下来,你可以从post1 / models.py和post2 / models.py中删除现在多余的部分,然后创建schemamigrations以将表更新为新状态:

$./manage.py schemamigration post1 --auto
$./manage.py schemamigration post2 --auto
$./manage.py migrate

就是这样!希望所有这些都能奏效,并且你已经重构了模型。



 类似资料:
  • 问题内容: 我想更改模型中特定字段的名称: 应更改为: 使用South进行此操作最简单的方法是什么? 问题答案: 你可以使用该功能。 的第一个参数是表名,因此记住如何创建表名很重要: Django自动从你的模型类和包含它的应用程序的名称中派生数据库表的名称。通过将模型的“应用程序标签”(即你在manage.py startapp中使用的名称)与模型的类名称连接在一起,并在其之间加下划线,来构造模型

  • 问题内容: 我一直在South的网站,Google和SO上寻找答案,但是找不到简单的方法来做到这一点。 我想使用South重命名Django模型。说你有以下几点: 并且你想要将转换为,即 为简单起见,我只是尝试将名称从更改为,但现在忽略其中的成员。 使用South进行此操作最简单的方法是什么? 我可能可以进行数据迁移,但这似乎很复杂。 编写一个自定义迁移,例如,但是在这种情况下我不确定如何修复外键

  • 你更喜欢/建议哪一个?

  • 我有一个BaseEntity,当我像这样制作mapper时,它有一个名为Customer的子级: Mapstruct不会自动映射BaseEntity字段。你能告诉我怎么做吗?

  • 问题内容: 我想将一个Web服务URL请求表示为一个对象,并发现在继承层次结构中可能有很多通用参数。一个请求可以有很多参数,一些是必选参数,而其他是可选参数,我相信Bloch的Builder模式是一个不错的选择,它可以使用流畅的接口模拟命名参数。 具体来说,我正在设计Google Maps网络服务API,该API具有常规的网络服务请求 和是必填参数,也是必填参数。还有一个可选参数。 每个服务都有其

  • 问题内容: 我正在寻找这样做: 这是我要使用的版本(尽管我可以接受任何建议):http : //docs.djangoproject.com/en/dev/topics/db/models/#id7 Django支持吗?如果没有,是否有办法获得类似的结果? 问题答案: 更新的答案:正如人们在评论中指出的那样,原始答案未正确回答问题。实际上,只有模型是在数据库中创建的,不是。 一种解决方案是创建一个