Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Form Wizard to Edit Model

Tags:

python

django

I have a Django form wizard working nicely for creating content of one of my models. I want to use the same Wizard for editing data of existing content but can't find a good example of how to do this.

Here is a simplified version of my 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 there is this function https://docs.djangoproject.com/en/dev/ref/contrib/formtools/form-wizard/#django.contrib.formtools.wizard.views.WizardView.get_form_instance for setting the form instance, but I'm not sure how you would go about getting the models ID to do the look-up here and exactly how the code would work.

A code example or a link to one would be most appreciated.

Thanks, Pete

like image 382
pxg Avatar asked Dec 11 '12 15:12

pxg


People also ask

How do I edit a form in Django?

Create Formfrom . models import Post : load(import) Post Model that we'll add or edit the data via Form. class Meta: : write contents which we want to use via this Form. in here, we set we'll use Post Model in this form( model = Post ), and we'll use title and content fields( fields = ('title', 'content') ).

How do I link models and forms in Django?

models import User class InputUserInfo(forms. Form): phone = forms. CharField(max_length=20) instagram = forms. CharField(max_length=20) facebook = forms.

What is form Is_valid () in Django?

The is_valid() method is used to perform validation for each field of the form, it is defined in Django Form class. It returns True if data is valid and place all data into a cleaned_data attribute.

What is the difference between forms and model forms in Django?

The similarities are that they both generate sets of form inputs using widgets, and both validate data sent by the browser. The differences are that ModelForm gets its field definition from a specified model class, and also has methods that deal with saving of the underlying model to the database. Save this answer.


3 Answers

I've just got this working so will post the answer in case it helps someone else.

You can pass the ID of the item you'd like to edit in urls.py like this:

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

You can then look up the item with 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 a dict so you can set it as the initial data.

like image 169
pxg Avatar answered Nov 11 '22 18:11

pxg


pxg's answer is insufficient. As pointed out by emin-buğra-saral it creates a new instance of the model rather than editing it. And emin-buğra-saral's answer, by itself, isn't enough. Either don't override the get_form_initial method and don't set an initial_dict value or use the implementation provided in this answer. This is how you should combine their 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 pxg's version of get_form_initial would actually work (as long as you also add the get_form_instance override) it's not necessary to look up the instance, extract its data, and create an initial value dictionary. All this is done automatically by the ModelForm prior to initializing the instance from initial_dict. By simply returning an empty initial value dictionary you'll have simpler, more efficient code.

like image 25
nmgeek Avatar answered Nov 11 '22 17:11

nmgeek


Addition to pxg's answer, get_form_instance should be like this, otherwise you won't be editing the model but create a new instance of it:

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
like image 39
Emin Bugra Saral Avatar answered Nov 11 '22 17:11

Emin Bugra Saral