This is my form:
class EventForm(forms.Form):
start_date = forms.CharField(required=True, widget=forms.TextInput(attrs={'class': 'span6 as-date'}))
end_date = forms.CharField(required=True, widget=forms.TimeInput(attrs={'class': 'span6 as-date'}))
title = forms.CharField(required=True, widget=forms.TextInput(attrs={'class': 'span8'}))
description = forms.CharField(required=True, widget=forms.Textarea(attrs={'rows': 4, 'class': 'span8'}))
total_seats = forms.IntegerField(required=True, widget=forms.TextInput(attrs={'class': 'span6'}))
buffer_seats = forms.IntegerField(required=True, widget=forms.TextInput(attrs={'class': 'span6'}))
seat_cost = forms.IntegerField(required=True, widget=forms.TextInput(attrs={'class': 'span8'}))
published = forms.BooleanField(required=False, widget=forms.CheckboxInput(attrs={'class': 'span6'}))
verified_booking = forms.BooleanField(required=False, widget=forms.CheckboxInput(attrs={'class': 'span6'}))
def clean(self):
try:
self.cleaned_data['start_date'] = datetime.strptime(self.cleaned_data['start_date'], '%Y/%m/%d %H:%M')
except ValueError:
raise forms.ValidationError('Improper start date')
try:
self.cleaned_data['end_date'] = datetime.strptime(self.cleaned_data['end_date'], '%Y/%m/%d %H:%M')
except ValueError:
raise forms.ValidationError('Improper end date')
if self.cleaned_data['buffer_seats'] >= self.cleaned_data['total_seats']:
raise forms.ValidationError('Seats buffered can not be same or greater than total seats')
if self.cleaned_data['start_date'] >= self.cleaned_data['end_date']:
raise forms.ValidationError('Event start date can not be greater than end date')
if self.cleaned_data['published'] == 'on':
self.cleaned_data['published'] = True
else:
self.cleaned_data['published'] = False
if self.cleaned_data['verified_booking'] == 'on':
self.cleaned_data['verified_booking'] = True
else:
self.cleaned_data['verified_booking'] = False
Here's the view:
event_form = EventForm(request.POST)
if event_form.is_valid():
event = events_api.save_event_from_form(request.user, address, event_form.cleaned_data)
But I'm getting event_form.cleaned_data as None. What am I missing?
form.clean() must return cleaned_data. The canonical implementation is:
class MyForm(forms.Form):
# ...
def clean(self):
cleaned_data = super(MyForm, self).clean()
# do your custom validations / transformations here
# and some more
return cleaned_data
Related
I am using a Userprofile form with an UpdateView and encountering an issue where validation errors are not being raised, even when the conditions for the errors to be raised are met. What could be causing this unexpected behavior?
forms.py.
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ("avatar","username","first_name","last_name","age","gender")
# fields = ("avatar",)
Gender = (
('one','Male'),
('two','Female'),
)
widgets ={
'age' : forms.TextInput(attrs={'class':'form-control'}),
'gender' : forms.Select(choices=Gender,attrs={'class': 'form-control'}),
}
# TRIED THIS AS WELL
# def clean_age(self):
# age = self.cleaned_data["age"]
# print(age,'hm here')
# if age < 18:
# print(age,'hm here')
# raise forms.ValidationError("You're age should be 18 plus")
# return age
def clean(self):
cleaned_data = super().clean()
age = cleaned_data.get('age')
print('haye',age)
if age < 18:
print(age,'hm here')
# raise forms.ValidationError("You're age should be 18 plus")
age = "You're age should be 18 plus"
self.add_error('age',age)
raise forms.ValidationError("You're age should be 18 plus")
views.py
here i'm updated user model fields and then userprofile field and then saving them respectively.
class UserProfileUpdateView(UpdateView):
refirect_field_name ='accounts:profile'
template_name = 'accounts/profiles/profile_update.html'
form_class = UserProfileForm
model = UserProfile
def get_object(self, *args, **kwargs):
return self.request.user.userprofile
def get_context_data(self, *args, **kwargs):
context = super(UserProfileUpdateView, self).get_context_data(*args, **kwargs)
update_form = UserProfileForm(instance = self.request.user.userprofile)
context['form']=update_form
return context
def form_valid(self, form):
username = form.cleaned_data['username']
print('username :',username)
first_name = form.cleaned_data['first_name']
print('first name :',first_name)
last_name = form.cleaned_data['last_name']
print('last name :',last_name)
age = form.cleaned_data['age']
print('age :',age)
gender = form.cleaned_data['gender']
print('gender :',gender)
# usermodel save
user = User.objects.get(username=self.request.user)
print('GOT reqested User',user)
user.username = username
print('changed username :',user.username)
user.age = age
print('changed age :',user.age)
user.gender = gender
print('changed gender:',user.gender)
user.first_name = first_name
print('changed first name :',user.first_name)
user.last_name = last_name
print('changed last name :',user.last_name)
user.save()
# userprofile save
profile = UserProfile.objects.get(user=self.request.user)
print('GOT reqested User',profile)
profile.username = username
print('changed username :',profile.username)
profile.age = age
print('changed age :',profile.age)
profile.gender = gender
print('changed gender:',profile.gender)
profile.first_name = first_name
print('changed first name :',profile.first_name)
profile.last_name = last_name
print('changed last name :',profile.last_name)
profile.save()
form.save()
return super().form_valid(form)
models.py
class UserProfile(models.Model):
user = models.OneToOneField(auth.models.User,related_name='userprofile', on_delete=models.CASCADE)
avatar = models.ImageField(("displays"), upload_to='displays', height_field=None, width_field=None, max_length=None,default ='user.jpg')
create_date = models.DateTimeField(default = timezone.now)
Gender = (
('one','Male'),
('two','Female'),
)
first_name = models.CharField(("first_name"), max_length=50,null=True)
last_name = models.CharField(("last_name"), max_length=50,null=True)
username = models.CharField(("username"), max_length=50,null=True)
age = models.IntegerField(("age"),null=True)
gender = models.CharField(("gender"), max_length=50,choices=Gender,null=True)
def __str__(self):
return f'{self.user.username} UserProfile'
def clean_fields(self, exclude=None):
if self.age < 18:
raise ValidationError(
{"age": "You're age should be 18+"}
)
return super().clean_fields(exclude=exclude)
def save(self,*args, **kwargs):
if not self.username:
self.username = self.user.username
if not self.age:
self.age = self.user.age
if not self.gender:
self.gender = self.user.gender
if not self.first_name:
self.first_name = self.user.first_name
if not self.last_name:
self.last_name = self.user.last_name
super(UserProfile,self).save(*args, **kwargs)
Please tell me how can i fix this issue and raise errors on unvalid details.
If more information is require then tell me in a comment section, I'll update my question with that information.
By using both methods there is no need to override form's clean method and the object is validated whenever you create an instance.
Method 1:
Override clean_fields method of class UserProfile in models.py
def clean_fields(self, exclude=None):
if self.age < 18:
raise ValidationError(
{"age": "You're age should be 18+"}
)
return super().clean_fields(exclude=exclude)
Method 2:
Add min value validation for age field while defining it
age = models.PositiveIntegerField(
help_text="Age of the user.",
validators=[
MinValueValidator(
18, "You're age should be 18+"
)
]
)
Your views:
def form_valid(self, form):
# userprofile save
profile = form.save(commit=False)
# usermodel save
user = self.request.user
user.username = profile.username
user.age = profile.age
user.gender = profile.gender
user.first_name = profile.first_name
user.last_name = profile.last_name
user.save()
return super().form_valid(form)
In Django, I want to build a form that collects shipping addresses from users! Then save them to database
There is views.py starts with defining a function "is_valid_form(values)"
def is_valid_form(values):
valid = True
for field in values:
if field == '':
valid = False
return valid
class EnCheckoutView(View):
def get(self, *args, **kwargs):
try:
order = Order.objects.get(user=self.request.user, ordered=False)
form = CheckoutForm()
context = {
'form': form,
'couponform': CouponForm(),
'order': order,
'DISPLAY_COUPON_FORM': True
}
shipping_address_qs = Address.objects.filter(user=self.request.user, address_type='S', default=True)
if shipping_address_qs.exists():
context.update({
'default_shipping_address': shipping_address_qs[0]
})
return render(self.request, 'en-checkout-page.html', context)
except ObjectDoesNotExist:
messages.info(self.request, 'You do not have an active order.')
return redirect('core:en-checkout')
def post(self, *args, **kwargs):
try:
order = Order.objects.get(user=self.request.user, ordered=False)
except ObjectDoesNotExist:
messages.warning(self.request, 'You do not have an active order')
return redirect('core:en-order-summary')
form = CheckoutForm(self.request.POST or None)
if form.is_valid():
use_default_shipping = form.cleaned_data.get("use_default_shipping")
if use_default_shipping:
print('Using the default shipping address')
address_qs = Address.objects.filter(user=self.request.user, default=True)
if address_qs.exists():
shipping_address = address_qs[0]
order.shipping_address = shipping_address
order.save()
else:
messages.info(self.request, 'No default shipping address available')
return redirect('core:en-checkout')
else:
print('User is entering a new shipping address')
customer_name = form.cleaned_data.get('customer_name')
phone = form.cleaned_data.get('phone')
email = form.cleaned_data.get('email')
shipping_address1 = form.cleaned_data.get('shipping_address1')
shipping_address2 = form.cleaned_data.get('shipping_address2')
en_shipping_country = form.cleaned_data.get('en_shipping_country')
shipping_zip = form.cleaned_data.get("shipping_zip")
if is_valid_form([customer_name, phone, shipping_address1]):
shipping_address = Address(
user=self.request.user,
customer_name=customer_name,
phone=phone,
email=email,
street_address=shipping_address1,
apartment_address=shipping_address2,
country=en_shipping_country,
zip=shipping_zip,
address_type='S'
)
shipping_address.save()
order.shipping_address = shipping_address
order.save()
set_default_shipping = form.cleaned_data.get('set_default_shipping')
if set_default_shipping:
shipping_address.default = True
shipping_address.save()
else:
messages.info(self.request, 'Please ***fill in the required shipping address fields')
en_payment_option = form.cleaned_data.get('en_payment_option')
if en_payment_option == 'S':
return redirect('core:en-payment', en_payment_option='Pay with credit card')
elif en_payment_option == 'P':
return redirect('core:ar-delivery', en_payment_option='Cash on delivery')
else:
messages.warning(self.request, 'Invalid payment option selected')
return redirect('core:en/checkout')
Why this form does not save the address to the database?
I could have posted forms.py, html template, and models.py, but I guess that will explain the problem.
forms.py
EN_PAYMENT_CHOICES = (
('S', 'Pay with credit card'),
('P', 'Cash on delivery')
)
class CheckoutForm(forms.Form):
customer_name = forms.CharField(max_length=100, required=True)
phone = forms.IntegerField(required=True)
email = forms.EmailField()
shipping_address1 = forms.CharField(required=True)
shipping_address2 = forms.CharField(required=False)
ar_shipping_country = CountryField(blank_label='(اختار البلد)').formfield(
required=False,
widget=CountrySelectWidget(attrs={
'class': 'custom-select d-block w-100',
}))
en_shipping_country = CountryField(blank_label='(Choose a country)').formfield(
required=False,
widget=CountrySelectWidget(attrs={
'class': 'custom-select d-block w-100',
}))
shipping_zip = forms.CharField(required=False)
set_default_shipping = forms.BooleanField(required=False)
use_default_shipping = forms.BooleanField(required=False)
payment_option = forms.ChoiceField(
widget=forms.RadioSelect, choices=PAYMENT_CHOICES)
en_payment_option = forms.ChoiceField(
widget=forms.RadioSelect, choices=EN_PAYMENT_CHOICES)
models.py
class Address(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
customer_name = models.CharField(max_length=100, null=True)
phone = models.IntegerField(null=True)
email = models.EmailField(null=True)
street_address = models.CharField(max_length=250)
apartment_address = models.CharField(max_length=250)
country = CountryField(multiple=False, null=True)
zip = models.CharField(max_length=100)
address_type = models.CharField(max_length=1, choices=ADDRESS_CHOICES)
default = models.BooleanField(default=False)
def __str__(self):
return self.user.username
class Meta:
verbose_name_plural = 'Addresses'
My model.py looks:
class VehicleInquiry(TimeStampedModel):
inquiry_status = models.PositiveSmallIntegerField(_("inquiry status"), choices=INQUIRY_STATUS_CHOICES, default=1)
ip = models.GenericIPAddressField(_("IP"), blank=True, null=True)
full_name = models.CharField(_("full name"), max_length=100)
address = models.CharField(_("address"), max_length=200)
phone_code = models.PositiveSmallIntegerField(_("phone code")
)
phone = models.CharField(_("phone"), max_length=20)
email = models.EmailField(_("email"))
is_subscribed = models.BooleanField(_("subscribed"), default=True)
vehicle = models.ForeignKey(VehicleStock, on_delete=models.SET_NULL, blank=True, null=True,
related_name="inquiries", verbose_name=_("vehicle")
)
country = models.ForeignKey(Country, on_delete=models.SET_NULL, blank=True, null=True,
related_name="inquiries", verbose_name=_("country")
)
arrival_port = models.ForeignKey(CountryPorts, on_delete=models.SET_NULL, blank=True, null=True,
related_name="inquiries", verbose_name=_("arrival port")
)
current_price = models.PositiveIntegerField(_('current price'), null=True, blank=True)
inspection = models.BooleanField(_("pre-export inspection"), default=False)
insurance = models.BooleanField(_("insurance"), default=True)
total = models.PositiveIntegerField(_('total price'), null=True, blank=True)
my form.py:
class VehicleInquiryForm(forms.ModelForm):
country2 = forms.TypedChoiceField(
label=_("Country"),
choices=[('','Arrival Country')]+[(country.id, country.name) for country in Country.objects.all().filter(visible=True).order_by('name')],
required=True,
)
phone_code = ChoiceFieldWithTitles(
label=_("Country dialing code"),
choices=[('','Dailing Code', 'Dailing Code')]+[(country.id, '{} (+{})'.format(country.name, country.phone_code), '+{}'.format(country.phone_code)) for country in Country.objects.all().filter(visible=True).order_by('name')],
required=True,
)
arrival_port = forms.TypedChoiceField(
label=False,
widget=forms.RadioSelect
)
phone = forms.CharField(
label=_("Phone"),
max_length=20,
required=True,
validators=[phone_number_validator]
)
full_name = StrippedCharField(
label=_("Full name"),
max_length=30,
required=True,
validators=[full_name_validator]
)
address = StrippedCharField(
label=_("Address"),
max_length=200,
required=True
)
class Meta:
model = VehicleInquiry
exclude = ('inquiry_status', 'vehicle', 'current_price', 'total')
def clean_country2(self):
country_id = self.cleaned_data['country2']
try:
country = Country.objects.get(id=country_id)
except Country.DoesNotExist:
raise forms.ValidationError(_('Please select the country'))
return country_id
def clean(self):
cleaned_data = super(VehicleInquiryForm, self).clean()
dialing_code = cleaned_data['phone_code']
try:
dialing_country = Country.objects.get(id=dialing_code)
except Country.DoesNotExist:
raise forms.ValidationError(_('Please select the phone code'))
return self.cleaned_data
def __init__(self, *args, **kwargs):
dialing_code = kwargs.pop('phone_code', None)
super(VehicleInquiryForm, self).__init__(*args, **kwargs)
self.fields['is_subscribed'].label = _("Keep me updated with news, specials offers and more.")
self.helper = FormHelper()
self.helper.template_pack = "bootstrap3"
self.helper.form_method = "post"
self.helper.form_id = "vehicle-shipping-form"
self.helper.form_show_errors = True
self.initial['insurance'] = True
self.fields['phone_code'].initial = dialing_code
self.helper.add_input(
Submit('inquiry', _('Inquiry'), css_class='btn btn-default',)
)
self.helper.form_method = 'post'
self.helper.layout = Layout(
Fieldset(
_("1. Choose Your Final Destination"),
Div(
Field('country2', css_class="order-select-country"),
),
-- other fields --
)
view.py
class VehicleStockDetailView(FormView):
template_name = "site/product/vehicle-detail.html"
template_name_done = "site/contact/contact-us-done.html"
template_name_done_email = "site/contact/emails/contact-us-done.html"
form_class = VehicleInquiryForm
model = VehicleStock
def get(self, request, slug, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
vehicle = get_object_or_404(VehicleStock, slug=slug)
similar_vehicles = VehicleStock.objects.get_public_available().filter(model__id=vehicle.model.id).exclude(slug=slug)[:6]
page_title = vehicle.model
return render(request, self.template_name, {'page_title': page_title, 'similar_products': similar_vehicles, 'stock_product': vehicle, 'shipping_form': form})
def post(self, request, slug, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
vehicle = get_object_or_404(VehicleStock, slug=slug)
similar_vehicles = VehicleStock.objects.get_public_available().filter(model__id=vehicle.model.id).exclude(slug=slug)[:6]
page_title = vehicle.model
if form.is_valid():
form.save()
return render(self.request, self.template_name_done, {'full_name': request.POST['full_name'], 'email': request.POST['email']})
return render(self.request, self.template_name, {'page_title': page_title, 'similar_products': similar_vehicles, 'stock_product': vehicle, 'shipping_form': form})
url.py
url(r'^vehicle/(?P<slug>[-_\w]+)/$', VehicleStockDetailView.as_view(), name='vehicle-detail'),
Now, when I fill the form and send inquiry it is not showing any error but showing again the form with entered field values except phone_code (it is showing default value). No errors showing, but the form is not validated. I tried different ways with TemplateView and with FormView. But no success.Deadly need any help.
You haven't passed the POSTed data to the form anywhere.
This is one of the reasons why you should not be overriding the get and post methods. The point of the various class-based views is that they do almost all of this for you. You should be inheriting from CreateView, so that the form is saved when it is valid, and the extra logic you have added should be in get_context_data - as you can see, this avoids having to include the same code twice.
class VehicleStockDetailView(CreateView):
template_name = "site/product/vehicle-detail.html"
template_name_done = "site/contact/contact-us-done.html"
template_name_done_email = "site/contact/emails/contact-us-done.html"
form_class = VehicleInquiryForm
model = VehicleStock
def get_context_data(self, *args, **kwargs):
context = super(VehicleStockDetailView, self).get_context_data(*args, **kwargs)
context['vehicle'] = get_object_or_404(VehicleStock, slug=self.kwargs['slug'])
context['similar_vehicles'] = VehicleStock.objects.get_public_available().filter(model__id=vehicle.model.id).exclude(slug=slug)[:6]
context['page_title'] = vehicle.model
return context
def form_valid(self, form, *args, **kwargs):
obj = form.save()
return render(self.request, self.template_name_done, {'full_name': self.request.POST['full_name'], 'email': self.request.POST['email']})
Note also that you really should never directly render a template on success; you should always redirect. Again, the form view takes care of this for you.
this is my views.py
def signup(request):
print "signup"
if request.method == 'POST':
print "post signup"
form = RegisterForm(request.POST)
try:
if form.is_valid():
print form.cleaned_data
u = User.objects.create_user(form.cleaned_data['emailid'], form.cleaned_data['emailid'], form.cleaned_data['passwd1'] )
ui = UserInfo()
ui.user = u
ui.class_of = form.cleaned_data['gradyear']
ui.grade = form.cleaned_data['grade']
ui.balance = 0
ui.save()
and in my forms.py i have:
class RegisterForm(forms.Form):
GRADE_CHOICES = (
(9,'9'), (10,'10'), (11,'11'), (12,'12') ,
)
curr_year = date.today().year
GRAD_YEAR_CHOICES = (
(curr_year,curr_year), (curr_year+1,curr_year+1), (curr_year+2,curr_year+2), (curr_year+3,curr_year+3) ,
)
first_name = forms.CharField(max_length = 25)
last_name = forms.CharField( max_length = 25)
emailid = forms.EmailField()
passwd1 = forms.CharField(max_length=100,widget=forms.PasswordInput)
passwd2 = forms.CharField(max_length=100,widget=forms.PasswordInput)
gradyear = forms.ChoiceField( choices=GRAD_YEAR_CHOICES)
grade = forms.ChoiceField( choices=GRADE_CHOICES)
def clean(self):
cleaned_data = super(RegisterForm, self).clean()
if cleaned_data['passwd1'] != cleaned_data['passwd2']:
raise forms.ValidationError({'passwd1':['Password do not match']})
if User.objects.filter(email=cleaned_data['emailid']).count():
raise forms.ValidationError({'emailid':['Email already taken ']})
return cleaned_data
why does everything print to the database except first_name and last_name??? (username, email, grade, gradyear, and password all save)
EDIT: This is my UserInfo
class UserInfo(models.Model):
user = models.OneToOneField(User, related_name='user_infos')
class_of = models.IntegerField()
#username = user.username
#fname = user.fname
#lname = user.last_name
#email = user.email
#Staff = user.is_staff
pub_date = models.DateTimeField( auto_now=True)
grade = models.IntegerField()
balance = models.DecimalField(max_digits=6, decimal_places=2)
#first_name = models.CharField(max_length = 25)
In the code provided, you never save first_name and last_name for User or UserInfo.
In def signup(request):, right after this line:
u = User.objects.create_user(form.cleaned_data['emailid'], form.cleaned_data['emailid'], form.cleaned_data['passwd1'] )
Try including this:
u.first_name = form.cleaned_data['first_name']
u.last_name = form.cleaned_data['last_name']
u.save()
views.py
if pform.is_valid():
user = pform.save()
forms.py
class UserProfileForm(forms.ModelForm):
sex = forms.CharField(max_length = 20,label="I am :",widget=forms.Select(choices=SEX_CHOICES,attrs = {'class':''}),required = False)
first_name = forms.CharField(max_length = 50,widget = forms.TextInput(attrs={'placeholder':'Please enter your real name.','class':''}),required = False)
last_name = forms.CharField(max_length = 50,widget = forms.TextInput(attrs={'placeholder':'Enter last name.','class':''}),required = False)
location = forms.CharField(max_length = 50,widget = forms.TextInput(attrs={'placeholder':'Enter your current location','class':''}),required = False)
def clean_first_name(self):
first_name = self.cleaned_data['first_name']
if first_name == '':
raise forms.ValidationError("This field is required.")
return first_name
def clean_phone(self):
phone = self.cleaned_data['phone']
if phone == '':
raise forms.ValidationError("This field is required.")
return phone
def clean_last_name(self):
last_name = self.cleaned_data['last_name']
if last_name == '':
raise forms.ValidationError("This field is required.")
return last_name
def clean_profession(self):
profession = self.cleaned_data['profession']
if profession == "":
raise forms.ValidationError("Select a valid option.")
return profession
def clean_sex(self):
sex = self.cleaned_data['sex']
if sex == "":
raise forms.ValidationError("Select a valid option.")
return sex
def __init__(self,*args,**kw):
super(UserProfileForm,self).__init__(*args,**kw)
self.phone = self.instance.get_profile().phone
self.profession = self.instance.get_profile().profession
self.sex = self.instance.get_profile().sex
self.location = self.instance.get_profile().location
def save(self,*args,**kw):
self.instance.first_name = self.cleaned_data.get("first_name")
self.instance.last_name = self.cleaned_data.get("last_name")
self.instance.get_profile().sex = self.cleaned_data.get("sex")
self.instance.get_profile().location = self.cleaned_data.get("location")
self.instance.get_profile().profession = self.cleaned_data.get("profession")
self.instance.get_profile().phone = self.cleaned_data.get("phone")
self.instance.save()
return self.instance
class Meta:
model = User
fields = ('first_name','last_name','phone','sex','profession','location')
#exclude = ('email')
doubt
everything is working fine but y am i not able to save the information to the user profile , when i use the self.instance.get_profile().phone = self.cleaned_data.get('#some_field') , because when i am retrieving the data its not showing up in m form , please help , thanks in advance
If I understood you well, then you get data from the form and can't save it to the users profile. To fix this, you need do save user profile too:
def save(self,*args,**kw):
self.instance.first_name = self.cleaned_data.get("first_name")
self.instance.last_name = self.cleaned_data.get("last_name")
profile = self.instance.get_profile()
profile.sex = self.cleaned_data.get("sex")
profile.location = self.cleaned_data.get("location")
profile.profession = self.cleaned_data.get("profession")
profile.phone = self.cleaned_data.get("phone")
profile.save()
self.instance.save()
return self.instance
You shouldn't use a # when fetching the field. Do this instead:
self.cleaned_data.get('some_field')