Django derive model field based on other field value - django

I have a CustomUser model
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name = "email", max_length = 60, unique = True)
username = models.CharField(max_length = 30, unique = True)
I am using a User creation form to register new users as follows,
class RegistrationForm(UserCreationForm):
email = forms.EmailField(max_length = 60, help_text = "This will be your login.")
class Meta:
model = Account
fields = ("email", "username", "password1", "password2")
What I want to do is remove the "username" from the form fields, so
fields = ("email", "password1", "password2")
And then when the user submits the form, I wish to insert a value into the username field based on the email provided by the user, for e.g. email = abc#xyz.com, then username = abc.
How do I do this?

form.py
class UserCreateForm(UserCreationForm):
password1 = forms.CharField(widget=forms.PasswordInput(attrs={'class':'form-control'}))
password2 = forms.CharField(widget=forms.PasswordInput(attrs={'class':'form-control'}))
class Meta:
model = User
fields = ['email','first_name','last_name','password1','password2']
exclude = ['username']
widgets = {
'username':forms.TextInput(attrs={'class':'form-control'}),
# 'first_name':forms.TextInput(attrs={'class':'form-control'}),
# 'last_name':forms.TextInput(attrs={'class':'form-control'}),
'email':forms.EmailInput(attrs={'class':'form-control'}),
}
view.py
def RegisterView(request):
if request.method == 'POST':
form = UserCreateForm(request.POST)
if form.is_valid():
email = form.cleaned_data['email']
fm = form.save(commit=False)
fm.username = email.split("#")[0]
fm.save()
messages.success(request,f'{email} Successfully Registred')
form = UserCreateForm()
return render(request, 'index.html', {'form': form})
else:
form = UserCreateForm()
context = {'form': form, }
return render(request, 'index.html', context)
HTML Code
<form action="" method="post">
{% csrf_token %}
{% for i in form %}
<p>{{i.label}} {{i}}</p>
{% endfor %}
<button type="submit">Add</button>
</form>
Webpage output (register form)
admin panel

Related

Issue with django request,get user from bd

