Hi Robert,
On 18/01/07, Robert <[EMAIL PROTECTED]> wrote:
I know newforms are still in development, but maybe there are known
practiced on
how to manage custom Form.
Let's say there's a model:
ITEM_TYPE_CHOICES = (
('new','new'),
('used','used')
)
class Item(models.Model):
owner = models.ForeignKey(Users) (maybe this should not be here
so it's not displayed at all?)
name = models.CharField(blank=False, maxlength="20")
type = models.CharField(maxlength="4", blank=False)
Here's the class Form:
class AddEditItemForm(forms.Form):
owner = ChoiceField(choices=[('','-------')]+[(o.id,o.email) for
o in User.objects.all()])
name = CharField()
type = CharField()
(I have ommited maxlength etc. for simplicity).
How shold the create/update view look like?
I would like to use {{ form.owner }} , {{ form.name }} in my template.
If you just want form.owner and form.name then you can drop 'type'
from the form definition.
Some are using:
def create_edit_item(request, object_id):
if object_id is None:
item = Item.objects.get(id=object_id)
ItemForm = AddEditForm(initial=item.__dict__)
else:
ItemForm = AddEditForm()
problem 1: item.__dict__ returns a dict with: owner_id value instaed of
owner, initial won't work then
if using owner_id in the AddEditForm() it looks messy in the template
(name=id_owner_id). I know form_for_instance produces form with
"owner" field name, not owner_id.
using item.__dict__ will not work properly for ForeignKeys and M2M
fields. It's better to pass the instance into the Form and do the
magic yourself (see below for an example).
I know there are some problems with form_for_model.save() yet.. and
that I have to manipulate form.clean_data and use object.save()
instaed, but how should my view If I want just edit name & type so that
the user
won't be asked to enter / won't be able to POST "owner" value.
To do this I'd leave the owner field out of the form, define a save
method for your form (which will return an appropriate instance) and
then update the instance with request.user or whatever.
Can anybody please explain how should my add/edit view & form look like
assuming the newly created item owner
gets the request.user & that when editing this can't be changed by
anyone?
To ensure that no-one can change the owner field make sure you set the
value yourself in the view and ignore anything passed in by the user.
Or maybe I can use form_for_instance, but I have no idea how can I "cut
off" some fields so they are not
in this form. That's just a thought.
I've considered the example from:
http://groups.google.com/group/django-users/browse_frm/thread/d9e03cf29739869f/71c60c65387802bc?lnk=gst&q=newforms&rnum=8#71c60c65387802bc
but I'd rather avoid using hiddenfields. Also I need to use {{
form.name }} instead of {{ form }}.
Right. Below I've inserted a little write up I've been working on.
What I've described works for me. YMMV. (I'd appreciate comments if
anyone has any).
Django Newforms
===============
Binding a form to a model instance
----------------------------------
Django's newforms module provides the helper method
'form_for_instance'. The method will return a Form similar to the one
returned by form_for_model but the initial data will be populated by
the instance's data. The form will have a 'save' method which will
save changes to the instance to the database (unless it is passed the
commit=False argument) and will return the instance itself.
Sometimes, however, it is desirable to use fields different from the
default. In order to bind a form to an instance one will have to
provide __init__ and save methods.
The __init__ method should be defined as follows:
def __init__(self, data=None, auto_id='id_%s', prefix=None,
initial=None, instance=None):
if instance is not None:
self.instance = instance
new_data = {}
# Populate new_data using 'instance'
# ...
data = new_data
else:
self.instance = None
super(MyForm, self).__init__(data, auto_id, prefix, initial)
The __init__ method will save the original instance in self.instance
and pass the data it contains to the superclass (most likely
forms.Form). The bound form will be created with
MyForm(instance=MyInstance). To use the form for creating new
instances it can be created with MyForm(request.POST).
The save method will look similar to the following:
def save(self, commit=True):
if self.instance is not None:
instance = self.instance
else:
instance = InstanceModel()
# Construct the instance below using self.clean_data
# Using self.clean_data ensures everything is validated.
# ...
if commit:
instance.save()
return instance
It should be noted that one will not be able to save ManyToMany data
without saving the instance first. If the model contains M2M fields
then commit=False will not make any sense.
Views
-----
Your add+edit view should look something like the following:
def add_edit_model(request, id=None):
if id is not None:
instance = MyModel.objects.get(id=id)
InstanceForm = MyForm(instance=instance)
else:
InstanceForm = MyForm()
if request.POST:
form = InstanceForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/whatever/url/')
return render_to_response('template.html', {'form': InstanceForm})
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Django
users" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---