0

I want to create an edit form for a single field in my model, where the textarea is prefilled with the current value for that field. However, the exact field name is not hardwired, and I want it to be specified by the url.

My model is called Topic. Two example fields are Notes and Objectives. I can hardwire the field value as in the following:

urls.py

(r'^/(?P<topicshortname>\d+)/(?P<whichcolumn>[^/]+)/edit/$', 'mysyte.myapp.views.edit_topic_text'),

views.py

def edit_topic_text(topicshortname, whichcolumn):
    thetopic = Topic.objects.get(topic__shortname__iexact = topicshortname)
    content =  Topic.objects.get(topic__shortname__iexact = topicshortname).objective
    return render_to_response('topic_text_edit.html', locals())

topic_text_edit.html

<form method="post" action="../save/">
    <textarea name="content" rows="20" cols="60">{{ content }}</textarea>
    <br>
    <input type="submit" value="Save"/>
</form>

I can also do the hardwiring in the template by using {{ thetopic.objective }}, but if I visited http://mysite.com/topic/Notes/edit/ both of these would prepopulate the form with the objective value, not the notes value.

Can I use the 'whichcolumn' url argument to specify which field to update in the object?

nimasmi
  • 3,978
  • 1
  • 25
  • 41

2 Answers2

1

You can use getattr to get the value of an attribute by name. For your example:

def edit_topic_text(topicshortname, whichcolumn):
    thetopic = Topic.objects.get(topic__shortname__iexact = topicshortname)
    content =  getattr(thetopic, whichcolumn)
    return render_to_response('topic_text_edit.html', locals())

However, you should be also aware of the security implications of this. Users will be able to edit any field on the model they like by changing the url. You should either check the value of whichcolumn before doing anything else with that data, or limit the possibilities in the urlconf with a more specific regular expression, eg:

(r'^/(?P<topicshortname>\d+)/(?P<whichcolumn>(Notes|Objectives))/edit/$', 'mysyte.myapp.views.edit_topic_text'),

You also mentioned fields 'Notes' and 'Objectives' but are accessing the field 'objective', so you may need to map the values of whichcolumn to the field name you are interested in, eg:

(r'^/(?P<topicshortname>\d+)/Objectives/edit/$', 'mysyte.myapp.views.edit_topic_text', {'whichcolumn': 'objective'}),
(r'^/(?P<topicshortname>\d+)/Notes/edit/$', 'mysyte.myapp.views.edit_topic_text', {'whichcolumn': 'note'}),

Another thing you should be aware of is that you where accessing the database twice by calling Topic.objects.get(...) twice. You should reuse the value of thetopic.

Michał Modzelewski
  • 1,320
  • 10
  • 8
  • That worked well for prepopulating the textarea. Thank you. I had read about and tried to fudge getattr(), but hadn't worked out the right syntax. Unfortunately my save url still doesn't work - I'm struggling to fit the getattr() into the save function, as it's still hardwired as `thetopic.objective = content`. Thanks for the security advice, I'll implement that. Comment also noted about accessing the database twice, thanks. 'Objectives' (plural) was a typo in my post. – nimasmi Jul 01 '11 at 13:32
  • Update: done it with `setattr(object, field, value)`, thanks to http://stackoverflow.com/questions/763558/django-object-get-set-field – nimasmi Jul 01 '11 at 14:18
0

you should separate the two concepts of Notes and Objectives in two different classes, then use them in your Topic main class as reference

it would be easier for you to retrieve your object type and populate the correct one

Samuele Mattiuzzo
  • 10,760
  • 5
  • 39
  • 63