Error saving forms to two different tables - django

This is my form , when i save it , it saves only to the User model but not the Client model in the database , i must be missing something simple but i cant figure it out. The following is the Form and the Client model
class RegisterForm(UserCreationForm):
email = forms.EmailField(label="Email")
fullname = forms.CharField(label="Full name")
type_choice= ( ('Customer','Customer'),('Supplier','Supplier'), )
type=forms.ChoiceField(choices=type_choice)
gender_choice=( ('Male','Male'), ('Female','Female'), )
gender=forms.ChoiceField(choices=gender_choice)
address=forms.CharField(label="Address",initial="Nothing")
phone_number=forms.IntegerField()
class Meta:
model= User
fields = ("username","fullname","email","type","gender","address","phone_number")
def save(self, commit=True):
user = super(RegisterForm, self).save(commit=False)
first_name, last_name = self.cleaned_data["fullname"].split()
user.first_name = first_name
user.last_name = last_name
user.email = self.cleaned_data["email"]
user.type=self.cleaned_data["type"]
user.gender=self.cleaned_data["gender"]
user.address=self.cleaned_data["address"]
user.phone_number=self.cleaned_data["phone_number"]
client= Client(Client_ID=3,Client_FirstName=first_name,Client_PhoneNumber=user.phone_number)
if commit:
user.save()
client.save()
return user,client
This is the Client model
class Client(models.Model):
Client_ID= models.IntegerField(primary_key=True)
Client_FirstName=models.CharField(max_length=30)
Client_LastName=models.CharField(max_length=30)
Client_Gender=models.CharField(max_length=30)
Client_PhoneNumber=models.IntegerField()
Client_Address=models.CharField(max_length=100)
Client_CreditRating=models.FloatField()
edit : I am following this example to insert a new entry into the table

Related

Password Confirmation error not displayed in django forms

I tried to compare password and confirmpassword. If i enter different password it does not raise error and redirects to loginpage.
models.py
class reg1(models.Model):
name=models.CharField(max_length=100)
city=models.CharField(max_length=100)
email=models.CharField(max_length=100)
username=models.CharField(max_length=100)
password=models.CharField(max_length=100)
cpassword=models.CharField(max_length=100)
class Meta:
db_table='reg1'
forms.py
class regform(forms.Form):
name = forms.CharField(max_length=100)
city = forms.CharField(max_length=100)
email = forms.CharField(max_length=100)
username = forms.CharField(max_length=100)
password = forms.CharField(max_length=100)
cpassword=forms.CharField(max_length=100)
def clean_password(self):
if self.data['password'] != self.data['cpassword']:
raise forms.Error('Passwords are not the same')
return self.data['password']
views.py
if myregform.is_valid():
name1 = myregform.cleaned_data['name']
city1 = myregform.cleaned_data['city']
email = myregform.cleaned_data['email']
username1 = myregform.cleaned_data['username']
password1 = myregform.cleaned_data['password']
password2=myregform.cleaned_data['cpassword']
a=reg1(name=name1,city=city1,email=email,
username=username1,password=password1,cpassword=password2)
a.save()
I expect the output as i enter a different password it will show password not matching error
I am using pycharm software and django framework with sqlite3 database.
Use a ModelForm to save yourself a bunch of typing.
You need to use clean() to validate data that relates to other fields.
You need to raise ValidationErrors.
class reg1(models.Model):
name = models.CharField(max_length=100)
city = models.CharField(max_length=100)
email = models.CharField(max_length=100)
username = models.CharField(max_length=100)
password = models.CharField(max_length=100)
cpassword = models.CharField(max_length=100)
class Meta:
db_table = "reg1"
class regform(forms.ModelForm):
class Meta:
model = reg1
exclude = ()
def clean(self, cleaned_data):
if cleaned_data["password"] != cleaned_data["cpassword"]:
raise forms.ValidationError("Passwords are not the same")
return cleaned_data
# ...
if myregform.is_valid():
a = myregform.save()

