Python 禁止save(),防止相关对象未保存导致数据丢失

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33838433/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 14:05:22  来源:igfitidea点击:

save() prohibited to prevent data loss due to unsaved related object

pythondjango

提问by Edwinner

I need to pass a primary key from a newly created ModelFormto another form field in the same view but I get an error. Any suggestions to make this work? It looks like in the past, this would be the answer:

我需要将新创建的主键传递ModelForm到同一视图中的另一个表单字段,但出现错误。有什么建议可以使这项工作?在过去,这将是答案:

def contact_create(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse(contact_details, args=(form.pk,)))
    else:
        form = ContactForm()

From the documentation, this is what is happening in the newer Django version > 1.8.3

从文档中,这是在较新的 Django 版本中发生的事情 > 1.8.3

p3 = Place(name='Demon Dogs', address='944 W. Fullerton') Restaurant.objects.create(place=p3, serves_hot_dogs=True, serves_pizza=False)
Traceback (most recent call last):
...
ValueError: save() prohibited to prevent data loss due to unsaved related object 'place'.

p3 = Place(name='Demon Dogs', address='944 W. Fullerton') Restaurant.objects.create(place=p3, services_hot_dogs=True, services_pizza=False)
Traceback(最近一次通话):
...
ValueError : 禁止 save() 以防止由于未保存的相关对象“位置”而导致数据丢失。

This is how I am getting my pkfrom the view:

这就是我pk从视图中获取的方式:

my_id = ""
if form.is_valid():
    # deal with form first to get id
    model_instance = form.save(commit=False)
    model_instance.pub_date= timezone.now()
    model_instance.user= current_user.id
    model_instance.save()
    my_id = model_instance.pk

if hourformset.is_valid():
    hourformset.save(commit=False)
    for product in hourformset:
        if product.is_valid():
            product.save(commit=False)
            product.company =  my_id
            product.save()
else:
    print(" modelform not saved")
return HttpResponseRedirect('/bizprofile/success')

采纳答案by wolendranh

This was introduced in Django 1.8. Previously you could assign not saved instance to One-To-One relation and in case of fail it was silently skipped. Starting from Django 1.8 you will get error message in this case. Check a documentationof Django 1.7 -> 1.8 upgrade.

这是在 Django 1.8 中引入的。以前,您可以将未保存的实例分配给一对一关系,如果失败,它会被悄悄跳过。从 Django 1.8 开始,您将在这种情况下收到错误消息。检查Django 1.7 -> 1.8 升级的文档

It says:

它说:

Assigning unsaved objects to a ForeignKey, GenericForeignKey, and OneToOneField now raises a ValueError.

将未保存的对象分配给 ForeignKey、GenericForeignKey 和 OneToOneField 现在会引发 ValueError。

If you are interested in more details, you can check savemethod in django.db.models.base: Some part of it:

如果您对更多详细信息感兴趣,可以savedjango.db.models.base以下部分查看方法:

for field in self._meta.concrete_fields:
    if field.is_relation:
        # If the related field isn't cached, then an instance hasn't
        # been assigned and there's no need to worry about this check.
        try:
            getattr(self, field.get_cache_name())
        except AttributeError:
            continue
        obj = getattr(self, field.name, None)
        # A pk may have been assigned manually to a model instance not
        # saved to the database (or auto-generated in a case like
        # UUIDField), but we allow the save to proceed and rely on the
        # database to raise an IntegrityError if applicable. If
        # constraints aren't supported by the database, there's the
        # unavoidable risk of data corruption.
        if obj and obj.pk is None:
            raise ValueError(
                "save() prohibited to prevent data loss due to "
                "unsaved related object '%s'." % field.name
            )

Last 5 rows are where this error is raised. basically your related objwhich is not saved will have obj.pk == Noneand ValueErrorwill be raised.

最后 5 行是引发此错误的地方。基本上你相关的obj未保存会obj.pk == NoneValueError将提高。

回答by doniyor

it is simple:

很简单:

p3 = Place(name='Demon Dogs', address='944 W. Fullerton')   
p3.save() # <--- you need to save the instance first, and then assign
Restaurant.objects.create(
    place=p3, serves_hot_dogs=True, serves_pizza=False
) 

回答by Edwinner

Answered - The problem arose from django not saving empty or unchanged forms. This led to null fields on those unsaved forms. Problem was fixed by allowing null fields on foreign keys, as a matter of fact -- all fields. That way, empty or unchanged forms did not return any errors on save.

回答 - 问题源于 django 没有保存空的或未更改的表单。这导致那些未保存的表单上的字段为空。问题是通过允许外键上的空字段来解决的,事实上 - 所有字段。这样,空的或未更改的表单在保存时不会返回任何错误。

FYI:Refer to @wolendranh answer.

仅供参考:请参阅@wolendranh 的答案。