I want to offer users the possibility to create a new publication based on an existing publication. To do that, I want them to click a link to "basedview" that contains the id of the publication they want the new item to base on. There are two formsets for n:n relations included.
that should open a prefilled form with all fields prefield with the data from the publication it's based on. once the user has made changes as needed, it should then save a new publication and new relations for the fieldset - the latter being the difficult part of it.
So my question is - how can I load all corresponding formsets from the database and then delete all their pk but still keep the relation to the publication item?
Right now it is like this in the get method:
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)
But that ends up to be just an edit of the existing publication. I somehow have to delete the pk after I populated the formset or find a way to populate the formset differently. Any Ideas?
Thank you very much!
Here the full code excerpt:
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,
))
I solved the problem and since it was a bit more complicated then expected, I share my finding here - if someone finds a simpler solution feel free to add another comment
That is the final get method in the view:
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,
)
)