Foreign Key field in django form not saving initialized value - python

I have a form with a foreign key field. The field is disabled and I initialized the value with initial. The value shows up but when I submit it, an error shows up: 'This field is required'
views.py:
def updateTicket(request, ticket_id):
ticketDetails = editTicket1.objects.filter(ticketID=ticket_id).last()
updateTrouble = editTrouble(request.POST or None, instance=ticketDetails, initial={'ticketID': ticket_id})
if updateTrouble.is_valid():
updateTrouble.save()
forms.py:
ticketID = forms.ModelChoiceField(queryset=tblTicket.objects.all(),widget=forms.Select(attrs={'disabled':'disabled'}))
How come when I disable the field, a foreign key field, the server does not accept the value. Even with initialization, when posted, it submits a blank value.

from thee django docs, it states this for the form field: "By default, each Field class assumes the value is required, so if you pass an empty value – either None or the empty string ("") – then clean() will raise a ValidationError exception:"
So, instead you should have done this; ticketID = forms.ModelChoiceField(required:False, queryset=tblTicket.objects.all(),widget=forms.Select(attrs={'disabled':'disabled'}))
or in your Models you'd have set a blank argument to the field to False, but I'll suggest to do it in the Form.

No sure if this is the issue but I think your form will always by showing the ticket_id since this is given in the initial form option which overrides the instance.
It's described here in the docs: https://docs.djangoproject.com/en/1.8/topics/forms/modelforms/#providing-initial-values
Also - if you want to correctly process the form I think you should expand the update ticket function like it is described in the docs:
https://docs.djangoproject.com/en/1.8/topics/forms/#the-view
The difference between the above example and your code will be in the else statement where instead of a blank form you initiate it using initial data like you provided in your code.
Hope that helps!

Related

(Django) How to clean an unbound form?

