Why clean method in my form will not clean? - django

I wrote a clean method on my form and it is not actually doing the validation.
class Property1Form(forms.ModelForm):
class Meta:
model = Property1
fields = ['unit','propertytype','is_true','date','followup_date','quantity','description']
def __init__(self, *args, **kwargs):
super(Property1Form, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if instance:
self.fields['unit'].required = False
self.fields['unit'].widget.attrs['disabled'] = 'disabled'
def clean(self):
form_data = self.cleaned_data
if Property1.objects.filter(unit=form_data['unit'], propertytype=form_data['propertytype'] ).count() > 0:
self._errors["propertytype"] = ["Propertytype already exists for unit"] # Will raise a error message
del form_data['propertytype']
Same validation does work for me on model level but on model level I am getting 500 error
ValidationError at
/unit/property/new/6/http://127.0.0.1:8000/unit/property_details/6/
{'all': [u'Same property cant be assigned more then ones']}
So trying to have same validation on the form side as well.
UPDATE:
view method
def property_new(request,pk,uri):
unit = get_object_or_404(Unit, pk=pk)
title = 'property'
uri = _get_redirect_url(request, uri)
if request.method == "POST":
form = Property1Form(request.POST)
form.fields['unit'] = unit
if form.is_valid():
properties = form.save(commit=False)
properties.unit = unit
properties.save()
messages.add_message(request, messages.SUCCESS, str(properties.unit) + "-SUCCESS Object created sucssefully")
return redirect(uri)
else:
form = Property1Form(initial={'unit': unit})
return render(request, 'object_edit.html', {'form': form, 'title':title, 'extend': EXTEND})

You have set required=False and disabled the unit field. That means that the browser will not submit any values for the unit field.
Therefore form.cleaned_data['unit'] is None, so the if statement in your clean method is always False.
As I suggested on your other question, I think it's a bad idea to set required=False and disabled the unit field. If you don't want the user to edit the field, don't include it in the form.

Related

How i can add correctly data to an existing choicefield and save it in database: Django

I want to add some choices to an exiting fieldchoice from the database,
I have did that in my views.py:
def operation(request):
if request.method == 'GET':
form = FormOperation(instance=request.user, )
var = Metry.objects.filter(user=request.user).last().profile.name
varr = Metry.objects.filter(user=request.user).last().profile.category
form.fields['dite'].choices.append((varr, var))
print(form.fields['dite'].choices)
else:
if request.user.is_authenticated:
form = FormOperation(request.POST, )
if form.is_valid():
form.save()
return render(request, 'pages/operation.html', {'form': form})
models.py:
dite = models.CharField(null = True, max_length=60,choices = CHOICES)
forms.py:
class FormOperation(forms.ModelForm):
class Meta:
model = Operation
exclude = ("user",)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
after "append" the choice , As a test I have did a "print" to see the choice and it's normal i can see it in my terminal, but not in the page browser of my django application indeed ,i can see just the first choices without considering what i have append in my views.py,...
Any help will be appreciated.
You can use list extend method. (Make sure your CHOICES is a LIST)
new_choices[('abc', 'def'),]
CHOICES.extend(new_choices)
(Note: It will not override the existing value in select field, and will create another choice with same value)

Complicated Django ModelForm validation with OneToOneField and customed argument

Sorry for the lengthy question. I have a complicated situation with django modelform validation. I have a model UserProject ready and created many objects. I also have another model Action_Inputs to accept multiple parameters, which is a onetoonefield relation with UserProject. I do need customed input argument for one field of Action_Inputs. But I cannot have the form valided.
models.py
class UserProject(models.Model):
pid = models.CharField(max_length=10, null=False, unique=True)
email = models.EmailField(max_length=254, null=False)
directory = models.CharField(max_length=255)
class Action_Inputs(models.Model):
userproject = models.OneToOneField(UserProject, null=False)
method = models.CharField(max_length=255)
file = models.FileField(upload_to='userdata')
Now I have the following ModelForm which takes a customed input argument jobid, catched from url, which is a string to get back to the previous UserProject pid:
class ActionInputsForm(ModelForm):
def __init__(self, jobid, *args, **kwargs):
super(ActionInputsForm, self).__init__(*args, **kwargs)
self.fields['userproject'].initial = jobid
class Meta:
model = Action_Inputs
fields = ['userproject', 'method', 'file'] # userproject will be hidden
def clean_userproject(self):
userproject = self.cleaned_data['userproject']
if len(userproject) != 10:
raise forms.ValidationError("---PID error.")
return UserProject.objects.get(pid=userproject)
def clean(self):
return self.cleaned_data
In my views.py
def parameters_Inputs(request, jobid):
if request.method == "POST":
form1 = ActionInputsForm(request.POST, request.FILES, jobid)
if form1.is_bound:
form1.save()
return render(request, 'goodlog.html', {'jobid': jobid})
elif request.method == "GET":
form1 = ActionInputsForm(jobid)
return render(request, 'inputsform.html',
{'form1': form1, 'jobid': jobid})
Now the request.POST['userproject'] is empty, which means the jobid has not been modified by init, the request.FILES looks correct but the validation is false. It says Unicode object has no attrite get, which is related to the uploaded file. Any idea about what is wrong? Thanks very much.
The following works:(thanks to Vladimir Danilov)
def __init__(self, jobid, *args, **kwargs):
super(ActionInputsForm, self).__init__(*args, **kwargs)
self.fields['userproject'].initial = UserProject.objects.get(pid=jobid)
def clean_userproject(self):
userproject = self.cleaned_data['userproject']
if not userproject:
raise forms.ValidationError("---UserProject not found.")
return userproject
def parameters_Inputs(request, jobid):
if request.method == "POST":
form1 = ActionInputsForm(jobid, request.POST, request.FILES)
.......
Not answer, but do you mean ActionInputsForm instead of Action_Inputs in these lines?
form1 = Action_Inputs(request.POST, request.FILES, jobid)
# ...
form1 = Action_inputs(jobid)
Also, you should write ActionInputsForm(jobid, request.POST, request.FILES).
Because in your case jobid will be request.POST.

Pass logged user to model field django

I don't know how to get the username from the current user.
I have a edit form rendered with djano-crispy-forms:
class RecepcionForm(forms.ModelForm):
fecha_recepcion = forms.DateField(widget=DateInput())
def __init__(self,*args,**kwargs):
super(RecepcionForm,self).__init__(*args,**kwargs)
self.helper = FormHelper(self)
self.helper.layout = Layout(
Field('id_proveedor',
'anio',
'mes',
'usuario',
readonly = True
),
Fieldset('',
'fecha_recepcion',
'num_archivos',
Submit('save','Grabar')
)
)
class Meta:
model = DetalleRecepcion
my views.py:
#login_required(login_url='/login/')
def RecepcionView(request):
idp = request.GET.get('i')
anio = request.GET.get('a')
mes = request.GET.get('m')
if request.method == 'POST':
r = DetalleRecepcion.objects.get(id_proveedor=idp,anio=anio,mes=mes)
form = RecepcionForm(request.POST, instance=r)
if form.is_valid():
form.save()
return HttpResponseRedirect('/monitor/')
else:
r = DetalleRecepcion.objects.get(id_proveedor=idp,anio=anio,mes=mes)
form = RecepcionForm(instance=r)
return render_to_response('recepcion.html',
{'form':form},
context_instance=RequestContext(request))
I need to fill the field usuario with the logged username.
I tried with form = request.user.username before the save of the form.
I am confused of this have to be done passed the value in the form definition or in the view.
If is possible to overwrite the retrieved value from the database and fill the field with the username in the form class.
Another question
How can I change the widget type in the form. The field id_proveedor is a foreign key and is rendered as a drop down box (select widget), but I need to show the value displayed in a label where the can't edit the value.
I tried with the readonly propertie, but the user is not capable to write in the select box, but is capable to select from the drop down.
How can change the widget or how can I disabled the drop dwon function from the select box
Thanks in advance
You can always pass whatever arguments or keyword arguments you need to a form class, you just have to remove them from the *args or **kwargs that are passed on when calling super(), otherwise Django will throw an exception because it's receiving an arg or kwarg it's not expecting:
class MyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user') # notice the .pop()
super(MyForm, self).__init__(*args, **kwargs)
# views.py
def my_view(request):
# assuming the user is logged in
form = MyForm(user=request.user)
I came across the same as your problem and found a solution just now. I do not know whether this is the best solution or maybe I will have problem later.
def add_trip_event(request):
#form = Trip_EventForm()
#return render(request, 'trips/add_trip_event.html', {'form': form})
if request.method == "POST":
form = Trip_EventForm(request.POST, request.FILES)
if form.is_valid():
post = form.save(commit=False)
post.trip_owner = Owner.objects.get(owner=request.user)
post.pub_date = timezone.now()
post.view = 0
post.save()
form.save_m2m()
return HttpResponseRedirect(reverse('trips:index'))
else:
form = Trip_EventForm()
return render(request, 'trips/add_trip_event.html', {'form': form})

django form with customer parameter and validation not getting clean function

I have the following form:
class GroupForm(forms.ModelForm):
class Meta:
model = Group
def __init__(self, customer):
self.customer = customer
super(GroupForm, self).__init__()
def clean(self):
cleaned_data = super(GroupForm, self).clean()
email = cleaned_data.get('email')
print email
try:
groups = Group.objects.filter(email=email, customer=self.customer)
if groups:
messsge = u"That email already exists"
self._errors['email'] = self.error_class([messsge])
except:
pass
return cleaned_data
I call the form from the view like so:
if request.method == "POST":
form = GroupForm(request.POST, customer, instance=group)
if form.is_valid():
form.save()
The problem is that the validation is never triggered. Also the print of the email is never hit which means the clean function is never hit.
Why is this occurring?
I see this problem a lot here on SO, and the cause is usually the same. You have overridden the init method and changed the signature, so that the first element is now customer, not data. But when you instantiate it in your view, you pass request.POST first, so the parameters don't match up to the right variables.
In addition, you don't pass the parameters into the super method, so the POST is never even seen.
Do this instead:
class GroupForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.customer = kwargs.pop('customer', None)
super(GroupForm, self).__init__(*args, **kwargs)
and in the view:
form = GroupForm(request.POST, customer=customer, instance=group)

Django: Save id on a OneToOneField

models:
class UserDataUpdate(models.Model):
code = models.CharField(max_length=8)
address = models.CharField(max_length=50)
class UserSurvey(models.Model):
about_treatment = models.CharField(max_length=2)
user_data_update = OneToOneField(UserDataUpdate)
views:
#login_required
def generate_survey(request):
user_data_update = UserDataUpdate.objects.get(code=request.user.username)
if request.method == 'POST':
form = SurveyForm(request.POST)
if form.is_valid():
form.save()
return redirect('/success')
else:
form = SurveyForm(request.GET)
return render_to_response(
'survey.html',
{'form': form },
context_instance = RequestContext(request))
form:
class SurveyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(SurveyForm, self).__init__(*args, **kwargs)
for field in self.fields.values():
field.widget = RadioSelect(choices=SURVEY_CHOICES)
class Meta:
model = Survey
exclude = ['user_data_update']
I just need a way to set the UserDataUpdate id (that already has been created) on a UserSurvey.
I'm getting this message on generate_survey request.POST:
user_data_update_app_usersurvey.user_data_update_id may not be NULL
It should be clear to you that you get the user_data_update value but then don't do anything with it. I guess you want to set it on the object that's created by the form:
if form.is_valid():
instance = form.save(commit=False)
instance.user_data_update = user_data_update
instance.save()
(I don't understand what all that stuff in the form's __init__ method is supposed to do. You only have one field in your form, anyway.)