我正在尝试将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_type
和object_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()
答案 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))