Getting this error message when running manage.py
AttributeError at /accounts/signup/teacher/ 'str' object has no
attribute 'add'
This is the code I have written->
forms.py
class TeacherSignUpForm(UserCreationForm):
email = forms.EmailField(max_length=100)
firstname = forms.CharField(max_length=100)
lastname = forms.CharField(max_length=100)
phonenumber = forms.IntegerField(required=True)
linkedin = forms.URLField(max_length=200)
class Meta(UserCreationForm.Meta):
model = User
def save(self, commit=True):
user = super().save(commit=False)
user.is_teacher = True
if commit:
user.save()
mentor = Mentor.objects.create(user=user)
mentor.email.add(*self.cleaned_data.get('email'))
mentor.firstname.add(*self.cleaned_data.get('firstname'))
mentor.lastname.add(*self.cleaned_data.get('lastname'))
mentor.phonenumber.add(*self.cleaned_data.get('phonenumber'))
mentor.linkedin.add(*self.cleaned_data.get('linkedin'))
return user
models.py
#mentor model
class Mentor(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
email = models.EmailField(max_length=100)
firstname = models.CharField(max_length=100)
lastname = models.CharField(max_length=100)
linkedin = models.URLField(max_length=200,null=True,blank=True)
phonenumber = models.IntegerField(null=True,unique=True)
and views
class TeacherSignUpView(CreateView):
model = User
form_class = TeacherSignUpForm
template_name = 'registration/signup_form.html'
def get_context_data(self, **kwargs):
kwargs['user_type'] = 'teacher'
return super().get_context_data(**kwargs)
def form_valid(self, form):
user = form.save()
login(self.request, user)
return redirect('teachers:app-instructor-dashboard')
I get this error message when I try and login as a mentor/teacher. Which should then redirect me to app-instructor-dashboard
Your view does not make much sense. An EmailField and a UrlField are not much more than CharFields with some extra validation. These are not collections (lists, etc.) of emails.
You thus should assign the values like:
class TeacherSignUpForm(UserCreationForm):
email = forms.EmailField(max_length=100)
firstname = forms.CharField(max_length=100)
lastname = forms.CharField(max_length=100)
phonenumber = forms.IntegerField(required=True)
linkedin = forms.URLField(max_length=200)
class Meta(UserCreationForm.Meta):
model = User
def save(self, commit=True):
self.instance.is_teacher = True
user = super().save()
mentor = Mentor.objects.create(
user=user,
email=self.cleaned_data['email'],
firstname=self.cleaned_data['firstname'],
lastname=self.cleaned_data['lastname'],
phonenumber=self.cleaned_data['phonenumber'],
linkedin=self.cleaned_data['linkedin']
)
return user
Note that it will be necessary to first save the user object. A User object that is not created at the database side, can not be used to create a Mentor object, since then it has no primary key to work with.
Related
Unable to add a new customer to the database..
I made a class Named customer that has a one-to-one relationship with a class named User that is an AbstractUser
I want to send the data through rest API so that I can create a new customer in the customer table and a new user that is One To One Related to the customer from the same view.
User Model
class User(AbstractUser):
# Add additional fields here
id = None
email = models.EmailField(max_length=254, primary_key=True)
name = models.CharField(max_length=100)
password = models.CharField(max_length=100)
is_patient = models.BooleanField(default=False)
is_doctor = models.BooleanField(default=False)
is_homesampler = models.BooleanField(default=False)
is_pathologist = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now=True)
first_name = None
last_name = None
username = None
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name', 'password']
objects = CustomUserManager()
def __str__(self):
return self.email
# Ensure that the password is hashed before saving it to the database
def save(self, *args, **kwargs):
self.password = make_password(self.password)
super(User, self).save(*args, **kwargs)
def has_perm(self, perm, obj=None):
return self.is_superuser
User Serializer
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
# fields = (['id', 'username', 'email', 'name'])
fields = '__all__'
customer Model
class customer(models.Model):
user = models.OneToOneField(
get_user_model(), on_delete=models.CASCADE, primary_key=True)
real = models.BooleanField(default=False)
def __str__(self):
return self.user.name
Customer Serializer
class CustomerSerializer(serializers.ModelSerializer):
userdata = UserSerializer(read_only=True, source='user')
class Meta:
model = customer
fields = '__all__'
def create(self, validated_data):
user_data = validated_data.pop('user')
user = get_user_model().objects.create(**user_data)
user.is_Patient = True
customer = customer.objects.create(user=user, **validated_data)
return customer
Create Customer View
# Create add customer API
#api_view(['POST'])
def addCustomer(request):
customer_serializer = CustomerSerializer(data=request.data)
if(customer_serializer.is_valid()):
customer_serializer.save()
print(customer_serializer.errors)
return Response({'message': 'okay'})
Body of API Call
{
"email" : "test#test.com",
"password": "Abc"
}
So the question is how can I create a view so that I can create a new user and a customer using just one API Call
Your call body doesn't match CustomerSerializer.
CustomerSerializer fields are "user" and "rest", so you only can pass these two unless you do something like these:
class CustomerSerializer(serializers.ModelSerializer):
userdata = UserSerializer(read_only=True, source='user')
email = serializers.EmailField(write_only=True)
password = serializers.CharField(write_only=True)
class Meta:
model = customer
fields = ["userdata", "email", "password", "id", "real"]
def create(self, validated_data):
email = validated_data.pop("email")
password = validated_data.pop("password")
user = get_user_model().objects.create(**{
"email": email,
"password": password
})
user.is_Patient = True
customer = customer.objects.create(user=user, **validated_data)
return customer
About the create method, it won't function correctly:
Because:
We shouldn't use create to create a new user instead we should use create_user More
I noticed that you removed the username so this method would be useless :)
After user.is_Patient = True, you forgot to save the user
The correct code would be:
class CustomerSerializer(serializers.ModelSerializer):
userdata = UserSerializer(read_only=True, source='user')
email = serializers.EmailField(write_only=True)
password = serializers.CharField(write_only=True)
class Meta:
model = customer
fields = ["userdata", "email", "password", "id", "real"]
def create(self, validated_data):
email = validated_data.pop("email")
password = validated_data.pop("password")
user = get_user_model().objects.create(email=email)
user.set_password(password)
user.is_Patient = True
user.save()
customer = customer.objects.create(user=user, **validated_data)
return customer
NOTE 1:
# Ensure that the password is hashed before saving it to the database
def save(self, *args, **kwargs):
self.password = make_password(self.password)
super(User, self).save(*args, **kwargs)
It is the wrong approach to make_password here because whenever you make a change in your user, it would run.
the ideal approach would be using user.set_password("new_pass") whenever you get a new password from the user.
NOTE 2:
When you pass read_only to a serializer, this means would be ignored if you passed it as data to the serializer.
About write_only, it's the opposite of read_only. It would not be returned if you called serializer.data. For example, we only want to write to the password, and we won't want to read it from the serializer, so we made it write_only.
UPDATE: Adding a name
You have to add a write_only field and then pass it to create method
class CustomerSerializer(serializers.ModelSerializer):
userdata = UserSerializer(read_only=True, source='user')
email = serializers.EmailField(write_only=True)
password = serializers.CharField(write_only=True)
name = serializers.CharField(write_only=True)
class Meta:
model = customer
fields = ["userdata", "email", "password", "id", "real", "name"]
def create(self, validated_data):
email = validated_data.pop("email")
password = validated_data.pop("password")
name = validated_data.pop("name")
user = get_user_model().objects.create(email=email, name=name)
user.set_password(password)
user.is_Patient = True
user.save()
customer = customer.objects.create(user=user, **validated_data)
return customer
I recently decided to update my forms.py file of my Django project to make one of the fields into a drop down menu rather than an empty text box. In my forms.py file, I changed the class for customers from;
class CustomerSignUpForm(UserCreationForm):
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
email_address = forms.EmailField(required=True)
membership_tier = forms.CharField(required=True)
class Meta(UserCreationForm.Meta):
model = User
#transaction.atomic
def data_save(self):
user = super().save(commit=False)
user.first_name = self.cleaned_data.get('first_name')
user.last_name = self.cleaned_data.get('last_name')
user.is_customer = True
user.save()
customer = Customer.objects.create(user=user)
customer.email_address = self.cleaned_data.get('email_address')
customer.membership_tier = self.cleaned_data.get('membership_tier')
customer.save()
return user
to the following
class CustomerSignUpForm(UserCreationForm):
member_tiers = (
'Basic',
'Intermediate',
'Beast'
)
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
email_address = forms.EmailField(required=True)
membership_tier = forms.CharField(choices = member_tiers, default = 'Basic', required=True)
class Meta(UserCreationForm.Meta):
model = User
#transaction.atomic
def data_save(self):
user = super().save(commit=False)
user.first_name = self.cleaned_data.get('first_name')
user.last_name = self.cleaned_data.get('last_name')
user.is_customer = True
user.save()
customer = Customer.objects.create(user=user)
customer.email_address = self.cleaned_data.get('email_address')
customer.membership_tier = self.cleaned_data.get('membership_tier')
customer.save()
return user
And here is my customer class in my models.py as well if that will help,
class Customer(models.Model):
member_tiers = (
'Basic',
'Intermediate',
'Beast'
)
username = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
email_address = models.EmailField(max_length=30)
membership_tier = models.CharField(max_length = 30, choices = member_tiers, default = 'Basic')
What my question boils down to is: Did I make the correct changes to my forms.py file and if not, what can I take away from this to learn for next time?
forms.CharField does not have a choices argument. See the documentation about this type of field.
You want a ChoiceField
My following question is about how I can develop a function that I can compare a POST request data (ModelForm) and existing data of model in queryset.
This is mi models.py:
class Employee(models.Model):
dni = models.CharField(max_length=9, null=False, blank=False, default="12345678R")
name = models.CharField(max_length=7)
surname = models.CharField(max_length=8)
email = models.CharField(max_length=20)
telefone_number = models.IntegerField()
user_nick = models.CharField(max_length=10, null=False, blank=False, default="user")
password = models.CharField(max_length=20, null=False, blank=False, default="password")
ticket = models.ManyToManyField(Ticket)
forms.py (EmployerLoginForm only to user_nick and password):
class EmployerForm(forms.ModelForm):
class Meta:
model = Employee
fields = "__all__"
class EmployerLoginForm(forms.ModelForm):
class Meta:
model = Employee
exclude = ['dni', 'name', 'surname', 'email', 'telefone_number', 'ticket']
In this case, to develop login function I am using the EmployerLoginForm in views.py:
_logger = nexus_services_logs.Logging(statics.NEXUS_VIEWS_LOGGING_NAME)
_views_manager_service = nexus_services_views_manager.ViewsManagerService()
_auth = nexus_services_auth.Authentication()
class IndexView(View):
def post(self, request, *args, **kwargs):
form = EmployerLoginForm(request.POST)
if(_auth.check_model_employer_authentication(form, _logger, _views_manager_service)):
if(_views_manager_service.validate_form(form, _logger)):
_views_manager_service.save_form(form, _logger)
return redirect('employerPortal')
else:
return redirect('index')
check_model_employer_authentication(form, _logger, _views_manager_service) is the function where I want compare form data and queryset. I find the problem when I cannot compare the objects using for loop (in auth.py):
class Authentication():
def __init__(self):
self.employer_exist = False
def check_model_employer_authentication(self, model, logger, views_manager_service):
queryset_all_employers = Employee.objects.order_by("id")
context_exployers = views_manager_service.build_context_queryset_employers(queryset_all_employers)
for employer in context_exployers["employers"]:
if(employer.user_nick == model.user_nick and employer.password == model.password):
self.employer_exist = True
logger.info_log("Exist nick with similar password")
return True
else:
logger.error_log("Nick or password not exist or coincidence with object in db")
return False
I have tried using a context but not works.
i am trying to save the current user in forms.py using save() method
can you please help me to solve this problem
here is my models.py
models.py
class Warden(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
firstName = models.CharField(max_length=30,null=True)
lastName = models.CharField(max_length=30,null=True)
email = models.EmailField(null=True)
phone_number = models.CharField(max_length=12 ,null=True)
hostel_name=models.CharField(max_length=20,null=True)
profile_image = models.ImageField(default="logo-2.png",upload_to='users/', null=True, blank=True )
def __str__(self):
return self.email
class HostelStaff(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
firstName = models.CharField(max_length=30,null=True)
lastName = models.CharField(max_length=30,null=True)
email = models.EmailField(null=True)
phone_number = models.CharField(max_length=12 ,null=True)
hostel_name=models.CharField(max_length=100)
#this is forignkey in which i want to save logged user
warden = models.ForeignKey(Warden, on_delete=models.CASCADE)
profile_image = models.ImageField(default="logo-2.png",upload_to='users/', null=True, blank=True )
def __str__(self):
return self.firstName + ' ' + self.lastName
this is my forms.py wher i overide save method
forms.py
class StaffSignUpForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
fields = ('username',)
def save(self):
user = super().save(commit=False)
user.is_hostelstaff = True
user.save()
return user
def __init__(self, *args, **kwargs):
super(StaffSignUpForm, self).__init__(*args, **kwargs)
self.fields['username'].widget.attrs['placeholder'] = ' username'
self.fields['password1'].widget.attrs['placeholder'] = ' password'
self.fields['password2'].widget.attrs['placeholder'] = ' confirm password'
self.helper = FormHelper()
self.helper.form_show_labels = False
for fieldname in ['username','password1', 'password2']:
self.fields[fieldname].help_text = None
class StaffSignUpTwo(forms.ModelForm):
class Meta:
model = HostelStaff
fields = ('firstName', 'lastName','email', 'phone_number', 'hostel_name',)
def __init__(self, user, *args, **kwargs):
super(StaffSignUpTwo, self).__init__(*args, **kwargs)
self.fields['firstName'].widget.attrs['placeholder'] = ' first name'
self.fields['lastName'].widget.attrs['placeholder'] = ' last name'
self.fields['hostel_name'].widget.attrs['placeholder'] = ' hostel name'
self.fields['email'].widget.attrs['placeholder'] = ' email'
self.fields['phone_number'].widget.attrs['placeholder'] = ' phone '
self.helper = FormHelper()
self.helper.form_show_labels = False
#transaction.atomic
def save(self, user):
self.fields['user'] = user
firstName = self.cleaned_data['firstName']
lastName = self.cleaned_data['lastName']
email = self.cleaned_data['email']
phone_number = self.cleaned_data['phone_number']
hostel_name = self.cleaned_data['hostel_name']
hostelstaff = HostelStaff.objects.create(user=user, email=email,firstName=firstName,lastName=lastName,
phone_number=phone_number,hostel_name=hostel_name)
#here is save method
def save(self,pk,commit=True):
obj = super().save(commit=False)
#i think error in this line
obj.warden=Warden.objects.get(user=self.user)
obj.save()
return obj
views.py
def StaffSignUpView(request):
if request.method == 'POST':
main_form = StaffSignUpForm(request.POST)
secondary_form = StaffSignUpTwo(request.user,request.POST)
if main_form.is_valid() and secondary_form.is_valid():
user = main_form.save()
secondary_form.save(request.user)
return redirect('warden_view:warden-home')
else:
main_form = StaffSignUpForm()
secondary_form = StaffSignUpTwo(request.user)
return render(request, 'warden_view/create_staff.html', {
'main_form': main_form,
'secondary_form': secondary_form
})
error scrrenshot
save() method in forms.py unable to save the foreignkey in Django
save() method in forms.py unable to save the foreignkey in Django
save() method in forms.py unable to save the foreignkey in Djangosave() method in forms.py unable to save the foreignkey in Djangosave() method in forms.py unable to save the foreignkey in Djangosave() method in forms.py unable to save the foreignkey in Djangosave() method in forms.py unable to save the foreignkey in Djangosave() method in forms.py unable to save the foreignkey in Djangosave() method in forms.py unable to save the foreignkey in Django
You do not set the value for the object wrapped in the form with:
#transaction.atomic
def save(self, user):
self.fields['user'] = user
# …
But with:
#transaction.atomic
def save(self, user):
self.instance.user = user
# …
as for the warden, it looks like you wrapped this in a function in the .save() method. That is not a good idea either.
You furthermore create a HostelStaff object in the save() method of the form, which of course has no warden field.
#transaction.atomic
def save(self, user):
self.instance.user = user
self.instance.warden, __ = Warden.objects.get_or_create(user=user)
return super().save()
I would however strongly advise against overriding the signature of the save() method, since class-based views, etc. often call these functions too.
Am new using django so i used practical example on this tutorial on extending user model using User Profile, am having trouble on form.py it gives that error, on removing this line;
supervisor.su_mobile_number.add(*self.cleaned_data.get('su_mobile_number'))
it works smoothly but no data for su_mobile_number was inserted o the database
view.py
class SupervisorSignUpView(CreateView):
model = User
form_class = SupervisorSignUpForm
template_name = 'registration/signup_form.html'
def get_context_data(self, **kwargs):
kwargs['user_type'] = 'supervisor'
return super().get_context_data(**kwargs)
def form_valid(self, form):
user = form.save()
login(self.request, user)
return redirect('home')
model.py
class User(AbstractUser):
is_supervisor = models.BooleanField(default=False)
is_student = models.BooleanField(default=False)
class Supervisor(models.Model):
user = models.OneToOneField('User', on_delete=models.CASCADE, primary_key=True, related_name='supervisor')
su_mobile_number = models.CharField(max_length=200)
forms.py
class SupervisorSignUpForm(UserCreationForm):
su_mobile_number = forms.CharField()
class Meta(UserCreationForm.Meta):
model = User
#transaction.atomic
def save(self):
user = super().save(commit=False)
user.is_supervisor = True
user.save()
supervisor = Supervisor.objects.create(user=user)
supervisor.su_mobile_number.add(*self.cleaned_data.get('su_mobile_number'))
return user
Use = operator to assign value and then call save() method
#transaction.atomic
def save(self):
user = super().save(commit=False)
user.is_supervisor = True
user.save()
supervisor = Supervisor.objects.create(user=user)
supervisor.su_mobile_number = self.cleaned_data.get('su_mobile_number')
supervisor.save()
return user
more shorter way is (as #Abdul Niyas P M mentioned)
#transaction.atomic
def save(self):
user = super().save(commit=False)
user.is_supervisor = True
user.save()
supervisor = Supervisor.objects.create(user=user, su_mobile_number=self.cleaned_data.get('su_mobile_number'))
return user