I am working on my Checkout view with regular/guest user but getting hard time to come around the integrity error. Idea is to let guest users register with email only to checkout and I need to set the user email unique.
models.py
from django.conf import settings
from django.db import models
class UserCheckout(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, null=True, blank=True)
email = models.EmailField(unique=True)
def __unicode__(self):
return self.email
forms.py
from django import forms
from django.contrib.auth import get_user_model
User=get_user_model()
class GuestCheckoutForm(forms.Form):
email = forms.EmailField()
email2 = forms.EmailField(label='Verify Email')
def clean_email2(self):
email = self.cleaned_data.get("email")
email2 = self.cleaned_data.get("email2")
if email == email2:
user_exists = User.objects.filter(email=email).count()
if user_exists != 0:
raise forms.ValidationError("User already exists. Please login instead")
return email2
else:
raise forms.ValidationError("Please confirm emails addresses are the same.")
In my cart views this is how I've rendered my form.
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
email = form.cleaned_data.get("email")
user_checkout = UserCheckout.objects.create(email=email)
return self.form_valid(form)
else:
return self.form_invalid(form)
I've registered the model with admin and in admin it shows the error for duplication perfectly fine but from frontend I am getting error below:
IntegrityError at /checkout/
column email is not unique
Request Method: POST
Request URL: http://localhost:8000/checkout/
Django Version: 1.8.13
Exception Type: IntegrityError
Exception Value:
column email is not unique
Exception Location: C:\Users\Ali\ecomm\lib\site-packages\django\db\backends\sqlite3\base.py in execute, line 318
Python Executable: C:\Users\Ali\ecomm\Scripts\python.EXE
Python Version: 2.7.9
You create every time when a checkout occurs an new UserCheckout. And in all these entries it is only allowed that every email exists only once.
I don't think you want this. Because if a guest orders two times it isn't allowed because his email is already in the DB. And that's why you get this error.
The clean_<fieldname> methods of a Form are used to perform validation relative to single field. If you need validation with access to multiple fields, use the clean method. Check the documentation on form validation for a thorough explanation.
That would give:
class GuestCheckoutForm(forms.Form):
email = forms.EmailField()
email2 = forms.EmailField(label='Verify Email')
def clean_email(self):
email = self.cleaned_data["email"]
if User.objects.filter(email=email).exists():
raise forms.ValidationError("Please confirm emails addresses are the same.")
return email
def clean(self):
cleaned_data = super(GuestCheckoutForm, self).clean()
email = cleaned_data.get('email')
email2 = cleaned_data.get('email2')
if email and email2 and email != email2:
self.add_error('email2', forms.ValidationError('Please confirm emails addresses are the same.'))
EDIT: I believe I found out why you got an IntegrityError:
You are validation that no User with the given email is in the database, you should also be validating that no other UserCheckout with the given email is in the database. Replace if User.objects.filter(email=email).exists(): by if User.objects.filter(email=email).exists() or UserCheckout.objects.filter(email=email).exists():
Related
My aim - Trying to create an authentication system in Django, and allows user to signup again with same username if their account is not activated.
If an user try to register with a certain username and that username already exists then update that user with this current user.
My Approach - I have created a form using "UserCreationForm" and defining my own methods to validate the form, and allows the user even if username already exists but user.is_active = False.
Code
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import User
class SignupForm(UserCreationForm):
email = forms.EmailField(max_length=200, help_text='Required')
name = forms.CharField()
institution = forms.CharField()
def clean_username(self):
username = self.cleaned_data.get('username')
user = None
try:
try:
user = User.objects.get(username=username)
print("is user active username", user.is_active)
except ObjectDoesNotExist as e:
pass
except Exception as e:
raise e
if not user:
pass
elif not user.is_active:
pass
else:
raise forms.ValidationError("This Username Already Exists")
except Exception as e:
raise e
return username
class Meta:
model = User
fields = ('username', 'email', 'institution', 'password1', 'password2')
views.py
from .forms import SignupForm
def regUser(form):
'''
It will save Django user and student.
It recieves form.cleaned_data as argument
'''
print("reg user line 1")
user = User.objects.create_user(username=form['username'],
email=form['email'],
password=form['password1'],
is_active=False,
)
# notice is_active = False, becuase we will activate account if user will
# verify the email
user.save()
student = Student(user=user, name=form['name'], institution=form['institution'])
student.save()
return user
def signup(request):
if request.user.is_authenticated:
return redirect('accounts:home')
if request.method == 'POST':
form = SignupForm(request.POST)
if form.is_valid():
user = regUser(form.cleaned_data)
current_site = get_current_site(request)
message = render_to_string('accounts/acc_active_email.html', {
'user':user, 'domain':current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
mail_subject = 'Activate your account.'
to_email = form.cleaned_data.get('email')
email = EmailMessage(mail_subject, message, to=[to_email])
email.send()
return render(request, 'accounts/signup.html', {'email_sent': True})
else:
for field in form:
for error in field.errors:
messages.error(request, error)
return redirect("accounts:signup")
return render(request, 'accounts/signup.html')
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
subject = models.CharField(max_length=250, default="default_value")
class Student(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
name = models.CharField(max_length=250, default="default_value")
institution = models.CharField(max_length=250, default="default_value")
def save(self):
super().save()
def __str__(self):
return self.user.username
My problem - I am getting error " A user with that username already exists" I don't why and from where this error is coming when I am trying to created a new user with already registered username but it account is not activated yet (user.is_active = False).
As much I know clean_fields functions are called to validate the form when we use "form.is_valid()" in our views.py, But I have already overridden the "clean_username" according to my need so why I am getting this error ? and from where it is generated ? and how to solve this ?
Also I would like to mention when user is registered it is also registered "student" that's why I am using "regUser" function. Also I read some other questions similar to this on stackoverflow this and this some answer was that inherit the form from "forms.Form" not from "UserCreationForm" but why can anyone explain?
Please not mark this question as already answered I have gone through all questions and it was not helpful.
The User model you defined inherited the AbstactUser, and username is defined there.
class AbstractUser(AbstractBaseUser, PermissionsMixin):
"""
An abstract base class implementing a fully featured User model with
admin-compliant permissions.
Username and password are required. Other fields are optional.
"""
username_validator = UnicodeUsernameValidator()
username = models.CharField(
_('username'),
max_length=150,
unique=True,
help_text=_('Required. 150 characters or fewer. Letters, digits and #/./+/-/_ only.'),
validators=[username_validator],
error_messages={
'unique': _("A user with that username already exists."),
},
)
...
The attribute unique for username field means that username must be unique among all users, not only active users.
(ref. https://docs.djangoproject.com/en/3.1/ref/models/fields/#unique)
If what you want is to allow users to have the same username among inactive users, set unique=False.
But, if 'inactive' means 'discarded' in your User model, I would recommend changing user's username to garbage value when the user is being inactivated.
Considering that a user can disable JavaScript in the browser, how can I proceed with a "double check" for e-mail validation in the Django backend (specifically, to prevent register using Webmail [GMail, Hotmail and so on])? Thanks.
You can do it inside your forms.py(you have to create that file) app like this
from django import forms
class ContactForm(forms.Form):
full_name = forms.CharField()
email = forms.EmailField()
def clean_email(self, *args, **kwargs):
email = self.cleaned_data.get('email')
if email.endswith('#gmail.com'): # etc.
raise forms.ValidationError('This is not a valid email')
return email
Here you can find more about it
I have been woking in django for a while. Now i am facing some problems with built-in function in django. The error state that TypeError: 'bool' object is not callable. This kind of error happened because of statement 'print(request.user.is_authenticated())'.
Here below is source code:
def login_page(request):
form = LoginForm(request.POST or None)
#ensure user is logged in or not
print(request.user.is_authenticated())
if form.is_valid():
print(form.cleaned_data)
return render(request,"auth/login.html",{})
For LoginForm() is imported by my file forms.py
from django import forms
class ContactForm(forms.Form):
#first will be name which is variable
fullname = forms.CharField(widget=forms.TextInput
(attrs={"class":"form-control","placeholder":"Your fullname"}))
email = forms.EmailField(widget=forms.EmailInput
(attrs={"class":"form-control","placeholder":"Your Email"}))
content = forms.CharField(widget=forms.Textarea
(attrs={"class":"form-control","placeholder":"Your content"}))
def clean_email(self):
email = self.cleaned_data.get("email")
if not "gmail.com" in email:
raise forms.ValidationError("Email has to be gmail.com")
#return value of email to be stored
return email
class LoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField()
yes what you want to do is:
print(request.user.is_authenticated)
without () because it is an built-in function
is_authenticated is an attribute of theUser model, not a method.
So, drop the method reference:
print(request.user.is_authenticated)
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 5 years ago.
Improve this question
I need to check the email for unique. I've got some code:
def signup(request):
if request.method == 'POST':
form = SignupForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.is_active = False
user.save()
current_site = get_current_site(request)
mail_subject = 'Activation'
message = render_to_string('acc_active_email.html', {
'user': user,
'domain': current_site.domain,
'uid':urlsafe_base64_encode(force_bytes(user.pk)).decode(),
'token':account_activation_token.make_token(user),
})
to_email = form.cleaned_data.get('email')
email = EmailMessage(
mail_subject, message, to=[to_email]
)
email.send()
return HttpResponse('Check your email')
else:
form = SignupForm()
return render(request, 'signup.html', {'form': form})
The issue is user is able to signup with existing emails, I am getting duplicate emails in my db.
I want to validate for unique email, user should be notified if email already in database, How can i achieve this, Is there any examples with some working code for registration. I am new to Django please help Thanks.
If you are using django-allauth you can use ACCOUNT_UNIQUE_EMAIL configuration variable and set it to True in your settings.py
ACCOUNT_UNIQUE_EMAIL=True
Or if you have custom Model for user then inspite of checking email manually you can simply define that email field unique=True in model.
class User(models.Model):
email = models.EmailField(_('email address'), unique=True)
So when user attempt for signup with existing email, it will throw IntegrityError. you can simply handle it and send response to your template
from django.db import IntegrityError
except IntegrityError as e:
if 'unique constraint' in e.message: # or e.args[0] from Django 1.10
#do something
Or if you want to check it manually then the right place to do this is in clean method inside your SignupForm
class SignupForm(ModelForm):
class Meta:
model = User
fields = ['email', ...]
def clean_email(self):
"""
Returns the email if entered email is unique otherwise gives duplicate_email error.
"""
email = self.cleaned_data['email']
if User.objects.filter(email=email).exists():
raise forms.ValidationError('duplicate_email')
return email
I want to edit the login form provided by django and don't want to build a new one because of the security issues. I have looked at other solutions like How to use another field for logging in with Django Allauth? it's a good example but it assigns email id based on mobile number. However I want to add another field that isn't particularly to authenticate just for input based on which redirection is done. I am quite confused about my approach and whether or not it is possible to do so. Kindly suggest. Thanks.
You can do that in your forms.py file by doing this.
class UserLoginForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control','placeholder':'Username'}))
password = forms.CharField(widget=forms.PasswordInput(attrs={'class':'form-control','placeholder':'Password'}))
yourfield = forms.CharField(widget=forms.TextInput(attrs={'class':'form-control','placeholder':'yourfield'}))
def clean(self, *args, **kwargs):
username = self.cleaned_data.get("username")
password = self.cleaned_data.get("password")
#user_qs = User.objects.filter(username=username)
#if user_qs.count() == 1:
# user = user_qs.first()
if username and password:
user = authenticate(username=username, password=password)
if not user:
raise forms.ValidationError("This user does not exist")
if not user.check_password(password):
raise forms.ValidationError("Incorrect password")
if not user.is_active:
raise forms.ValidationError("This user is no longer active")
return super(UserLoginForm, self).clean(*args, **kwargs)
Apologies if I've misunderstood your question, but here is how I've added extra fields to user registration it which seems pretty straightforward. I've included some extra related methods just to be verbose:
../forms.py:
class CustomRegistrationForm(RegistrationForm):
"""
Form for registering a new user account.
Subclasses should feel free to add any additional validation they
need, but should avoid defining a ``save()`` method -- the actual
saving of collected user data is delegated to the active
registration backend.
"""
username = forms.RegexField(regex=r'^[\w.#+-]+$',
max_length=30,
label="Username",
error_messages={'invalid': "This value may contain only letters, numbers and #/./+/-/_ characters."})
email = forms.EmailField(label="E-mail")
password1 = forms.CharField(widget=forms.PasswordInput,
label="Password")
password2 = forms.CharField(widget=forms.PasswordInput,
label="Password (again)")
extra_field = forms.CharField([field options])
def clean(self):
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("The two password fields didn't match.")
return self.cleaned_data
Then, simply set your register URL to use the proper form class:
../urls.py:
url(r'^accounts/register/$', RegistrationView.as_view(form_class=accounts.forms.CustomRegistrationForm), name='registration_register'),
Is this field not part of your standard model, or does your input need to do some extra work? You can set a signal to make some extra magic happen when the user is registered:
from forms import CustomRegistrationForm
def user_created(sender, user, request, **kwargs):
form = CustomRegistrationForm(request.POST)
user_account = get_user_account(user)
user_account.persona = form.data['persona_tier']
user_account.save()
from registration.signals import user_registered
user_registered.connect(user_created)
FYI I'm using django-registration-redux backend but this approach should help get you close regardless.