3

I have a complex django object, which has properties of other class types. This gets like this:

class Order:
   contractor - type Person
   some other fields....

In my form I'd like to be able to either choose existing Person object from the dropdown or add a new one with a form. I've managed to create forms and appropriate workflow, but the problem is with saving the Order itself, I simply can't get the id of a saved Person instance. I'm doing sth like this:

def make_order(request):
  if request.method == 'POST':
    parameters = copy.copy(request.POST)
    contractor_form = ContractorForm(parameters)
    if contractor_form.is_valid():
      contractor_form.save()
      parameters['contractor'] = ???
    form = OrderForm(parameters)
    if form.is_valid():
      form.save() 
      return HttpResponseRedirect('/orders/')
  else:
    form = OrderForm()
    contractor_form = ContractorForm()

  return render_to_response('orders/make_order.html', {'order_form' : form, 'contractor_form' : contractor_form})

So, if POST request reaches this method I first check if ContractorForm have been filled - I assume that if the form is valid, it is meant to be used. If yes, than I save it and would like to assign the saved object's database id to appropriate field for OrderForm to find it.

All my forms are ModelForms.

The questions are:

  1. Are there better ways to do this? (choose from dropdown or add in place) - better or more pythonic ;-)
  2. How can I get saved objects id when using ModelForms?

Edited

My ContractorForm is:

class ContractorForm(ModelForm):
  class Meta:
    model = Contractor

Nothing fancy.

Marcin Cylke
  • 2,100
  • 2
  • 21
  • 40
  • 2
    On a side note, use reverse (http://docs.djangoproject.com/en/dev/topics/http/urls/#reverse) instead of referencing the '/orders/' url directly in your `HttpResponseRedirect`... it'll save you tons of headaches in the future, trust me :) – Sam Dolan Sep 06 '10 at 22:42
  • Ha! You're right, I should've done that earlier. – Marcin Cylke Sep 07 '10 at 04:51

1 Answers1

8

save() should return the newly created instance.

if contractor_form.is_valid():
  instance = contractor_form.save()
  parameters['contractor'] = instance

where id would be instance.id, or even better instance.pk.

pk vs. id:

Regardless of whether you define a primary key field yourself, or let Django supply one for you, each model will have a property called pk. It behaves like a normal attribute on the model, but is actually an alias for whichever attribute is the primary key field for the model. You can read and set this value, just as you would for any other attribute, and it will update the correct field in the model.

Follow-up on comment:

Well it does work by default, so there must be something else wrong.

models.py

class Category(models.Model):
    name = models.CharField(max_length=70)
    slug = models.SlugField()

forms.py

from django import forms
from models import Category

class MyModelForm(forms.ModelForm):
    class Meta:
        model = Category

Test in shell:

In [3]: from katalog.forms import MyModelForm
In [4]: data = {'name':'Test', 'slug':'test'}
In [5]: form = MyModelForm(data)
In [6]: instance = form.save()
In [7]: instance
Out[7]: <Category: Test>
In [8]: instance.id
Out[8]: 5L
Community
  • 1
  • 1
Davor Lucic
  • 28,970
  • 8
  • 66
  • 76
  • This was my first guess, but unfortunately it doesn't work like this. ModelForm.save() returns None. There should be a way of doing this with overloaded save() method, but this seems overcomplicated and messy. – Marcin Cylke Sep 07 '10 at 04:50
  • Well, I've tested this again, and your solution works. I'll however test it more thoroughly with my specific case. – Marcin Cylke Sep 07 '10 at 19:51