SO,I want to get user details from database and show them in user.html,but I cant do it. They dont display in this file. I tried to do class UserView(ListView):, but it wasnt working. Maybe I didnt understand request.
view.py
def registerform(request): ##registerform
form = SightUp(request.POST or None)
if form.is_valid():
user_obj = form.save()#Сохранение значений в датабазе методом .save()
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password1')
email = form.cleaned_data.get('email')
user = authenticate(username=username,password =raw_password,email=email)
login(request,user)
return redirect('/userprofile/')# ЗАМЕНИТЬ
context = {'form':form }
return render(request,'user.html',context)
#def userprofiles(request):
# userall = detailsuser.objects.all()
# context = {
# 'objects':userall
# }
# return render(request,'userprofile.html', context)
class UserView(ListView):
model = User
template_name = 'userprofile.html'
context = 'detailsuser'
def get_queryset(self):
return detailsuser.objects.filter(user = self.request.user)
forms.py
class SightUp(UserCreationForm):
first_name = forms.CharField( widget = forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'First Name'}), max_length=32, help_text='First name')
last_name = forms.CharField( widget = forms.TextInput(attrs={'class':'form-control','placeholder':'Last name'}), max_length=32)
email = forms.EmailField(widget =forms.TextInput(attrs={'class':'form-control', 'placeholder': 'Email'}), max_length =64,help_text='Enter valid Email')
username = forms.CharField(widget =forms.TextInput(attrs={'class':'form-control','placeholder':'Username'}))
password1 = forms.CharField(widget =forms.PasswordInput(attrs={'class':'form-control','placeholder':'Password1'}))
password2 = forms.CharField(widget =forms.PasswordInput(attrs={'class':'form-control','placeholder':'Password2'}))
class Meta(UserCreationForm.Meta):
model = User
fields = UserCreationForm.Meta.fields + ('first_name','last_name','email')
user.html
{% for i in detailsuser %}
<h1> yourname: i.email </h1>
{% endfor %}
<h1>Your last name:</h1>
<h1>Your nickname:</h1>
models.py
class detailsuser(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
Your challenge stems from the register view you need to make a conditional test for the POST method like so:
def registerform(request): ##registerform
if request.method == 'POST': #Here is where you make the condition for POST
form = SightUp(request.POST or None)
if form.is_valid():
user_obj = form.save()#Сохранение значений в датабазе методом .save()
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password1')
email = form.cleaned_data.get('email')
user = authenticate(username=username,password =raw_password,email=email)
login(request,user)
return redirect('/userprofile/')# ЗАМЕНИТЬ
else:
form = SightUp()
context = {'form':form }
return render(request,'user.html',context)
Your user html had a problem, you didn't add the {% endfor %} tag that's why you are not seeing any information. Do something like so:
{% for i in detailsuser %}
<h1> yourname: i.email </h1>
{% endfor %}
<h1>Your last name:</h1>
<h1>Your nickname:</h1>
{% endfor %}
I ansewer it. Problem was because of cycle in my template

How do I make a User Profile form using OnetoOneField extending the User Model?

I would like to make a form that extends the User Model using OnetoOneField. It would basically be a form in which a user can add/update their information after they have registered.
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
username = models.CharField(max_length=120)
name = models.CharField(max_length=120) # max_length = required
email = models.EmailField(max_length=120)
paypal_id = models.CharField(max_length=120)
bio = models.TextField(max_length=500, blank=True)
def __str__(self):
return self.user.username
forms.py
class UserProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ["username", "name", "email", "paypal_id", "bio"]
views.py
def userprofile_view(request):
if request.method == 'POST':
profile_form = UserProfileForm(request.POST)
if profile_form.is_valid():
profile = profile_form.save(commit=False)
profile.save()
return redirect('account')
else:
profile_form = UserProfileForm()
context = {'profile_form': profile_form}
return render(request, 'accounts/account_create.html', context)
template.html
{% extends 'base.html' %}
{% block content %}
<form action="." method="POST">
{% csrf_token %}
{{ profile_form.as_p }}
<input type="submit" value="Save"/>
</form>
{% endblock %}
I keep getting this error when I hit Save:
(1048, "Column 'user_id' cannot be null")
Is there any fix for this?
You can create both user and profile models at once using a generic create view.
Forms:
class UserProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ["username", "name", "email", "paypal_id", "bio", "user"]
class UserForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ['username', 'first_name', 'last_name', 'email', 'password1', 'password2']
View:
class CreateUserProfileView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = Profile
form_class = UserProfileForm
user_form_class = UserForm
template_name = 'accounts/account_create.html'
success_message = "Profile created successfully"
success_url = reverse_lazy('profile-list')
def get(self, request):
profile_form = self.form_class()
user_form = self.user_form_class()
return render(request, self.template_name, {'profile_form': profile_form, 'user_form': user_form})
def post(self, request, *args, **kwargs):
profile_form = self.form_class(request.POST)
user_form = self.user_form_class(request.POST)
if all([profile_form.is_valid(), user_form.is_valid()]):
user = user_form.save()
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
messages.success(request, self.success_message)
else:
return render(request, self.template_name, {'profile_form': profile_form, 'user_form': user_form})
return HttpResponseRedirect(self.success_url)
You need to overwrite save() method of Profile to create/update User on-the-fly while saving Profile.
I.e.:
class Profile(models.Model):
...
def save(self, *args, **kwargs):
if not self.user.pk:
self.user = User.objects.create_user(self.user.username, password=self.user.password)
self.user.save() # mandatory as create_user is not recognized as save operation
super().save(*args, **kwargs)

adding extra field ('city') to UserRegisterForm Django

When new users register I want to store:
fields = ['username', 'email', 'password1', 'password2', 'city']
so I extended UserRegisterForm by adding 'city' to the form.
It renders fine in the template and save everything except 'city'. There is no even column 'city' in the new users profile when checking by admin page so looks like its not creating one.
I found few similar posts and been following Doc but that didint help.
Have tried many different ways but will post two I think mostly sensible ones.
EXAMPLE 1
- *forms.py*
...
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
city = forms.CharField(required=True)
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2', 'city']
def save(self, commit=True):
user = super(UserRegisterForm, self).save(commit=False)
user.city = self.cleaned_data['city']
if commit:
user.save()
return user
- *views.py*
...
from django.contrib.auth.forms import UserCreationFormfrom
from .forms import UserRegisterForm
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save()
print('VALID')
username = form.cleaned_data.get('username')
messages.success(request,
'{} Your account has been created! You can now Log In'.format(username))
return redirect('/login/')
else:
form = UserRegisterForm()
context = {
'form': form,
}
return render(request, 'users/register.html', context)
#login_required
def profile(request):
return render(request, 'users/profile.html')
- *template*
...
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<!-- {{ form2 }} -->
<button class="btn-signup" type="submit">Sign Up</button>
</form>
In Example 2 Iam creating new class 'ProfileForm' with new model as separate form and including it in the views.py in one function with UserRegisterForm.
EXAMPLE 2
- *models.py*
...
class Profile(models.Model):
city = models.CharField(max_length=25, blank=False)
def __str__(self):
return self.city
- *forms.py*
...
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
city = forms.CharField(required=True)
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2', 'city']
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['city']
def save(self, commit=True):
user = super(UserRegisterForm, self).save(commit=False)
user.city = self.cleaned_data['city']
if commit:
user.save()
return user
- *views.py*
...
from django.contrib.auth.forms import UserCreationFormfrom
from .forms import UserRegisterForm, ProfileForm
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
form2 = ProfileForm(request.POST)
if form.is_valid() and form2.is_valid():
form.save()
form2.save()
print('VALID')
username = form.cleaned_data.get('username')
messages.success(request,
'{} Your account has been created! You can now Log In'.format(username))
return redirect('/login/')
else:
form = UserRegisterForm()
form2 = ProfileForm()
context = {
'form': form,
'form2': form2
}
return render(request, 'users/register.html', context)
- *template*
...
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
{{ form2 }}
<button class="btn-signup" type="submit">Sign Up</button>
</form>
Your Profile model should have a OneToOne relation with the User model like this:
Class Profile (models.Model):
user = models.OneToOneField (User,on_delete=models.CASCADE)
city = models.CharField (max_length=25,blank=False)
You don't need to define ProfileForm.You can create profile objects for the user like this.
form = UserRegisterForm (request.POST)
if form.is_valid ():
city = form.cleaned_data ['city']
user = form.save ()
Profile.objects.create (user=user,city=city)
return redirect ('some_view)

Django form without model not appearing in template when rendered

I have a form without an associated model, just a contact form for sending a message.
I have some experience with django forms by now, so I thought I had done everything correctly, but nothing ends up rendering when the page is viewed in a browser at all, nor are there any errors to troubleshoot.
My forms.py:
from django import forms
class ContactForm(forms.Form):
class Meta:
fields = ['full_name', 'phone', 'email', 'message']
full_name = forms.CharField(max_length=20)
phone = forms.CharField(max_length=20)
email = forms.CharField(max_length=30)
message = forms.CharField(max_length=400)
And my view that turns the form into something useful:
def contact_view(request):
full_name = request.POST.get('full_name', False)
phone = request.POST.get('phone', False)
email = request.POST.get('email', False)
message = request.POST.get('message', False)
form = ContactForm()
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
# send_emails(first_name, last_name, email)
template = loader.get_template('/myapp/mysite/main_page/templates/main_page/thankyoumsg.html')
return HttpResponse(template.render({}, request))
template = loader.get_template('/myapp/mysite/main_page/templates/main_page/contact.html')
return HttpResponse(template.render({}, request))
And my template:
<form class="leave-comment" action="." method="post">
{% csrf_token %}
{{form.as_p}}
<button type="submit">Submit</button>
</form>
But nothing is displaying, and I am unsure why. How can I troubleshoot this?
You're not including the form in the response at the last line. This should (probably) do the trick:
def contact_view(request):
...
return HttpResponse(template.render({'form': form}, request))
I also believe you need to add the fields directly to the form class, not in the Meta-class.
from django import forms
class ContactForm(forms.Form):
# Move out the fields here instead
full_name = forms.CharField(max_length=20)
phone = forms.CharField(max_length=20)
email = forms.CharField(max_length=30)
message = forms.CharField(max_length=400)
class Meta:
# This may still be there but may also be a bit redundant since
# you're choosing to show all applied fields.
fields = ['full_name', 'phone', 'email', 'message']
class Meta is only used when you have a model. If you only need to render a form without a specific model use it this way. for more information please visit official documentation:
https://docs.djangoproject.com/en/2.1/topics/forms/
forms.py
class ContactForm(forms.Form):
full_name = forms.CharField(max_length=20)
phone = forms.CharField(max_length=20)
email = forms.CharField(max_length=30)
message = forms.CharField(max_length=400)
views.py
def contact_view(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
full_name = form.cleaned_data['full_name']
phone = form.cleaned_data['phone']
email = form.cleaned_data['email']
message = form.cleaned_data['message']
template = loader.get_template('/myapp/mysite/main_page/templates/main_page/thankyoumsg.html')
return HttpResponse(template.render({'form': form}, request))
template = loader.get_template('/myapp/mysite/main_page/templates/main_page/thankyoumsg.html')
return HttpResponse(template.render({'form': form}, request))
form = ContactForm()
template = loader.get_template('/myapp/mysite/main_page/templates/main_page/contact.html')
return HttpResponse(template.render({'form': form}, request))

Django auth_user_model

I'd like to make auth_user_model login but I need to login with Email and Password. So I thought I can do that if I can save email value in 'username' field.
class HeepooUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone = models.CharField(max_length=15, null=True)
allow_phone = models.BooleanField(default=False)
school = models.ForeignKey(School)
date_join = models.DateTimeField(auto_now_add=True)
def register(request):
registered = False
if request.method == 'POST':
user_form = UserForm(request.POST)
profile_form = RegisterForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save(commit=False)
user.set_password(user.password)
user = user_form.save()
profile = profile_form.save(commit=False)
profile.user = user
profile = profile_form.save()
registered = True
return HttpResponseRedirect("/books/")
else:
return HttpResponse('Wrong access1')
else:
user_form = UserForm()
profile_form = RegisterForm()
return render(request, "register.html", {
'user_form': user_form,
'profile_form': profile_form,
'registered': registered,
})
forms.py
class UserForm(forms.ModelForm):
email = forms.EmailField(max_length=50, required=True,
widget=forms.TextInput(attrs={'class':'form-control', }),
)
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('email', 'password',)
class RegisterForm(forms.ModelForm):
class Meta:
model = HeepooUser
exclude = ('allow_phone', 'user',)
Register.html
<form action="" method="post">
{% csrf_token %}
{{ user_form.as_p }}
{{ profile_form.as_p }}
<input type="submit" value="Register">
</form>
Could you please help me on?
Thanks!
You can request the email instead of username to the user in your login form in order to use it for loggin him, then just generate a username for that user, you can do it using his email or name.
EDIT:
You only need to generate an username. Let's say that you are requesting name and last name to the user. Let's create a method to generate it.
def generate_username(first_name, last_name):
username = '%s.%s' % (first_name.lower(), last_name.lower())
username = '{:.29}'.format(username)
counter = User.objects.filter(first_name=first_name,last_name=last_name).count()
if counter > 0:
username += '%s' % (counter + 1)
return username
Then you can use it on your view.
user = user_form.save(commit=False)
user.set_password(user.password)
user.username = generate_username(first_name, last_name)
.....
If you don't want to request first name or last name, you can generate the username using his email too.