I have a couple of forms, one is created from as a ModelForm and the other is a simple Form. Both of them are used in a request.POST, and to obtain the information from them I am using to different methods:
For the ModelForm form, I do this:
form = ApplicantForm(request.POST)
if form.is_valid():
applicant = form.save(commit=False)
applicant.confirmation_code = '999999'
applicant.save()
For the simple form, I am using:
form = ConfirmationCode(request.POST)
code = request.POST['confirmation_code']
confirmation_id=request.POST['confirmation_id']
As you can see, to access the information in the first form I am using the "form.save.ANYFIELD", and for the second one I am using "request.POST['ANYFIELD']. Is it possible to access the the information in the first form using the request.POST methods even if it hasnt been saved? Which is better?
You can try like this for modelform:
form = ApplicantForm(request.POST)
if form.is_valid():
app_code= form.cleaned_data['confirmation_code'] #assuming confirmation_code is a field in your modelform
.....
You seem a bit confused about what saving is doing in a modelform. When you call form.save(), you're creating a new instance of the model the form is associated with, and (unless you specify commit=False) saving that data to the database. Because you have an instance, you can use any of the normal model instance methods and access patterns.
If you want to use a form without an associated model, you can't call save - because there's nothing to save, and no model to create an instance of - but you should access the data via the form.cleaned_data dictionary after you call form.is_valid(). This is because the data in cleaned_data has been validated according to the rules in the form, and converted into the relevant types where necessary: for instance, if you had an IntegerField in your form called my_number, request.POST['my_number'] will be a string like "3" but form.cleaned_data['my_number'] will be an actual integer, 3.
Related
I have created a form to update the existing user profile. But when i save the form it shows the error user already exists.
I used another approach by getting the user profile and then updating each field, but in that case each field has to be validated?
Any clue how to save the form as an update not as a new entry?
I suggest using UpdateView, one of Django's class-based-views for generic editing:
class django.views.generic.edit.UpdateView
A view that displays a
form for editing an existing object, redisplaying the form with
validation errors (if there are any) and saving changes to the object.
This uses a form automatically generated from the object’s model class
(unless a form class is manually specified).
I managed to get the answer, i imported the form to
import the user that i want to edit
u = User.objects.get(username = user_name)
creating the form with values from existing in database and updating with values from POST
user_form = UserEditForm(request.POST,instance=u)
save the form, since it already has existing record it will update
user_form.save()
One of the custom fields of my ModelForm holds the pk for the database row to be edited. Therefore, I would like to first check if the form is valid, then set the instance using the cleaned pk field, then save the form. Is it even possible?
My workaround right now is to create a new ModelForm instance, which is not very neat.
If your form is overwriting all the information in the instance, you could simply set the primary key manually:
if form.is_valid():
obj = form.save(commit=False)
obj.pk = form.cleaned_data['pk_to_edit']
obj.save()
return ...
I have a ModelForm field that is based on the following Model:
class Phrase(models.Model):
subject = models.ForeignKey(Entity) # Entity is unique on a per Entity.name basis
object = models.ForeignKey(Entity) # Entity is unique on a per Entity.name basis
The modelform (PhraseForm) has a field 'subject' that is a CharField. I want users to be able to enter a string. When the modelform is saved, and the string does not match an existing Entity, a new Entity is created.
This is why I had to overwrite the "subject" field of the Modelform, as I cannot use the automatically generated "subject" field of the Modelform (I hope I'm making myself clear here).
Now, all tests run fine when creating a new Phrase through the modelform. But, when modifying a Phrase:
p = Phrase.objects.latest()
pf = PhraseForm({'subject': 'anewsubject'}, instance=p).
pf.is_valid() returns False. The error I get is that "object" cannot be None. This makes sense, as indeed, the object field was not filled in.
What would be the best way to handle this? I could of course check if an instance is provided in the init() function of the PhraseForm, and then assign the missing field values from the instance passed. This doesn't feel as if it's the right way though, so, is there a less cumbersome way of making sure the instance's data is passed on through the ModelForm?
Now that I'm typing this, I guess there isn't, as the underlying model fields are being overwritten, meaning the form field values need to be filled in again in order for everything to work fine. Which makes me rephrase my question: is the way I've handled allowing users to enter free text and linking this to either a new or existing Entity the correct way of doing this?
Thanks in advance!
Why are you modifying using the form.
p = Phrase.objects.latest()
p.subject = Entity.objects.get_or_create(name='anewsubject')[0]
docs for get_or_create
If you are actually using the form it should work fine:
def mod_phrase(request, phrase_id=None):
phrase = get_object_or_404(Phrase, pk=phrase_id)
if request.method == 'POST':
form = PhraseForm(request.POST, instance=phrase)
if form.is_valid():
form.save()
return HttpResponse("Success")
else:
form = PhraseForm(instance=phrase)
context = { 'form': form }
return render_to_response('modify-phrase.html', context,
context_instance=RequestContext(request))
Setting the instance for the ModelForm sets initial data, and also lets the form know which object the form is working with. The way you are trying to use the form, you are passing an invalid data dictionary (lacks object), which the form is correctly telling you isn't valid. When you set the data to request.POST in the example above, the request.POST includes the initial data which allows the form to validate.
I have a form that consists of a response for each entry in another model. At the time the form is generated the response to each item may or may not exist. I need a form that allows me to update the response if it exists and create it with the form post data if it doesn't exist.
Currently I am iterating through a range and creating my forms with the post data:
forms = [SpecialNoteForm(request.POST, prefix=str(x), ) for x in rang(1,3)]
I am doing this because I don't know how else to access the form data cleanly in order to identify the object that the form should be instantiated with. I tried doing something like this after the forms list was created because i can then access the form data:
for form in forms:
try:
instance = SpecialNote.objects.get(flag=form["flag"].data, host=form["host"].data)
form.instance = instance
form.save()
The errors on the form persist after I do this, however. I need a way of accessing the data I need to instantiate the object at the time of form creation or a way of re-evaluating the form after i've attached an instance to it.
EDIT
I ran into the same problem with model formsets as I did with my initial approach--I don't know how to instantiate the forms while at the same time allowing for intial values on forms that don't have an instance. I don't want to create all of the model instances before hand because it is import whether or not the user has submitted these with the required fields filled in.
My current approach is still using the model forms:
forms = []
for n in form_range(request.POST): # calculates number of forms based on post data
try:
instance = SpecialNote.objects.get(flag=request.POST.get('%s'%n+'-flag'), host=request.POST.get('%s'%n+'-host'))
except:
instance = None
forms.append(SpecialNoteForm(request.POST, prefix=str(n), instance=instance))
for form in forms:
if form.is_valid():
form.save()
In summary, the problem with formsets is I don't know how to properly instantiate the forms without having them be queriable, i.e. already in the database. The problem with using regular model forms and a prefix is that getting the objects that i need to instantiate them with is messy (as you can see from my current approach). I'm looking for a solution to either of these two problems.
Multiple identical model forms on one page is what model formsets are for. They should take care of all of those issues.
I have a simple Django Form:
class testForm(forms.Form):
list = forms.CharField()
def getItems(self):
#How do I do this? Access the data stored in list.
return self.list.split(",") #This doesn't work
The list form field stores a csv data value. From an external instance of testForm in a view, I want to be able to look at the .csv value list stored in the form field.
Like others have already mentioned, you need to make use of the form's cleaned_data dictionary attribute and the is_valid method. So you can do something like this:
def getItems(self):
if not self.is_valid():
return [] # assuming you want to return an empty list here
return self.cleaned_data['list'].split(',')
The reason your method does not work is that the form fields are not your typical instance variables. Hope this helps!
What you usually do in django in a view to get the form data would be something like this.
form = testForm(request.POST)
if form.is_valid:
# form will now have the data in form.cleaned_data
...
else:
# Handle validation error
...
If you want to do some data formatting or validation yourself you can put this in the validation method in the form. Either for the entire form or for a form field. This is also a great way to make your code more DRY.
There are a couple of things you need to know here.
First is that generally in a Python class method you access the attributes through the 'self' object. So in theory your function should be:
def get_items(self):
return self.list.split(",")
However, in the case of a Django form, this won't work. This is because a field doesn't have a value of its own - the value is only attached to the field when it's rendered, and is obtained in different ways depending on whether the value was applied through initial data or by passing in a data dictionary.
If you have validated the form (through form.is_valid()), you can get the form via the cleaned_data dictionary:
return self.cleaned_data['list']
However this will fail if list has failed validation for any reason.
Call is_valid on the form, then access the cleaned_data dictionary.