Django Create Wizard for Model Editing

I have a Django form wizard that works great for creating the contents of one of my models. I want to use the same Wizard to edit the data of existing content, but I can not find a good example of how to do this.

Here is a simplified version of the project code:

forms.py

class ProjectEssentialsForm(forms.ModelForm): class Meta: model = Project fields = [ 'title', 'short_description', 'who_description', 'problem_description', 'solution_description' ] class ProjectYourInfoForm(forms.ModelForm): class Meta: model = Project fields = [ 'gender', 'location', 'post_code', 'sector', ] 

views.py

 TEMPLATES = { 'project_essentials': 'projects/essentials-form.html', 'project_your_info': 'projects/your-info-form.html', } class ProjectWizard(SessionWizardView): instance = None def get_form_instance(self, step): """ Provides us with an instance of the Project Model to save on completion """ if self.instance is None: self.instance = Project() return self.instance def done(self, form_list, **kwargs): """ Save info to the DB """ project = self.instance project.save() def get_template_names(self): """ Custom templates for the different steps """ return [TEMPLATES[self.steps.current]] 

urls.py

 FORMS = [ ('project_essentials', ProjectEssentialsForm), ('project_your_info', ProjectYourInfoForm), ] urlpatterns = patterns('', (r'^projects/add$', ProjectWizard.as_view(FORMS)), ) 

I see that this function exists https://docs.djangoproject.com/en/dev/ref/contrib/formtools/form-wizard/#django.contrib.formtools.wizard.views.WizardView.get_form_instance to set the instance of the form, but I'm not sure how you are going to get the model identifier, look here and see exactly how the code will work.

Sample code or a link to it would be appreciated.

Thanks Pete

+7
source share
4 answers

I just got this job, so I will post the answer if it helps someone else.

You can pass the identifier of the element you want to change to urls.py, for example:

 (r'^projects/edit/(?P<project_id>[-\d]+)$', ProjectWizard.as_view(FORMS)), 

Then you can view the item with the following code in

views.py:

 class ProjectWizard(SessionWizardView): def get_form_initial(self, step): if 'project_id' in self.kwargs and step == 'project_essentials': project_id = self.kwargs['project_id'] project = Project.objects.get(id=project_id) from django.forms.models import model_to_dict project_dict = model_to_dict(project) return project_dict else: return self.initial_dict.get(step, {}) 

You need to convert the model to dict so that you can set it as source data.

+10
source

pxg answer is not enough. As noted by Emin-Bugra-Saral, he creates a new instance of the model, and does not edit it. And the answer of Emin-Bugra-Saral in itself is not enough. Either do not override the get_form_initial method and do not set the initial_dict value or use the implementation provided in this answer. Here's how you should combine your answers:

in urls.py:

(r'^projects/edit/(?P<project_id>[-\d]+)$', ProjectWizard.as_view(FORMS)),

in views.py:

 class ProjectWizard(SessionWizardView): def get_form_initial(self, step): if 'project_id' in self.kwargs: return {} return self.initial_dict.get(step, {}) def get_form_instance(self, step): if not self.instance: if 'project_id' in self.kwargs: project_id = self.kwargs['project_id'] self.instance = Project.objects.get(id=project_id) else: self.instance = Project() return self.instance 

While the version of get_form_initial on pxg actually works (as long as you also add an override of get_form_instance), there is no need to search for an instance, retrieve its data and create an initial value dictionary. All this is done automatically by ModelForm until the instance is initialized from initial_dict. Just returning an empty dictionary of initial value, you get a simpler and more efficient code.

+2
source

The addition to the answer pxg, get_form_instance should be like this, otherwise you will not edit the model, but create a new instance:

 def get_form_instance(self, step): if not self.instance: if 'initial_id' in self.kwargs: initial_id = self.kwargs['initial_id'] self.instance = Project.objects.get(id=initial_id) else: self.instance = Project() return self.instance 
+1
source

I had to modify this a bit to get it working in Django 1.11 with django-formtools 2.1.

 class ProjectWizard(SessionWizardView): def get_form_initial(self, step): if 'project_id' in self.kwargs: return {} return self.initial_dict.get(step, {}) def get_form_instance(self, step): if not self.instance_dict: if 'project_id' in self.kwargs: project_id = self.kwargs['project_id'] return Project.objects.get(id=project_id) return None 

The get_form_instance method get_form_instance expects an object or None to be returned .

0
source

All Articles