django 禁止保存()以防止由于未保存相关对象而导致数据丢失

ufj5ltwl  于 2023-10-21  发布在  Go
关注(0)|答案(5)|浏览(129)

我需要从一个新创建的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()

从文档中可以看出,这是在较新的Django版本> 1.8.3中发生的事情。
p3 =地点(名称='恶魔犬',地址='944 W. Fullerton ')Restaurant.objects.create(place=p3,serves_hot_dogs=True,serves_pizza=False)
回溯(最近的呼叫最后一次):
...
ValueError:禁止保存()以防止由于未保存的相关对象“place”而导致数据丢失。
下面是我从视图中获取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')
edqdpe6u

edqdpe6u1#

这很简单:

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
)
fbcarpbf

fbcarpbf2#

这是在Django 1.8中引入的。以前,您可以将未保存的示例分配给One-To-One关系,如果失败,则会自动跳过。从Django 1.8开始,在这种情况下你会得到错误消息。查看Django 1.7 -> 1.8升级的文档。
上面写着:
将未保存的对象复制到ForeignKey、GenericForeignKey和OneToOneField现在会引发ValueError。
如果您对更多细节感兴趣,可以在django.db.models.base中检查save方法:其中的一部分:

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
            )

最后5行是引发此错误的位置。基本上你的相关的obj没有保存会有obj.pk == NoneValueError会被提升。

qq24tv8q

qq24tv8q3#

Answer-问题源于django不保存空的或未更改的表单。这导致那些未保存的表单上出现空字段。问题已通过允许外键上的空字段得到修复,事实上--所有字段。这样,空的或未更改的表单在保存时不会返回任何错误。

**FYI:**请参阅@wolendranh回答。

xtfmy6hx

xtfmy6hx4#

我只是删除了我的model.save()和错误消失了。
只有当您在没有更改的情况下保存它时,此操作才有效。否则,如果您更改了查询集中的某些内容,则应该保存一次。
一个例子:

  • 查看.py*
queryset = myModel.objects.get(name="someName", value=4)

queryset.value = 5
# here you need to save it, if you want to keep the changes.
queryset.save()
...

# If you save it again, without any changes, for me I got the error save() prohibited to prevent data loss due to unsaved related object

# don't save it again, unless you have changes.
# queryset.save()
sc4hvdpw

sc4hvdpw5#

save在很多情况下都可以工作,但是在某些情况下,如果稍后由于某些错误而导致另一个对象保存失败,则不希望保存一个对象。基本上,您希望回滚更改。如果您不正确处理这种情况,您可能最终会有损坏的数据。
Django已经提供了原子事务API来处理这种情况。将所有模型更改封装在一个函数中,并将其 Package 在原子事务中。

相关问题