I have a problem. I looked at the web for a solution but did not find one. If my problem already have an answer, please give me the links.
The Problem
Here is the problem:
I create a form inside one of my view with some initial values:
form = MyForm(initial=initial)
However, I do not have a full control over these initial values, thus I need to check is the form is valid. However, because the form in unbound .is_valid() always return False.
So, I tried to create an bound form from the first step:
form = MyForm(initial)
However, I do not initialize all the field, simply because I do not know their name and how many they are, thus I cannot initialize all of them.
The problem is that some of the field I do not initialize are required. Thus, the .is_valid() always return False because I do not provide required field(s).
What I know is that all of the required field have a default value.
When I created the form with initial values (i.e. MyForm(initial=initial)), the defaults value are provided. So I wish I could do something like:
form = MyForm(initial=initial)
form = MyForm(form)
However, that obviously doesn't work.
I see two potential solution to my problem:
Validate an unbound form
Get a list with all the fields and their default values (if one) (I do not know this list in advance)
I do not know how to make 2, however, I tried this for 1:
form = MyForm(initial=initial)
form.clean()
form.clean() calls a custom function where I stated (I had no problem with a bound form):
cleaned_date = super().clean()
That returns the following errors:
AttributeError at XXX
'MyForm' object has no attribute 'cleaned_data'
And well, that is kind of logical, the form is unbound, thus the data are not cleaned yet.
Any piece of advice (or complete solution) will be greatly appreciated.
Thank you for having reading me.
Wrong Solution (that works, but too wordly/ugly)
There is one solution to this problem but I am sure this is not the could one (it is way too ugly).
I first create a unbound field:
form = MyForm()
Then I read the initial value of the fields inside the string representation of the form.
for field in form:
index_name = str(field.find("name"
name = field[index_name+len('name="':]
name = name[:name.find('"')]
index = str(field).find("value")
if index >= 0: # if their is a default value
value = field[index+len('value="'):]
value = value[:value.find('"')]
initial[name] = value
Then I just need to remake the form, bound this time:
form = MyForm(initial)
However, this solution is overwhelming and I am sure there is a better way to go.
Ideally you would get the default values and do an initial.update(defaults) and hand it to the form.
If the defaults are not available to you, you can try to remove fields from the form that are not in initial.
form = MyForm(data=initial)
field_keys = list(form.fields.keys())
for field_name in field_keys:
if field_name not in initial:
form.fields.pop(field_name)
form.is_valid() # <- only validates fields in initial
Maybe you can initialize your form with your initial values with no full control, and run form.is_valid() and use the form.cleaned_data to initial another form? But Why would you have to do validating on the unbound form? I think this scenario is rare.

Assigning value to a django form after form have been initiated

I have a form SOproduct2Form
in this form I have a field priceperunit
It is defined in my model like this
priceperunit = MoneyField(max_digits=10, decimal_places=2, default_currency='USD')
I am trying after the form got initialized to assign it with default value .
Since form is object and not dictionary I do it like this
form = SOproduct2Form(instance = soproduct1)
#form.priceperunit = 3
form.priceperunit = soproduct1.product.defaultPrice
#setattr(form, priceperunite, 5)
I am not getting any error,at the output it always displays 0
I tried to play with assigning value directly I am getting same 0.(see commented line)
When use setattr (also commented) I am getting error that priceperunit is not defined.
Question: What is the problem and how to make it work?
Do you really need to assign the value AFTER the form is initiated? According to your problem description, it seems to me that you just want to set the initial value entered in the field.
Generally in standard Django fields you would use initial argument, but I checked the source code of django-money and it seems you need default and default_currency arguments. Try something like this:
priceperunit = MoneyField(default=value, default_currency=currency)

How to set a default value for a Django Form Field, that would be saved even in the absence of user initiated changes?

When looking for this feature, one is flooded under answers pointing toward the Form initial member.
Yet, by its design, this approach would not save anything to database if the user does not change at least one value in the form, because the has_changed method returns False when only initial values are submitted.
Then, if one were to override has_changed to always return true, the behaviour would be to try to save forms for which no value (nor initial nor user input) is found.
Is it possible to have a real default value in Django: a value that the user can change if he wants, but that would still save the form to DB when the form is only submitted with default values ?
Here is the solution I am currently using to replace the meaning of initial to achieve the behaviour described in the question. I override the had_changed method of the Form to be:
def has_changed(self):
for name, field in self.fields.items():
prefixed_name = self.add_prefix(name)
data_value = field.widget.value_from_datadict(self.data, self.files, prefixed_name)
if data_value and not issubclass(field.__class__, forms.models.InlineForeignKeyField):
return True
return False
The second check (issubclass(...)) is required in case the Form is used in an InlineFormset: when editing the parent model, the foreign_key field is automatically populated for all forms displayed (even the ones that have no default values), so it prevents saving the ones that are left blank (neither defaults nor user input).
Now, on a personal and probably polemic note, I must say I hope I missed something obvious. My requirements seem quite basic, yet the solution here is nothing short of a brittle hack...
I don't think there is a premade solution for you. You'll have to do one of two things:
When the form is submitted, examine the value of the field in question. If it is equal to the default value, then ignore the result of has_changed and save it. (Be aware that this could result in duplicate items being saved, depending on your schema.)
When the form is submitted, search for an existing record with those field values. If no such record exists, save it. Otherwise do nothing. (If these records contain a last-updated timestamp, you might update that value, depending on your application.)

Django: Check if user have added a new instance in the form?

I have a form, which i am rendering. It also allow user to add a new instance if it does not exist in the list.
lets say the field is name from category modal.
name is an drop down list, and if user does not find his value in the list, he writes the name in the next input box.
When i validate it, it fails. because its not an instance of category.
Then I got it by using self.data and i compare if its an Integer, or not?
If its an integer, than its simply an existing element, if not, the user might have chosen a new User, and thus by getting it from the self.data, i can create the
category
object and save it and replace the original value with the ID so that validation does not fail.
Problem.
I know using self.data and using it for a db query can be dangerous. As user is allowed to input anything in it, and it might empty my database with that query, (i have heard it like that). Is this really possible? if yes, how to avoid that.
Hope someone can give me an idea.
Suppose your form has a name field for existing category names and a new_name field for the input box. In your form's clean() method, you'll want to check to see if self.cleaned_data has a value for new_name and act accordingly. You might do:
self.cleaned_data['name'] = self.cleaned_data['new_name']
for example.
Unless you override other field or form methods, the data in these fields are 'safe' as far as malicious input is concerned. If you raise a ValidationError in the form's clean() method, is_valid() will return false. So, as long as you:
form = YourForm(...)
if form.is_valid():
form.save()
The save() will not be called with invalid data.

Clearing Django form fields on form validation error?

I have a Django form that allows a user to change their password. I find it confusing on form error for the fields to have the *'ed out data still in them.
I've tried several methods for removing form.data, but I keep getting a This QueryDict instance is immutable exception message.
Is there a proper way to clear individual form fields or the entire form data set from clean()?
Regarding the immutable QueryDict error, your problem is almost certainly that you have created your form instance like this:
form = MyForm(request.POST)
This means that form.data is the actual QueryDict created from the POST vars. Since the request itself is immutable, you get an error when you try to change anything in it. In this case, saying
form.data['field'] = None
is exactly the same thing as
request.POST['field'] = None
To get yourself a form that you can modify, you want to construct it like this:
form = MyForm(request.POST.copy())
Someone showed me how to do this. This method is working for me:
post_vars = {}
post_vars.update(request.POST)
form = MyForm(post_vars, auto_id='my-form-%s')
form.data['fieldname'] = ''
form.data['fieldname2'] = ''
If you need extra validation using more than one field from a form, override the .clean() method. But if it's just for one field, you can create a clean_field_name() method.
http://docs.djangoproject.com/en/1.1/ref/forms/validation/#ref-forms-validation
I just created the form again.
Just try:
form = AwesomeForm()
and then render it.
Django has a widget that does that:
https://docs.djangoproject.com/en/1.8/ref/forms/widgets/#passwordinput
now if you are not working with passwords you can do something like this:
class NonceInput(Input):
"""
Hidden Input that resets its value after invalid data is entered
"""
input_type = 'hidden'
is_hidden = True
def render(self, name, value, attrs=None):
return super(NonceInput, self).render(name, None, attrs)
Of course you can make any django widget forget its value just by overriding its render method (instead of value I passed None in super call.)
Can't you just delete the password data from the form's cleaned_data during validation?
See the Django docs for custom validation (especially the second block of code).
I guess you need to use JavaScript to hide or remove the text from the container.

Categories

Resources