Key Error with form - DJANGO - django

I have a project in django and I am creating a simple form that will allow a user to create a simple profile that asks for name and date of birth and location. I am getting a key error with the date of birth section and I dont know exactly why.
I am trying to collect data and store it to then later added it to a database record.
Here is the views file:
cd = form.cleaned_data
first_name = cd['first_name']
last_name = cd['last_name']
dob_month = cd['dob_month']
dob_day = ['dob_day']
dob_year = ['dob_year']
city = cd['city']
state = cd['state']
phone = cd['phone']
privacy = cd['privacy']
Here is the models file:
user = models.ForeignKey(User, on_delete=models.CASCADE) # server
first_name = models.CharField(max_length=25, default='first')
last_name = models.CharField(max_length=25, default='last')
dob_month = models.IntegerField(default=0)
dob_day = models.IntegerField(default=0)
dob_year = models.IntegerField(default=0)
city = models.CharField(max_length=45) # user
state = models.CharField(max_length=25, default='state')
phone = models.BigIntegerField(default=0) # user
privacy = models.SmallIntegerField(default=1) # user
created = models.DateTimeField(auto_now_add=True) # server
here is the forms file:
class ProfileForm(forms.ModelForm):
split_choices = (('1', 'public'),
('2', 'private'))
privacy = forms.TypedChoiceField(
choices=split_choices, widget=forms.RadioSelect, coerce=int
)
dob = forms.DateField(widget=extras.SelectDateWidget)
class Meta:
model = Profile
fields = ['first_name', 'last_name', 'dob', 'city', 'state', 'phone', 'privacy']
and finally, here is the error that I am getting:
KeyError at /setup_profile/
'dob_month'
Request Method: POST
Request URL: http://127.0.0.1:8000/setup_profile/
Django Version: 1.8.6
Exception Type: KeyError
Exception Value:
'dob_month'
Exception Location: C:\Users\OmarJandali\Desktop\opentab\opentab\tab\views.py in profile_setup, line 292
first_name 'omar'
last_name 'jandali'
dob_month '1'
dob_day '23'
dob_year '2024'
city 'riverside'
state 'ca'
phone '9515343666'
privacy '1'
submit 'submit'
UPDATED:
here is the views.py file but the issue is with the cd['dobv_month'], but i have no idea why the error is coming from there.
def profile_setup(request):
if 'username' not in request.session:
return redirect('login')
else:
# the following is just going to grab the currently logged in user and
# save the profile information to the appropriate user
username = request.session['username']
currentUser = User.objects.get(username = username)
# the following is the provessing for the form where the user entered
# the profile informaiton
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
first_name = cd['first_name']
last_name = cd['last_name']
dob_month = cd['dob_month']
dob_day = ['dob_day']
dob_year = ['dob_year']
city = cd['city']
state = cd['state']
phone = cd['phone']
privacy = cd['privacy']
# this is the new record that is going to be created and saved
new_profile = Profile.objects.create(
user = currentUser,
first_name = first_name,
last_name = last_name,
dob_month = dob_month,
dob_day = dob_day,
dob_year = dob_year,
city = city,
state = state,
phone = phone,
privacy = privacy,
)
return redirect('home_page')
else:
# this is what is going to be saved into the html file and used to
# render the file
form = ProfileForm()
message = 'fill out form below'
parameters = {
'form':form,
'currentUser':currentUser,
'message':message,
}
return render(request, 'tabs/profile_setup.html', parameters)

Let's say your model name is User.
forms.py:
from .models import User
class UserForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UserForm, self).__init__(*args, **kwargs)
class Meta:
model = User
fields = '__all__'
and views.py:
def user_create(request):
form = UserForm(request.POST or None)
if request.method == 'POST':
form = UserForm(request.POST or None)
if not form.is_valid():
print form.errors
return render(request, 'user_create.html', {'form': form})
else:
first_name = form.cleaned_data.get("first_name")
last_name = form.cleaned_data.get("last_name")
# pass your extra fields here
new_user = User.objects.create_user(
user=user,
first_name=first_name,
last_name=last_name,
)
new_user.save()
return redirect('where you want to redirect',)
return TemplateResponse(request, 'user_create.html')
finally user will be save.
Read docs:https://docs.djangoproject.com/en/1.11/topics/forms/modelforms/

Related

Django - MultiValueKeyError in form when running test

