So I have a student model which inherits from AbstractUser. I used 2 forms in one view for registration since I needed email, name and surname to be in my student database (as well as other fields). Now I'm trying to make an update profile view, with 2 forms that I made especially for updating the info. But I think I'm getting it wrong.. might need a little help here. I need the student to be able to update his email (which is from User model) and his photo, phone, name and surname (which are in Student model).
<form method="POST" action="{% url 'profile_edit' %}" class="" >
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Save</button>
</form>
def profile_edit(request):
user = request.user
form1 = UserEditForm(request.POST or None, initial={'email': user.email,
})
form2 = StudentEditForm(request.POST or None, initial={'name': user.student.name,
'surname': user.student.surname,
'phone': user.student.phone,
'photo': user.student.photo})
if request.method == 'POST':
if form1.is_valid() and form2.is_valid():
user.email = request.POST['name']
user.student.name = request.POST['name']
user.student.surname = request.POST['surname']
user.student.phone = request.POST['phone']
user.student.photo = request.POST['photo']
user.save()
return render(request, 'index.html')
context = {
"form1": form1,
"form2": form2
}
return render(request, "registration/profile_edit.html", context)
class UserForm(forms.ModelForm):
email = forms.EmailField(required=True)
password = forms.CharField(label='Password', max_length=32, required=True, widget=forms.PasswordInput)
confirm_password = forms.CharField(label='Confirm', max_length=32, required=True, widget=forms.PasswordInput,
help_text="Passwords must match!")
class StudentForm(forms.ModelForm):
name = forms.CharField(max_length=30, required=True)
surname = forms.CharField(max_length=50, required=True)
student_ID = forms.CharField(required=True, max_length=14, min_length=14)
photo = forms.ImageField(required=True)
phone = forms.CharField(max_length=15, required=True)
class Meta:
model = Student
fields = ('name', 'surname', 'phone', 'student_ID', 'photo')
class UserEditForm(forms.ModelForm):
email = forms.EmailField(required=False)
class Meta:
model = User
fields = ('email',)
class StudentEditForm(forms.ModelForm):
name = forms.CharField(max_length=30)
surname = forms.CharField(max_length=50)
photo = forms.ImageField(required=False)
phone = forms.CharField(max_length=15, required=False)
class Meta:
model = Student
fields = ('name', 'surname', 'phone', 'photo')
Problem is that I am getting no form, so I am either doing something wrong in the view, either the forms.
<form method="POST" action="{% url 'profile_edit' %}" class="" >
{% csrf_token %}
{{ form1.as_p }}
{{ form2.as_p }}
<button type="submit">Save</button>
</form>
according to your context the names of your forms are form1 and form2, so form only wont display any form
You don't need two forms. I have answered your previous question which led to this question.
It will save you from a lot of unnecessary Code.
Related
I am creating a "UsercreationForm" in django.
When I saved the form, it didn't create any entry in database then I debug it and found an error message that Password fields does not match
I don't know what I did wrong. Please help me figure it out.
Here is my forms.py
from django import forms
from accounts.models import Customer, User
from django.contrib.auth.forms import UserCreationForm
from django.core.exceptions import ValidationError
from datetime import datetime
class UserSignup(UserCreationForm):
class Meta:
model = User
fields = ("username","first_name", "last_name", "email")
username = forms.CharField(label="Username", required=True)
first_name= forms.CharField(label="First Name", required=True)
last_name=forms.CharField(label="Last Name", required=False)
email =forms.EmailField(label="Email", required=False)
password1 = forms.CharField(label="Password", required=True)
password2 = forms.CharField(label="Confirm Password", required=True)
def username_clean(self):
username = self.cleaned_data['username'].lower()
new = User.objects.filter(username = username)
if new.count():
raise ValidationError("User Already Exist")
return username
def email_clean(self):
email = self.cleaned_data['email'].lower()
new = User.objects.filter(email=email)
if new.count():
raise ValidationError(" Email Already Exist")
return email
def clean_password2(self):
password1 = self.cleaned_data['password1']
password2 = self.cleaned_data['password2']
if password1 != password2:
raise ValidationError("Password don't match")
return password2
def save(self, commit = True):
user = User.objects.create_user(
self.cleaned_data['username'],
self.cleaned_data['email'],
self.cleaned_data['password1'],
last_login= datetime.now()
)
return user
class AddDetails(forms.ModelForm):
class Meta:
model = Customer
fields = ("age", "phone")
age = forms.IntegerField(label="Age", required=True)
phone = forms.CharField(label="Mobile Number", required=True)
Here is my views.py
from django.shortcuts import render, redirect
from accounts.forms import *
from datetime import datetime
from django.contrib import messages
def usersignup(request):
if request.method=="POST":
# User Sign-up form (username, email, first_name, last_name, password1, password2)
user_form= UserSignup()
# Customer detail form (age and phone number)
details_form = AddDetails(request.POST)
# If both forms are valid
if all((user_form.is_valid(), details_form.is_valid())):
# Saving with commit=False gets you a model object, then you can add your extra data and save it.
user = user_form.save()
customer= details_form.save(commit=False)
# As user is in OnetoOne Relationship with customer
customer.user= user
customer.save()
messages.success(request, 'Account created successfully')
# return redirect('details')
# if a GET (or any other method) we'll create a blank form
user_form =UserSignup()
details_form= AddDetails()
return render(request, 'registration_form.html', {'user_form': user_form, 'details_form': details_form})
Here is registration_form.html
{% extends 'base.html' %}
{% block content %}
<div class = "login">
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
<h1>Sign up for new account</h1>
<form method="post" >
{% csrf_token %}
<table>
{{user_form.as_table}}
{{details_form.as_table}}
<tr>
<td></td>
<td><input type="submit" name="submit" value="Register" /></td>
</tr>
</table>
</form>
</div>
{% endblock content %}
Here are my models
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
class Customer(models.Model):
user= models.OneToOneField(User, on_delete=models.CASCADE)
age= models.IntegerField(blank=True)
phone= models.CharField(max_length=15, blank=False, null=False)
def __str__(self):
return self.user.first_name
Both passwords are matched. but still getting errors.
I think, this is because of your if condition in the usersignup view, try some modifications in it, for checking both form validation try changing it to if user_form.is_valid() and details_form.is_valid():, in the following way:
views.py
def usersignup(request):
if request.method == "POST":
# User Sign-up form (username, email, first_name, last_name, password1, password2)
user_form = UserSignup(request.POST)
# Customer detail form (age and phone number)
details_form = AddDetails(request.POST)
# If both forms are valid
if user_form.is_valid() and details_form.is_valid():
# Saving with commit=False gets you a model object, then you can add your extra data and save it.
user = user_form.save()
customer = details_form.save(commit=False)
# As user is in OnetoOne Relationship with customer
customer.user = user
customer.save()
messages.success(request, 'Account created successfully')
# return redirect('details')
# if a GET (or any other method) we'll create a blank form
user_form = UserSignup()
details_form = AddDetails()
return render(request, 'home/registration_form.html', {'user_form': user_form, 'details_form': details_form})
Note: Function based views are generally written in snake_case not in smallcase, it will be better if you changed it to user_sign_up from usersignup.
i want the user to be able to see what the current value of the field is, while submitting another value
forms.py:
class CustomerInfoForm(forms.Form):
first_name = forms.CharField(
label="Firstname",
widget=widgets.TextInput(),
required=False,
)
last_name = forms.CharField(
label="Lastname",
widget=widgets.TextInput(),
required=False,
)
views.py: (authentication by phone number)
#login_required
def customer_panel_info_view(request):
info_form = CustomerInfoForm(request.POST or None)
if request.user.is_authenticated:
user_phone_number = request.user.phone_number
if info_form.is_valid():
first_name = info_form.cleaned_data.get("first_name")
last_name = info_form.cleaned_data.get("last_name")
customer = User.objects.get(phone_number=user_phone_number)
customer.first_name = first_name
customer.last_name = last_name
customer.save()
context = {
"info_form": info_form,
}
return render(request, "panel/info.html", context)
the template:
<form action="" method="post">
{% csrf_token %}
{% info_form %}
<button type="submit" class="btn btn-success">submit</button>
</form>
here is the flow:
user goes to this form and wants to add, change or delete a piece of information(this is a piece of the whole template. actually it contains gender birthdate and other things). I want the fields to have the current value so user knows which fields already has a value
If you'd like to avoid ModelForm, you can achieve this through the initial parameter.
#login_required
def customer_panel_info_view(request):
initial = {"first_name": request.user.first_name, "last_name": request.user.last_name})
info_form = CustomerInfoForm(request.POST) if request.method == "POST" else CustomerInfoForm(initial=initial)
if info_form.is_valid():
first_name = info_form.cleaned_data.get("first_name")
last_name = info_form.cleaned_data.get("last_name")
request.user.first_name = first_name
request.user.last_name = last_name
request.user.save()
context = {
"info_form": info_form,
}
return render(request, "panel/info.html", context)
Note, I also removed the logic that refetched the user. If you're using login_required the user will always be authenticated.
I recommend you to use the ModelForm Class https://docs.djangoproject.com/en/3.2/topics/forms/modelforms/
Regarding the method customer_panel_info_view , you're using the decorator login_required , so the user is always authenticated.
this is my code:
views.py
class SignUpView(generic.CreateView):
form_class = SignUpForm
success_url = reverse_lazy('login')
template_name = 'registration/signup.html'
forms.py
class SignUpForm(UserCreationForm):
first_name = forms.CharField(max_length=30, required=True, help_text='Required.')
last_name = forms.CharField(max_length=30, required=True, help_text='Required.')
email = forms.EmailField(max_length=254, required=True , help_text='Required.')
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password1', 'password2',)
class ProfileForm(forms.ModelForm):
location = forms.CharField(max_length=200, required=True, help_text='Required.')
phone = forms.CharField(max_length=10, required=True, help_text='Required.')
class Meta:
model = Profile
fields = ('location','phone')
i don't know how to extend signupform with profileform, i want user to submit together since signup
You can do it like :-
forms.py
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class SignUpForm(UserCreationForm):
email = forms.EmailField(max_length=200)
password1 = forms.CharField(widget=forms.PasswordInput())
username = forms.CharField(help_text=False)
first_name = forms.CharField(max_length=25)
address = forms.CharField(max_length=200)
phone = forms.IntegerField()
gender = forms.ChoiceField(choices=GENDER_CHOICES)
age = forms.IntegerField()
class Meta:
model = User
fields = (
'first_name',
'address',
'phone',
'gender',
'age',
'email',
'username',
)
signup.html
{% extends "mains/base.html" %}
{% block content %}
<form method="post" action="{% url 'users:signup_view' %}">
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Register</button>
</form>
{% endblock content %}
(The code is Successfully Tested and Worked)
You can also use Django Crispy Forms to look forms more beautiful and decent.
View.py
class Register(TemplateView):
template_name = 'registration.html'
def get(self, request, *args, **kwargs):
form = CreateForm()
return render(request, self.template_name, {'form': form})
#staticmethod
def post(request):
try:
data = request.POST.get
user = User(
first_name=data('first_name'),
last_name=data('last_name'),
username=data('username').strip(),
email=data('email'),
)
user.set_password(data('password').strip())
user.save()
request.session["user_id"] = user.id
return HttpResponse(' Save successfully ')
except Exception as c:
return HttpResponse("Failed : {}".format(c), 500)
Form.py
role_choice= (("Customer", "Customer"), ("Employee", "Employee"))
class CreateForm(forms.Form):
first_name = forms.CharField(label="Enter Your First Name", max_length=30, required=True)
last_name = forms.CharField(label="Enter Your Last Name", max_length=30, required=True)
username = forms.CharField(required=True, widget=forms.TextInput())
email = forms.CharField(required=True, widget=forms.TextInput())
password = forms.CharField(required=True, widget=forms.PasswordInput())
role = forms.ChoiceField(choices=role_choice, widget=forms.RadioSelect())
class Customer(forms.Form):
contact = forms.IntegerField(label="Enter your contact number", required=True, )
amount = forms.IntegerField(required=True, min_value=500)
type = forms.ChoiceField(choices=choice)
Model.py
class Customers(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
contact = models.BigIntegerField()
amount = models.BigIntegerField()
type = models.CharField(max_length=1)
Template
{% extends "home.html" %}
{% load crispy_forms_tags %}
{% block title %}Create Account{% endblock %}
{% block content %}
<div>
{% csrf_token %}
{{ form|crispy }}
<button type="submit">Submit</button><br>
</div>
{% endblock %}
After the registration when user select customer option after sumbit the form i go to customer page if user select employee option he/she go to employee page but i don't know how to do this
First of all, I strongly advice not to write all the views, etc. yourself. Django already has a lot of tooling inplace. It has a UserCreationForm [Django-doc] that can be slighly modified. For example:
# app/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
class RoleUserCreationForm(UserCreationForm):
ROLES = (
('Customer', 'Customer'),
('Employee', 'Employee')
)
role = forms.ChoiceField(choices=ROLES, widget=forms.RadioSelect())
class Meta(UserCreationForm.Meta):
fields = (*UserCreationForm.Meta.fields, 'first_name', 'last_name')
We can here thus add the extra fields for first_name and last_name as well.
Now we can make use of this in a CreateView [Django-doc], and override the form_valid(..) method [Django-doc]:
# app/views.py
from app.forms import RoleUserCreationForm
from django.contrib.auth import get_user_model
from django.shortcuts import redirect
from django.views.generic.edit import CreateView
class RegisterView(CreateView):
model = get_user_model()
form_class = RoleUserCreationForm
def form_valid(self, form):
request.session['user_id'] = self.object.id
if form.cleaned_data['role'] == 'Customer':
return redirect('name-of-customer-view')
else:
return redirect('name-of-employee-view')
Where you replace the 'name-of-customer-view' and 'name-of-employee-view' with the name of these views respectively.
I have to send some data to my database where I have a phone object. For this I need to select the desired phone number and insert the desired information to the database.
A requirement is to display the phone numbers that belongs to the current login user.
I use Django model named Phone and a modelForm named phoneForm.
class Phone(models.Model):
user = models.ForeignKey(User)
phone_num = models.ForeignKey(Sim, null=True)
imei = models.CharField(max_length=30, primary_key=True)
num_calls = models.CharField(max_length=20, null=True, blank=True)
time_btwn_calls = models.CharField(max_length=20, null=True, blank=True)
psap = models.CharField(max_length=30, null=True, blank=True)
class Sim(models.Model):
phone_num = models.CharField(max_length=30, primary_key=True)
pin = models.CharField(max_length=15)
puk = models.CharField(max_length=15)
class phoneForm(ModelForm):
class Meta:
model = Phone
fields = ['phone_num', 'num_calls', 'time_btwn_calls', 'psap']
widgets = {'phone_num': Select(attrs={'class': 'form-control'}),
'num_calls': TextInput(attrs={'class': 'form-control'}),
'time_btwn_calls': TextInput(attrs={'class': 'form-control'}),
'psap': TextInput(attrs={'class': 'form-control'})
}
labels = {
'phone_num': ('Select phone number'),
'num_calls': ('Number of calls'),
'time_btwn_calls': ('Time between calls'),
'psap': ('PSAP'),
}
def __init__(self, *args, **kwargs):
super(phoneForm, self).__init__(*args, **kwargs)
self.queryset = Phone.objects.filter(user_id = request.user.id).values('phone_num')
How can I acces the database properly to filter the phone_num values that belongs to the current user and then set them in phone_num choices?
My template is:
<div class="row">
<div class="col-md-6 col-sm-offset-3">
<form method="post" action="" enctype="multipart/form-data">
{% csrf_token %} <!-- obligatorio para protegerse de ataques maliciosos -->
{{ form.as_p }} <!-- pasamos la variable form y con as_p conseguimos <p> -->
<button type="submit" class="btn btn-primary">Send to TCU</button>
</form>
</div>
And my view.py:
def phone_config(request):
phone = Phone.objects.get(phone_num=611111111)
if request.method == 'POST':
form = phoneForm(request, request.POST, instance=phone)
if form.is_valid():
form.save()
return redirect(reverse('gracias'))
else:
form = phoneForm(request, instance=tcu)
return render(request, 'heroconfigurer/heroconfigurer.html', {'form': form})
def gracias_view(request):
return render(request, 'heroconfigurer/gracias.html')
To modify the phone_num field in your form, you access self.fields['phone_num'] in your form's __init__ method.
class phoneForm(ModelForm):
class Meta:
model = Phone
...
def __init__(self, user, *args, **kwargs):
super(phoneForm, self).__init__(*args, **kwargs)
phone_nums = Phone.objects.filter(user=user).values_list('phone_num', flat=True)
self.fields['phone_num'].queryset = Sim.objects.filter(phone_num__in=phone_nums)
When you initialise the form in your view, you need to pass the user, e.g.
form = phoneForm(user, request.POST)
If that doesn't work, please explain why and show your Sim model.
Note a couple of other changes:
No need to use values()
If Sim.user is a foreign key, then you can simplify the filter to filter(user=request.user)
The user has been added to the form's __init__ method.