Getting a foreign key into a form
Asked Answered
C

1

6

I'm new to Django and Python, and have spent a couple days trying to solve this problem. I've tried several approaches in other threads here, but I think I'm missing some basic concept because none of them have worked for me. Here's what I'm trying to do:

I'm using ModelForm, and I have created a form for adding records that includes a foreign key. I want this value to be set by default to match the record that was displayed on the page I linked from. [Code shown below edited to show suggested corrections].

Here's the relevant code from views.py:

def add_sighting(request):
unit = request.GET.get('unit')
form = SightingForm(request.POST or None, initial={'unit':unit})
if form.is_valid():
    sighting = form.save(commit=False)
    sighting.save()
    return redirect(index)
return render_to_response('trainapp/add_sighting_form.html',
                          {'unit': unit, 'sighting_form': form},
                          context_instance=RequestContext(request))

Here's the relevant code from add_sighting_form.html:

<form action="/trainapp/add_sighting/" method="post">
{% csrf_token %}
<table>
{{ sighting_form.as_table }}
</table>
<input type="submit" value="Save" />
</form>

Here's the relevant code from the template I linked from:

<p><a href="/trainapp/add_sighting/?unit={{ unit.id }}">Add sighting</a></p>
Cushiony answered 10/10, 2012 at 21:59 Comment(0)
W
4

Several approaches might work here.

The easiest one is using the initial parameter when creating an instance of the form before you pass it into the context of some view.

Say you are using a view method as follow:

def some_view( request ):
    id = request.GET.get( 'record-id' )
    # do check if id is valid...

    # load some record
    record = Record.objects.get( pk=id )

    # create a form instance
    form = RecordForm( initial={ 'some_key_field_name':record.id } )

    # set up context
    context = Context({
         'record' : record,
         'form' : form
    })

    # render the templateview using the above context
    # and return a HttpResponse ...

If you are using class based views instead, you might override get_context_data to get a similar result.

Class based views

Based on your code I also want to suggest you take a look at class based views in Django. The can handle getting and posting forms for you. It even takes care of creating the (default) form for you.

The equivalent of the posted code would be something like this:

class CreateSightingView( CreateView ):

    model = Sighting

    def get_context_data( self, **kwargs ):
        # call the super to get the default context
        data = super( CreateSightingView, self ).get_context_data( **kwargs )

        # add the initial value here
        # but first get the id from the request GET data
        id = self.request.GET.get( 'record-id' )
        # again: do some checking of id
        data.get( 'form' ).initial[ 'unit' ] = id

        return data
Windowlight answered 10/10, 2012 at 22:25 Comment(7)
I'm not sure if I've applied the concept correctly to my code (I've added it to my question above). When I click "Save" on the form, I'm getting the following error: "IntegrityError at /trainapp/add_sighting/", "trainapp_sighting.unit_id may not be NULL".Cushiony
Where exactly does the error occur? If it is on the line: form = SightingForm(request.POST or None, initial={'unit':unit.id}) then I would think that unit.id == null, which in turn would suggest that the pk of unit is not a field named id. Is that the case?Windowlight
I think this will set the initial value of the primary key to 1, correct? What I am trying to do is have the value set to match the page I linked from.Cushiony
Well, the code you showed before in your post effectively did the same. You got a unit with pk=1 and then passed that id to the form as initial data. I just showed you the method of setting the id in the form. I cannot tell you where to get the id from, since I don't know where I can find it. The easiest way to go would be to pass the id in the request for the form as a GET variable. That way you can get it as is shown above in the edited code. You can also pass it as a url kwarg; an example of an url kwarg is shown hereWindowlight
Thanks. I appreciate your help with this. I'll look around for information on how to pass the id in the request for the form as a GET variable. Is there additional information I could provide that would enable you to help with that step?Cushiony
Well, at some point you render the page that contains, as I presume, an url that links to the form page. As you render that url, presumably in a template, you can set the get variable by appending ?some-name=the-id to the url. Where you use the id of the item you are also rendering on that page. (I'm guessing a lot here, so I hope this helps you)Windowlight
Thanks again for your help. I've got it working now. One typo in your code worth noting: ( initial={ 'some_key_field_name'=record.id } ) should be ( initial={ 'some_key_field_name':record.id } ). I'll post the working code above.Cushiony

© 2022 - 2024 — McMap. All rights reserved.