Django-通过预先填充表单和相应的内联表单集,基于另一个对象创建一个新对象
我想为用户提供基于现有出版物创建新出版物的可能性。为此,我希望他们单击指向“basedview”的链接,该链接包含他们希望新项目基于的出版物的id。包括两个用于n:n关系的表单集 这将打开一个预填充的表单,其中所有字段都以它所基于的发布中的数据为前缀。一旦用户根据需要进行了更改,它应该为字段集保存一个新的发布和新的关系——后者是其中的难点 所以我的问题是-如何从数据库中加载所有相应的表单集,然后删除它们的所有pk,但仍然保持与发布项的关系 现在在get方法中是这样的:Django-通过预先填充表单和相应的内联表单集,基于另一个对象创建一个新对象,django,django-forms,django-crispy-forms,formsets,Django,Django Forms,Django Crispy Forms,Formsets,我想为用户提供基于现有出版物创建新出版物的可能性。为此,我希望他们单击指向“basedview”的链接,该链接包含他们希望新项目基于的出版物的id。包括两个用于n:n关系的表单集 这将打开一个预填充的表单,其中所有字段都以它所基于的发布中的数据为前缀。一旦用户根据需要进行了更改,它应该为字段集保存一个新的发布和新的关系——后者是其中的难点 所以我的问题是-如何从数据库中加载所有相应的表单集,然后删除它们的所有pk,但仍然保持与发布项的关系 现在在get方法中是这样的: self.
self.object = None
try:
self.object = KombiPublikation.objects.get(pk=self.kwargs['pk'])
except ObjectDoesNotExist:
raise Http404("Keinen Output unter dieser PubID gefunden.")
form = KombiPublikationForm(instance=self.object)
pubspr_formset = KombiPublikationSpracheFormset(instance=self.object)
pubpers_formset = KombiPublikationPersonFormset(instance=self.object)
但这最终只是对现有出版物的编辑。我必须在填充表单集后删除pk,或者找到一种不同的填充表单集的方法。有什么想法吗
多谢各位
下面是完整的代码摘录:
class PublikationBasedView(PublikationCreateView):
def get(self, request, *args, **kwargs):
self.object = None
try:
self.object = KombiPublikation.objects.get(pk=self.kwargs['pk'])
except ObjectDoesNotExist:
raise Http404("Keinen Output unter dieser PubID gefunden.")
#todo: delete the pk of all objects in forms in formset, else they stay the same and are also changed!!
#fix: delete pk in objekt in order to save it as a new objekt - else based does not work at all!
#self.object.pk=None
form = KombiPublikationForm(instance=self.object)
pubspr_formset = KombiPublikationSpracheFormset(instance=self.object)
pubpers_formset = KombiPublikationPersonFormset(instance=self.object)
return self.render_to_response(
self.get_context_data(
form=form,
pubspr_formset=pubspr_formset,
pubpers_formset=pubpers_formset,
)
)
#its based on this create view
class PublikationCreateView(LoginRequiredMixin, ShowNumberOfItems, CreateView):
form_class = KombiPublikationForm
template_name = 'output/pub_create.html'
model = KombiPublikation
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
pubspr_formset = KombiPublikationSpracheFormset()
pubpers_formset = KombiPublikationPersonFormset()
return self.render_to_response(
self.get_context_data(
form=form,
pubspr_formset=pubspr_formset,
pubpers_formset=pubpers_formset
)
)
def post(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
pubspr_formset = KombiPublikationSpracheFormset(self.request.POST)
pubpers_formset = KombiPublikationPersonFormset(self.request.POST)
if form.is_valid() and pubspr_formset.is_valid() and pubpers_formset.is_valid():
return self.form_valid(form, pubspr_formset, pubpers_formset)
else:
return self.form_invalid(form, pubspr_formset, pubpers_formset)
def get_success_msg(self):
return 'Ihr Output wurde erfolgreich unter PubID {} angelegt. Speicherort: {}. <br>'.format(self.object.pk, self.object.status)
def form_valid(self, form, pubspr_formset, pubpers_formset):
""" Called if all forms are valid."""
self.object = form.save()
pubspr_formset.instance = self.object
pubspr_formset.save()
pubpers_formset.instance = self.object
pubpers_formset.save()
messages.success(self.request, self.get_success_msg())
return redirect(self.get_success_url())
def form_invalid(self, form, pubspr_formset, pubpers_formset):
""" Called if whether a form is invalid. Re-renders data-filled forms and errors."""
return self.render_to_response(
self.get_context_data(
form=form,
pubspr_formset=pubspr_formset,
pubpers_formset=pubpers_formset,
))
类PublikationBasedView(PublikationCreateView):
def get(自我、请求、*args、**kwargs):
self.object=None
尝试:
self.object=kombipublication.objects.get(pk=self.kwargs['pk'])
除ObjectDoesNotExist外:
提高Http404(“在公共基金上的基宁输出”)
#todo:删除formset中表单中所有对象的主键,否则它们将保持不变,并且也会更改!!
#修正:删除ObjeT中的pk以将其保存为新的ObjeT-基于else的根本不起作用!
#self.object.pk=None
表单=KombiPublicationForm(实例=self.object)
pubspr_formset=kombipublicationspracheformset(实例=self.object)
pubpers_formset=KombiPublicationPersonFormSet(实例=self.object)
返回self.render\u to\u响应(
self.get\u上下文\u数据(
形式=形式,
pubspr_formset=pubspr_formset,
pubpers_formset=pubpers_formset,
)
)
#它基于此创建视图
类PublikationCreateView(LoginRequiredMixin、ShowNumberOfItems、CreateView):
form_class=KombiPublicationForm
模板名称='output/pub\u create.html'
模型=Kombipublication
def get(自我、请求、*args、**kwargs):
self.object=None
form\u class=self.get\u form\u class()
表单=自我。获取表单(表单类)
pubspr_formset=KombiPublicationsPracheFormSet()
pubpers_formset=KombiPublicationPersonFormSet()
返回self.render\u to\u响应(
self.get\u上下文\u数据(
形式=形式,
pubspr_formset=pubspr_formset,
pubpers\u formset=pubpers\u formset
)
)
def post(自我、请求、*args、**kwargs):
self.object=None
form\u class=self.get\u form\u class()
表单=自我。获取表单(表单类)
pubspr_formset=kombipublicationspracheformset(self.request.POST)
pubpers_formset=KombiPublicationPersonFormset(self.request.POST)
如果form.is\u valid()和pubspr\u formset.is\u valid()和pubpers\u formset.is\u valid():
返回self.form\u valid(form、pubspr\u formset、pubpers\u formset)
其他:
返回self.form\u无效(form,pubspr\u formset,pubpers\u formset)
def获取成功消息(自我):
返回'Ihr Output wurde erfolgreich unter PubID{}angelegt。Speicherort:{}
'.format(self.object.pk、self.object.status)
def form_valid(self、form、pubspr_formset、pubpers_formset):
“”“如果所有表单都有效,则调用。”“”
self.object=form.save()
pubspr_formset.instance=self.object
pubspr_formset.save()
pubbers_formset.instance=self.object
pubbers_formset.save()文件
messages.success(self.request、self.get\u success\u msg())
返回重定向(self.get\u success\u url())
def form_无效(self、form、pubspr_formset、pubpers_formset):
“”“如果表单无效,则调用。重新呈现数据填充的表单和错误。”“”
返回self.render\u to\u响应(
self.get\u上下文\u数据(
形式=形式,
pubspr_formset=pubspr_formset,
pubpers_formset=pubpers_formset,
))
设置表单的实例后,它将绑定到该对象。所有更新都将更新到您传递的对象
相反,你需要
使用initial在运行时声明表单字段的初始值。例如,您可能希望用当前会话的用户名填写用户名字段
还有一个实用程序,它将为您提供初始值所需的dict:
返回包含实例
中的数据的dict,该dict适合作为表单的初始
关键字参数传递
因此,您需要执行以下操作:
from django.forms.models import model_to_dict
object = # Your code here...
# You don't want `id`. Possibly others...?
initial_data = model_to_dict(object, exclude=['id'])
form = YourFormClass(initial=initial_data)
# ...
希望这能有所帮助 我解决了这个问题,因为它比预期的要复杂一些,所以我在这里分享我的发现-如果有人找到一个更简单的解决方案,请随意添加其他评论
这是视图中的最终get方法:
def get(self, request, *args, **kwargs):
self.object = None
try:
self.object = KombiPublikation.objects.get(pk=self.kwargs['pk'])
except ObjectDoesNotExist:
raise Http404("Keinen Output unter dieser PubID gefunden.")
#load all form initials and render the form correctly - but save new objects
#1. make sure the main publikation object is saved as a new object:
self.object.pk = None
self.object.erstellungsdatum = datetime.now()
form = KombiPublikationForm(instance=self.object)
#2. get the corresponding querysets for sprache and person:
pubspr = KombiPublikationSprache.objects.filter(publikation=self.kwargs['pk'])
pubpers = KombiPublikationPerson.objects.filter(publikation=self.kwargs['pk'])
#make a list of dicts out of the querysets and delete pk id and fk relations
pubspr_listofdicts = []
for pubspr in pubspr:
pubspr_dict= model_to_dict(pubspr)
del pubspr_dict['id']
del pubspr_dict['publikation']
pubspr_listofdicts.append(pubspr_dict)
pubpers_listofdicts = []
for pubpers in pubpers:
pubpers_dict=model_to_dict(pubpers)
del pubpers_dict['id']
del pubpers_dict['publikation']
pubpers_listofdicts.append(pubpers_dict)
#create new formsets with the right amount of forms (leng(obj_listofdicts)
KombiPublikationSpracheFormset = inlineformset_factory(KombiPublikation,
KombiPublikationSprache,
form=KombiPublikationSpracheForm,
extra=len(pubspr_listofdicts),
can_delete=True,
can_order=True,
min_num=1,
validate_min=True)
KombiPublikationPersonFormset = inlineformset_factory(
KombiPublikation,
KombiPublikationPerson,
form=KombiPublikationPersonForm,
extra=len(pubpers_listofdicts),
can_delete=True,
can_order=True,
min_num=0,
validate_min=True)
#initiate the formset with initial data:
pubspr_formset = KombiPublikationSpracheFormset(instance=self.object, initial=pubspr_listofdicts)
pubpers_formset = KombiPublikationPersonFormset(instance=self.object, initial=pubpers_listofdicts)
return self.render_to_response(
self.get_context_data(
form=form,
pubspr_formset=pubspr_formset,
pubpers_formset=pubpers_formset,
)
)
你好,我想这是正确的方法。问题在于,它没有在重新设计的表单中设置外键值。除了外键,所有东西都在那里,即使它们作为值存在于dict中。知道他们为什么不出现在表格里吗?嗯。。。这可能是因为您的字段是ModelChoiceFields或类似的字段,而model_to_dict中的数据格式不正确。您需要对其进行实验和调整。我尝试加载fk对象,并用相应的对象替换dict中的值。但仍然-外键值未显示在呈现形式中…:(