Django GenericForeignKey更新

时间:2018-08-03 10:17:44

标签: django django-migrations generic-foreign-key

我正在尝试将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()

2 个答案:

答案 0 :(得分:1)

没有理由在此处使用过滤器和更新。您已经有了对象。

for comment in comments:
    comment.content_object = comment.post
    comment.save()

答案 1 :(得分:0)

我在迁移中更新通用外键时遇到问题。如果我尝试直接将键设置为对象,则它不会在保存时设置任何内容(因为它无法识别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))