How to intercept and control saving a Django POST form?

When the user is required to fill his profile, he picks a city from the Google Places Autocomplete and posts the form, in the view I extract the city Id from the Google API based on the posted text (I use the same id as pk in my db) and try to extract a city from my db.
These are the models:
class City(models.Model):
#extracted from the Google API
city_id = models.CharField(primary_key=True, max_length=150)
name = models.CharField(max_length=128, blank=True)
country = models.CharField(max_length=128, blank=True)
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile', primary_key=True)
city = models.ForeignKey(City, blank=True, null=True)
prof_pic = models.ImageField(blank=True, upload_to='profile_pictures')
This is the view:
def createprofile(request):
if request.method =='POST':
user = User.objects.get(username=request.user.username)
user_form = UserForm(data=request.POST, instance=user)
profile_form = UserProfileForm(data=request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
user.save()
profile = profile_form.save(commit=False)
profile.user = user
#brings back the city search result as text
searched_city = request.POST['city']
#brings back city ID from the Google API
searched_city_id = population_script.get_city_json(searched_city.replace(" ", ""))['results'][0]['id']
#If it's a valid city
if searched_city_id != -1:
city = City.objects.get(city_id = searched_city_id)
profile.city = city#this is what I want to happen!
else:
return HttpResponse("There's no such city, please try a different query.")
if 'prof_pic' in request.FILES:#now save the profile pic
profile.prof_pic = request.FILES['prof_pic']
print("PROF PIC IS: " + profile.prof_pic.url)
else:
profile.prof_pic = 'images/anon.png'
profile.save()
if 'next' in request.GET:
return redirect(request.GET['next'])
else:
print (user_form.errors, profile_form.errors)
else:
user_form = UserForm()
profile_form = UserProfileForm()
return render(request,
'excurj/createprofile.html', {'user_form':user_form, 'profile_form':profile_form})
However, I keep receiving an error that what's been posted is just text while the city needs to be a City object. I can save the profile pic ok though.
Cannot assign "'Dubai - United Arab Emirates'": "UserProfile.city"
must be a "City" instance.
edit: these are the forms:
class UserForm(forms.ModelForm):
first_name = forms.CharField(
label = "First Name:",
max_length = 80,
required = True
)
last_name = forms.CharField(
label = "Last Name:",
max_length = 80,
required = True,
)
class Meta:
model = User
fields = ('first_name', 'last_name')
class UserProfileForm(forms.ModelForm):
city = forms.CharField(
label = "Your Current City:",
max_length = 200,
required = True,
)
class Meta:
model = UserProfile
fields = ('city','prof_pic', 'dob', 'sex', 'education', 'career', 'about_you',
'music_movies_books', )
Please provide a related_name to the city field in the UserProfile.
I worked around this by creating a new UserProfile field called city_search_text which saves the searched text thus it of course does not return any error. I then receive it in the POST request and comfortable pull the proper city in the view.
I handled a similar issue by overriding my forms' clean method. Something like the following will work:
def clean(self):
# fix city problem
if self.cleaned_data.get("city") is not None:
self.cleaned_data['city'] = City.objects.get(id=self.cleaned_data.get("city"))
return self.cleaned_data

Django - saving onetonone linked forms at same time not working

I've have the following forms:
class UpdateProfile(forms.ModelForm):
username = forms.CharField(required=True)
email = forms.EmailField(required=True)
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
class Meta:
model = User
fields = ('username', 'email', 'first_name', 'last_name')
def clean_email(self):
username = self.cleaned_data.get('username')
email = self.cleaned_data.get('email')
if email and User.objects.filter(email=email).exclude(username=username).count():
raise forms.ValidationError('This email address is already in use. Please supply a different email address.')
return email
class UserDetailForm (forms.ModelForm):
linked_user = forms.CharField (required = True)
linked_password = forms.CharField (required = True, widget = forms.PasswordInput())
connections = forms.IntegerField (required = True)
class Meta:
model = User_detail
fields = ('linked_user','linked_password','connections')
I'm trying to save them at the same time if both valid using:
if request.method == 'POST':
form = UpdateProfile(request.POST, instance=request.user)
linked_form = UserDetailForm(request.POST, instance=request.user)
if all((form.is_valid(),linked_form.is_valid())):
user = form.save()
linked = linked_form.save(commit=False)
linked.user = user
linked.save()
msg = "Profile Updated"
else:
return error(request)
This is the User_detail model:
class User_detail (models.Model):
user = models.OneToOneField (
User,
on_delete = models.CASCADE
)
linked_user = models.CharField (
verbose_name = 'LinkedIn Username',
max_length = 50,
)
linked_password = models.CharField (
max_length = 50,
verbose_name = 'LinkedIn Password',
)
connections = models.IntegerField (
verbose_name = 'Connections per day',
default = 24,
)
def __unicode__(self):
return u'%s' % (self.user.first_name + ' ' + self.user.last_name)
The first form is being saved, the second isn't and I don't understand what I'm missing
Help much appreciated.
The problem is in linked_form = UserDetailForm(request.POST, instance=request.user). request.user is not an instance of model User_detail.
What is happening is that, django is trying to find the instance in the model and not finding any. You need to provide a valid User_detail instance so that django can update that instance.
Reference: save() method

Django - extra fields for user form

In the site I'm developing I have a form to register users that extends the userCreationForm. Said form only adds fields that are not in the default, but they are in the model such as email, first_name and last_name.
class RegisterForm(UserCreationForm):
email = forms.EmailField(label = "Email", required=True)
first_name = forms.CharField(label = "First name", required = True )
last_name = forms.CharField(label = "Last name", required = True)
class Meta:
model = User
fields = ("username", "first_name", "last_name", "email", "password1", "password2" )
def __init__(self, *args, **kwargs):
super(RegisterForm, self).__init__(*args, **kwargs)
for fieldname in ['username', 'password1', 'password2']:
self.fields[fieldname].help_text = None
My question is if there's a way to add another field like an imagefield, date of birth, etc. so that I can make a more complete user profile? Or do I have to create my own user model?
The Django idiomatic way of adding more fields to the User model is to make a second model where User is a ForeignKey. So:
from django.db import models
from django.contrib.auth.models import User
class MyUser(models.Model):
user = models.ForeignKey(User)
# ... other fields. i.e. imagefield, date of birth (dob), etc ..
# example:
dob = models.DateField()

Mapping a different field OneToOneField in a ModelForm

I have two django models related with a OneToOneField. I'll show the relevant fields:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, db_index=True)
And
class PasswordRecovery(models.Model):
user = models.OneToOneField(User, primary_key=True)
token = models.CharField(default=utils.make_token)
password = models.CharField(max_length=128)
Then I have a form for the PasswordRecovery model
class PasswordRecoveryForm(forms.ModelForm):
password_check = forms.CharField(max_length=128)
class Meta:
model = PasswordRecovery
fields = ('user', 'password', 'password_check')
A few details are omitted here. Tell me if you think they are relevant.
The problem is that the user field shows as a 'select' element and I would like it to be an email field. Instead of being able to chose a user from a lista I want it instead to required the email to be typed.
How can I do this?
Thanks in advance
You should override the clean_user method to pass the User objects
class PasswordRecoveryForm(forms.ModelForm):
user = forms.EmailField(required=True)
password_check = forms.CharField(max_length=128)
class Meta:
model = PasswordRecovery
fields = ('user', 'password', 'password_check')
def clean_user(self):
user_email = self.cleaned_data['user']
if User.objects.get(email__iexact=user_email):
return User.objects.get(email__iexact=user_email)
return None
#If you wanna to fill in the email add this
def __init__(self, *args, **kwargs):
super(PasswordRecoveryForm, self).__init__(*args, **kwargs)
if self.instance:
self.fields['user'].initial = self.instance.user.email