Opened 6 years ago

Closed 6 years ago

Last modified 5 years ago

#12392 closed (wontfix)

Create_object generic view does not provide a way to pre-populate a form with dynamic data

Reported by: stewart.matheson@… Owned by: nobody
Component: Generic views Version: master
Severity: Keywords: pre-populate, generic, view, dictionary
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

To my knowledge which may be limited there is no simple way to pre-populate a form that is being used in a generic view for creating an object. It would be fantastic to be able to pass a dictionary of values to to create object method so that when the form is rendered this dictionary of values gets pre-populated in the form.

I apologise if this is an erroneous ticket. My experience with Django is limited however I have spent a lot of time reading the documentation and reading through the Django source code without having found any simple way of doing this.

Change History (8)

comment:1 Changed 6 years ago by Stewart <stew@…>

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Version changed from 1.1 to SVN

comment:2 Changed 6 years ago by oyvind

May be related to #6735

comment:3 Changed 6 years ago by Stewart <stew@…>

A class-based approach would definitely work. To me it seems like a more sensible way of tackling generic views. However #6735 seems to specifically relate to list views where is this issue focuses around the create and update generic views. In a class-based approach ideally this could take an instance of the ModelForm. That way you could perform any operations on the instance that are needed such as binding data. That would definitely solve the issue and make generic views much simpler for displaying forms with pre-populated data.

comment:4 Changed 6 years ago by lukeplant

  • Resolution set to wontfix
  • Status changed from new to closed

Pass in your own form class which implements __init__ to provide the 'initial' keyword argument:

from django.forms import ModelForm
from myapp.models import MyModel

class MyModelForm(ModelForm):
    class Meta:
        model = MyModel

    def __init__(self, *args, **kwargs):
        kwargs['initial'] = {'field1':'val1'}
        return super(MyModelForm, self).__init__(*args, **kwargs)

Then pass MyModelForm as the form_class argument.

I didn't try this, but I'm fairly sure the basic approach should work. Since it is fairly simple and avoids cluttering the generic view interface, I'm closing WONTFIX.

comment:5 Changed 6 years ago by Stewart <stew@…>

Doesn't this solution assume I already know the values? What if I need to assign the values dynamically say from a GET parameter? There is no mechanism to do this. Or am I misunderstanding your solution?

comment:6 Changed 6 years ago by Stewart <stew@…>

  • Resolution wontfix deleted
  • Status changed from closed to reopened
  • Summary changed from Create_object generic view does not provide a way to pre-populate a form to Create_object generic view does not provide a way to pre-populate a form with dynamic data

comment:7 Changed 6 years ago by lukeplant

  • Resolution set to wontfix
  • Status changed from reopened to closed

If you need the values to be dynamic based on the request object (which you didn't mention before) you can do it by creating the model form in a function that wraps the create_object view:

from django.forms import ModelForm
from myapp.models import MyModel

def my_view(request):

    class MyModelForm(ModelForm):
        class Meta:
            model = MyModel
   
        def __init__(self, *args, **kwargs):
            kwargs['initial'] = {'field1': request.GET.get('field1','')}
            return super(MyModelForm, self).__init__(*args, **kwargs)

    return create_object(request, form_class=MyModelForm)

(If you haven't seen this before, it's called a closure - MyModelForm.__init__ is using the request object, which hasn't been passed in to that method, but is available because it is in the enclosing scope in which MyModelForm.__init__ is defined. For each call to my_view, a class called MyModelForm is created, and thrown away afterwards.)

If you need to get values out of the request, you have to do this in a view function that wraps create_object i.e. you cannot do it in the URL conf. Unless, of course, we added a keyword argument to create_object that is a callable that takes a request object and returns some values to be passed to the form as 'initial', but this is only highlighting that we are at the stage of very custom requirements that are best catered for either by writing your own view completely or using something like the code above. I'll admit that this isn't 'simple', but I wouldn't describe your actual requirements as that simple either, and since there are so many ways in which generic views could be customised we have to limit new options to things that cannot be done in other ways (at least until class based generic views arrive).

comment:8 Changed 5 years ago by bjourne

I came here from google because I had the same problem and I want to second stewart's idea. An "initial" argument on the create_object view to send to the form class' constructor would be really great.

Note: See TracTickets for help on using tickets.
Back to Top