3

我正在尝试在 django 中将 ForeignKey 转换为 GenericForeignKey。我计划在三个迁移中执行此操作,mig1、mig2、mig3。

迁移 1 (mig1) 具有以下代码

class Migration(migrations.Migration):

    dependencies = [
        ('contenttypes', '0002_remove_content_type_name'),
        ('post_service', '0008_auto_20180802_1112'),
    ]

    operations = [
        migrations.AddField(
            model_name='comment',
            name='content_type',
            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType'),
        ),
        migrations.AddField(
            model_name='comment',
            name='object_id',
            field=models.PositiveIntegerField(null=True),
        ),
    ]

迁移 2 (mig2) 有以下代码

def change_posts_to_generic_key_comment(apps, schema_editor):
    Comment  = apps.get_model('post_service', 'Comment')
    db_alias = schema_editor.connection.alias
    comments = Comment.objects.using(db_alias).all()
    for comment in comments:
        Comment.objects.filter(id=comment.id).update(content_object=comment.post)

def reverse_change_posts_to_generic_key_comment(apps, schema_editor):
    Comment  = apps.get_model('post_service', 'Comment')
    db_alias = schema_editor.connection.alias
    comments = Comment.objects.using(db_alias).all()
    for comment in comments:
        Comment.objects.filter(id=comment.id).update(content_object=)

class Migration(migrations.Migration):

    dependencies = [
        ('post_service', '0009_auto_20180802_1623'),
    ]

    operations = [
        migrations.RunPython(change_posts_to_generic_key_comment, reverse_change_posts_to_generic_key_comment),
    ]

我尝试同时使用对象的更新和直接分配

comment.content_object = content.post其次是comment.save()

它们似乎都不起作用。我如何更新通用外键字段。

一种方法是手动设置content_typeobject_id。有没有更好的方法来做到这一点?

编辑:评论模型

class Comment(models.Model):

    post = models.ForeignKey(Post,on_delete=models.CASCADE)

    # Fields for generic relation
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True)
    object_id = models.PositiveIntegerField(null=True)
    content_object = GenericForeignKey()
4

2 回答 2

2

我在迁移中更新通用外键时遇到问题。如果我尝试将密钥直接设置为对象,它不会在保存时设置任何内容(因为它无法识别 GenericForeignKey),如果我尝试设置 content_type 和 object_id,我会收到关于 content_type 必须设置为 ContentType 的错误(这就是我在做)。

最后,我创建了一个从迁移运行的管理命令,如下所示:

from django.db import migrations, models
import django.db.models.deletion
from django.core.management import call_command

def populate_discounts(apps, schema_editor):
    """
    I could not get special to update as a generic foriegn key in the 
    migration. Do it as a one off management command
    """
    call_command('initialise_credit_specials')


class Migration(migrations.Migration):

    dependencies = [
        ('contenttypes', '0002_remove_content_type_name'),
        ('money', '0068_auto_20190123_0147'),
    ]

    operations = [
        migrations.AddField(
            model_name='invoicecredit',
            name='special_id',
            field=models.PositiveIntegerField(blank=True, null=True),
        ),
        migrations.AddField(
            model_name='invoicecredit',
            name='special_type',
            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.ContentType'),
        ),
        migrations.RunPython(populate_discounts)
    ]

我的管理命令非常简单:

from django.core.management.base import CommandError, BaseCommand    
from money.models import InvoiceCredit, PromotionCode, Sale


class Command(BaseCommand):
    """
    Report how much we need to refund at the end of the financial year
    """
    def handle(self, *args, **options):
        print('updating discounts')
        # first promotions 
        for pc in PromotionCode.objects.all():
            ics = InvoiceCredit.objects.filter(
                desc__contains=pc.code
                )
            for ic in ics.all():
                ic.special = pc
                ic.save()
                print('invoice credit %d updated with %s' % (ic.id, ic.special.code))

        # Then sales
        for sale in Sale.objects.all():
            ics = InvoiceCredit.objects.filter(
                desc__startswith=Sale.desc,
                invoice__booking__tour_date__tour=sale.tour_combinations.first().base_tour
                )
            for ic in ics.all():
                ic.special = sale
                ic.save()
                print('invoice credit %d updated with sale %d' % (ic.id, sale.id))
于 2019-01-25T01:41:00.377 回答
2

没有理由在这里使用过滤器和更新。你已经有了对象。

for comment in comments:
    comment.content_object = comment.post
    comment.save()
于 2018-08-03T10:31:34.877 回答