I have a CustomUser model, using django's auth for authentication, and a custom signup view. In the signup form I have some validation to check that the email_suffix (domain of the email) matches with the district that they select in the form. I also check that the email is unique.
When running a test on this, I get an error on the form:
raise MultiValueDictKeyError(key)
django.utils.datastructures.MultiValueDictKeyError: 'district'
Model
class CustomUser(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
is_student = models.BooleanField('student status', default=False)
is_teacher = models.BooleanField('teacher status', default=False)
SD23 = 'SD23'
SD39 = 'SD39'
SD67 = 'SD67'
SDISTRICT = [
(SD23, 'Kelowna SD23'),
(SD39, 'Vancouver SD39'),
(SD67, 'Summerland SD67'),
]
district = models.CharField(
max_length=4, choices=SDISTRICT, blank=True, default='SD39')
paper = models.BooleanField(default=False)
def __str__(self):
return self.username
View
def signup(request):
if request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
to_email = form.cleaned_data.get('email')
# make the username the same as the email
user.username = str(to_email)
user.is_teacher = True
user.is_staff = True
user.is_active = False
user.save()
group = Group.objects.get(name='teacher')
user.groups.add(group)
current_site = get_current_site(request)
print(urlsafe_base64_encode(force_bytes(user.pk)))
sendgrid_client = SendGridAPIClient(
api_key=os.environ.get('SENDGRID_API_KEY'))
from_email = From("doug#smartmark.ca")
to_email = To(to_email)
subject = "Activate your SmartMark Account"
active_link = render_to_string('account/acc_active_email_link.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
html_text = f'Hello {user}<br/><p>Please click on the link below to confirm</p>{active_link}'
html_content = HtmlContent(html_text)
mail = Mail(from_email, to_email, subject,
html_content)
response = sendgrid_client.send(message=mail)
return redirect(reverse('accounts:account_activation_sent'))
else:
form = CustomUserCreationForm()
return render(request, 'account/signup.html', {'form': form})
Form
class CustomUserCreationForm(UserCreationForm):
""" form from class based view """
paper = forms.BooleanField(
label='I agree that keeping a backup paper gradebook is best practice')
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
class Meta:
model = get_user_model()
fields = ('email', 'first_name', 'last_name', 'district', 'paper')
def signup(self, request, user):
user.district = self.cleaned_data['district']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.paper = self.cleaned_data['paper']
user.email = self.cleaned_data['email']
def check_suffix(self, e, d):
email_domain = e.split("#", 2)[1]
t_suffix = email_creation(d)[0] # method which takes the 'district' and creates an email suffix
print(email_domain)
print(t_suffix)
if email_domain == t_suffix:
return True
else:
return False
def clean_email(self):
value = self.cleaned_data["email"]
value_district = self.data["district"]
if not value:
raise forms.ValidationError('An Email address is required.')
check_users = CustomUser.objects.filter(email__iexact=value)
if check_users:
raise forms.ValidationError('This email is already in use.')
if value and not check_users:
if not self.check_suffix(value, value_district):
self.add_error(
"email", "Your email address does not match your school district.")
return value
email_creation method
def email_creation(school_district):
if school_district == "SD23":
teacher_suffix = "sd23.bc.ca"
student_suffix = "learn.sd23.bc.ca"
email_prefix = True
elif school_district == "SD39":
teacher_suffix = "vsb.bc.ca"
student_suffix = "learn.vsb.bc.ca"
email_prefix = True
elif school_district == "SD67":
teacher_suffix = "sd67.bc.ca"
student_suffix = teacher_suffix
email_prefix = True
return(teacher_suffix, student_suffix, email_prefix)
Test
def test_signup_endpoint(self):
email = "foo#vsb.bc.ca"
result = self.client.post('/accounts/signup/', {'email': email})
self.assertEqual(result.status_code, 200)
created_user = get_user_model().objects.get(email=email)
self.assertTrue(created_user.is_active ==
False, created_user.to_dict())
The check_suffix might seem a bit convoluted but the MultiValueDictKeyError is happening before this method is called. The problem seems to be the `self.data['district'], it doesn't like the choice? Do I need to set/define this choice/field in my test? I tried that by adding the following in the test, but it didn't change the error.
email = "foo#vsb.bc.ca"
district = "SD39"

Django Forn Not Saving Extra Information

I extended the Django AbstratUser so that users can use email to sign in and signup, these work perfectly. The problem I am facing, however, is that the extra information on the extended model is not storing the information in the database, even though the user gets created. Once I hit the submit button, the user and extended model get created, and while the user model stores the information, the extended model is always empty.
I have tried using both signals and #transaction_atomic, yet, I have not been able to figure it out. Maybe I am missing out something, I do not know.
Models.py
class Company(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True)
name= models.CharField(_('Company name'), max_length=250)
...
#more information
...
class Meta:
verbose_name = _('Company')
verbose_name_plural = _('Companies')
def __str__(self):
return self.name
forms.py
class CompanySignUpForm(CustomUserCreationForm):
name = forms.CharField(widget=TextInput(attrs={'placeholder': 'Company name'}))
...
#more fields
...
class Meta(CustomUserCreationForm.Meta):
model = User
#transaction.atomic
def save(self):
user = super().save(commit=False)
user.is_company = True
user.save()
company = Company.objects.create(user=user)
company.name = self.cleaned_data.get('name')
...
#more information
...
return user
Views.py
def company_signup(request):
if request.method == 'POST':
form = CompanySignUpForm(request.POST)
if form.is_valid():
form.save()
return render(request, 'accounts/templates/company_success.html')
else:
form = CompanySignUpForm()
return render(request, 'accounts/templates/company_signup.html', context={
'title': _('Create a Company Account'),
'form': form,
})
Edit:
Thanks to #Mandrup, I was able to extend his solution to fit my need.
forms.py
class CompanySignUpForm(CustomUserCreationForm):
name = forms.CharField(widget=TextInput(attrs={'placeholder': 'Company name'}))
number_of_employees = forms.CharField(widget=NumberInput(attrs={'placeholder': 'Number of employees'}))
phone = forms.CharField(widget=TextInput(attrs={'placeholder': 'Contact Number'}))
country = forms.ModelChoiceField(queryset=Country.objects.all(), required=True, empty_label="Country")
class Meta(CustomUserCreationForm.Meta):
model = User
#transaction.atomic
def save(self, commit=True):
user = super(CompanySignUpForm, self).save(commit=False)
if commit:
user.is_company = True
user.save()
name = self.cleaned_data.get('name')
number_of_employees = self.cleaned_data.get('number_of_employees')
phone = self.cleaned_data.get('phone')
country = self.cleaned_data.get('country')
company = Company(user=user, name=name, number_of_employees=number_of_employees, phone=phone, country=country)
company.save()
return user
Edit:
This worked for me when i tried to create an extended user profile. I changed it to fit your needs.
Model:
class Company(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True)
name= models.CharField(max_length=250)
...
#more information
...
def __str__(self):
return self.name
Form:
class RegisterUserForm(UserCreationForm):
class Meta:
model = User
fields = ["username", "email", "password1", "password2"]#add whatever fields you want to here
def save(self, commit=True):
user = super(RegisterUserForm, self).save(commit=False)
if commit:
user.save()
company = Company(user=user, name='Company name')
company.save()
return user

Using a registration form to add to custom user fields (django)

I'm creating custom user models for a registration form in django, but I'm having some problems getting the data into the database. Currently the users can register and their username, password, email, first name and last name are saved, but all the other form data isn't saving into the object. Below are my forms and the output:
Models.py
class Profile(models.Model):
user = models.OneToOneField(User)
gender = models.CharField(max_length=20)
medication = models.CharField(max_length=50, blank=True)
medical_history = models.CharField(max_length=50,blank=True)
DOB = models.CharField(max_length=20)
telephone = models.CharField(max_length=20)
address = models.CharField(max_length=30)
city = models.CharField(max_length=20)
state = models.CharField(max_length=20)
postcode = models.CharField(max_length=30)
forms.py:
class CreateAccountForm(ModelForm):
class Meta:
model = Profile
fields = ("username","password","password2","first_name","last_name",
"gender","medication","medical_history","DOB","email","telephone",
"address","city","state","postcode")
views.py:
def create_account(request):
form = CreateAccountForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
password2 = form.cleaned_data['password2']
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
gender = form.cleaned_data['gender']
medication = form.cleaned_data['medication']
medical_history = form.cleaned_data['medical_history']
DOB = form.cleaned_data['DOB']
email = form.cleaned_data['email']
telephone = form.cleaned_data['telephone']
address = form.cleaned_data['address']
city = form.cleaned_data['city']
state = form.cleaned_data['state']
postcode = form.cleaned_data['postcode']
if password == password2:
if (password_verification(password)) == 3:
if (username_verification(username)) == False:
form.save()
return HttpResponseRedirect('/login')
else:
return HttpResponseRedirect('/create_account')
else:
return HttpResponseRedirect('/create_account')
else:
return HttpResponseRedirect('/create_account')
return render(request, "create_account.html", {'form': form})
In the django admin window, the user is registering to the database with the create_user fields, but none of the added custom fields are saving in the available columns. Any help would be great this is really bugging me. Below is a pic of the empty fields, cheers!
You are saving User only user.save() so other Profile ( please change your user table to something meaningful Profile.
And also you don't need password first_name last_name email in your profile as well.
And I'll suggest to use the ModelForm to save the Profile table.
user_form = CreateAccountForm(request.POST)
profile_form = ProfileForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
# save the form after your password check
user_form.save()
profile_form.save()

what causes the weird "UNIQUE constraint failed: auth_user.username" error?

I try to insert data in user model into other model by one to one relationship. In specific, I want insert username,email and password attributes of User into other models.In Addtional, I intend to create both User model and other model in one form. So, I override the save method in modelform. It works partially and be able to insert data in both models and databases, except throw a UNIQUE constraint failed: auth_user.username error.
In models.py
class Staff(models.Model):
yes_or_no = ((True, 'Yes'),(False, 'No'))
male_or_female = ((True,'Male'),(False,'Female'))
user = models.OneToOneField(User, unique=True)
gender = models.BooleanField(default = True, choices = male_or_female)
birthday = models.DateField(default =None,blank = False, null = False)
created = models.DateTimeField(default=datetime.now, blank=True)
authorized = models.BooleanField(default=False,choices = yes_or_no)
store_id = models.ForeignKey(Store,default=1)
#property
def name(self):
return self.user.username
#property
def email(self):
return self.user.email
#property
def password(self):
return self.user.password
#property
def first_name(self):
return self.user.first_name
#property
def last_name(self):
return self.user.last_name
def __str__(self):
return self.user.username
In forms.py
class StaffForm(forms.ModelForm):
name = forms.CharField(max_length=100)
email= forms.EmailField(max_length=100, required=True)
password = forms.CharField(max_length=50)
store_id = forms.ModelChoiceField(queryset = Store.objects.all(),empty_label="--------") # select values ?
first_name = forms.CharField(required = True,max_length=100)
last_name = forms.CharField(required = True,max_length=100)
class Meta:
model = Staff
fields = ('gender','birthday','authorized','store_id')
widgets = {'authorized':forms.RadioSelect,
'gender':forms.RadioSelect,
'birthday':SelectDateWidget(years=range(date.today().year-50,date.today().year))
}
def save(self,*args,**kwargs):
Staff = super(StaffForm,self).save(commit=False)
user = User.objects.create(
username=self.cleaned_data['name'],
first_name=self.cleaned_data['first_name'],
last_name = self.cleaned_data['last_name'],
email= self.cleaned_data['email'])
user.set_password(self.cleaned_data['password'])
if self.cleaned_data['authorized']:
user.is_staff = True
Staff.user = user
Staff.save()
In views.py
#login_required(login_url='/dataInfo/login/')
def createstaff(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = StaffForm(request.POST or None)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
form.save()
return HttpResponseRedirect('/dataInfo/staff_view/')
# if a GET (or any other method) we'll create a blank form
else:
form = StaffForm()
return render(request, 'dataInfo/create_staff.html', {'form': form})

Form validation error message is not shown in ModelForm

I have a Model like this:
class Client(models.Model):
user = models.OneToOneField(User)
# True if the signed up user is client
is_client = models.BooleanField(default=True)
# Which company the client represents
company = models.CharField(max_length=200, null=True)
# Address of the company
address = models.CharField(max_length=200, null=True)
company_size = models.ForeignKey(CompanySize, null=True)
account_type = models.ForeignKey(AccountType)
billing_address = models.CharField(max_length=254, null=True)
ModelForm of the above model looks like this:
class ProfileForm(ModelForm):
class Meta:
model = Client
exclude = ['user', 'is_client']
def clean(self):
cleaned_data = super(ProfileForm, self).clean()
if not cleaned_data:
raise forms.ValidationError("Fields are required.")
return cleaned_data
In my views, I am doing like this:
def post(self, request, user_id):
# Get the profile information from form, validate the data and update the profile
form = ProfileForm(request.POST)
if form.is_valid():
account_type = form.cleaned_data['account_type']
company = form.cleaned_data['company']
company_size = form.cleaned_data['company_size']
address = form.cleaned_data['address']
billing_address = form.cleaned_data['billing_address']
# Update the client information
client = Client.objects.filter(user_id=user_id).update(account_type=account_type, company=company,
company_size=company_size, address=address, billing_address=billing_address)
# Use the message framework to pass the message profile successfully updated
#messages.success(request, 'Profile details updated.')
return HttpResponseRedirect('/')
else:
profile_form = ProfileForm()
return render(request, 'website/profile.html', {'form': profile_form})
If all the forms data are filled, it successfully redirects to / but if data are not filled it redirects to website/profile.html with the form. But error messages All fields are required are not shown. What's wrong?
Your error is that you are creating a new form when you want to send the error to template, you need send your object "form" and not "profile_form" for include the error information.
Regards.