Django: NOT NULL constraint failed: wishlist_wish.user_id - python

I have a wishlist app with a custom user model. I added the user as the foreign key to each wishlist item. However, I am only able to add the foreign key by specifying a default user, even after deleting the existing db files and running makemigrations and migrate. The default user is associated with the wishlist item regardless of which user is logged in, and if I don't include a default user I get the "NOT NULL constraint failed: wishlist_wish.user_id" error.
How can I update the code so that the wishlist item is associated with the logged-in user creating the item?
A related question is whether I need to include a user id in my custom user model? I tried doing this as well and ran into the same problem. Thanks in advance.
Wish Model:
class Wish(models.Model):
name = models.TextField()
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default=1)
def __str__(self):
return self.name
Wish View:
def add_wish(request):
user = request.user
wishes = Wish.objects.filter(user=request.user)
if request.method == 'POST':
form = WishForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
else:
form = WishForm()
context = {'form' : form, 'wishes' : wishes}
return render(request, 'wishlist/add_wish.html', context)
Wish Form:
class WishForm(ModelForm):
class Meta:
model = Wish
fields = ('name', )
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['name'].widget.attrs.update({'class' : 'textarea', 'placeholder' : 'Enter wishlist item'})
Custom User (Account) Model:
class MyAccountManager(BaseUserManager):
def create_user(self, email, username, first_name, last_name, password=None):
if not email:
raise ValueError("Users must provide an email to create an account.")
if not first_name:
raise ValueError("Users must provide full name to create an account.")
if not last_name:
raise ValueError("Users must provide full name to create an account.")
user = self.model(
email = self.normalize_email(email),
username = username,
first_name = first_name,
last_name = last_name,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, first_name, last_name, password):
user = self.create_user(
email = self.normalize_email(email),
username = username,
first_name = first_name,
last_name = last_name,
password = password
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
email = models.EmailField(max_length=100, unique=True)
username = models.CharField(max_length=100, unique=False, blank=True, null=True)
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'first_name', 'last_name']
objects = MyAccountManager()
def __str__(self):
return self.first_name + " " + self.last_name
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True

You simply need to provide a value for the .user for the Wish you are creating:
from django.contrib.auth.decorators import login_required
#login_required
def add_wish(request):
wishes = Wish.objects.filter(user=request.user)
if request.method == 'POST':
form = WishForm(request.POST)
if form.is_valid():
form.instance.user = requst.user
form.save()
return redirect('home')
else:
form = WishForm()
context = {'form' : form, 'wishes' : wishes}
return render(request, 'wishlist/add_wish.html', context)
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].

Related

Seperate login for custom user and django admin in Django

I'm currently working on a django project and I have a custom user model in my django app. Custom user authentication is working perfectly, but the issue I'm facing is whenever I'm logging into admin account in the django admin site, it logs out the previous user(let say, user2) and admin being logged in.
How Can I separate their login, so that admin site logins don't interfere with my website login?
Here is my code attached:
Custom User model and its manager:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class CustomerManager(BaseUserManager):
def create_user(self, email, username, name, password=None):
if not email:
raise ValueError('Users must have an email address to register')
if not username:
raise ValueError('Users must have an username address to register')
if not name:
raise ValueError('Users must enter their name to register')
user = self.model(
email = self.normalize_email(email),
username = username,
name=name,
)
user.set_password(password)
user.save(using = self._db)
return user
def create_superuser(self, email, username, name, password=None):
user = self.create_user(
email = self.normalize_email(email),
username = username,
name=name,
password=password,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class Customer(AbstractBaseUser):
# user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
email = models.EmailField(max_length=254, null=True, unique=True)
username = models.CharField(max_length=40, unique=True)
name = models.CharField(max_length=200)
phone = models.CharField(max_length=10, null=True)
address = models.CharField(max_length=500, null=True)
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'name']
objects = CustomerManager()
def __str__(self):
return self.name
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
Login View:
def loginUser(request):
if request.user.is_authenticated:
return redirect('home')
else:
if request.method == 'POST':
email = request.POST.get('email')
password = request.POST.get('password')
user = authenticate(request, email=email, password=password)
if user is not None:
login(request, user)
return redirect('home')
else:
messages.info(request, 'Email or Password didn\'t match!')
context = {}
return render(request, 'accounts/login.html', context)
Logout View:
#login_required(login_url='login')
def logoutUser(request):
logout(request)
return redirect('login')
User Profile View:
#login_required(login_url='login')
def userProfile(request, email):
customer = Customer.objects.filter(email=email).first()
context = {'customer':customer}
return render(request, 'accounts/profile.html', context)
CreateUserForm and LoginForm:
class CreateUserForm(UserCreationForm):
class Meta:
model = Customer
fields = ['username', 'email', 'name', 'password1', 'password2']
# fields = '__all__'
class LoginForm(forms.ModelForm):
password = forms.CharField(label='password', widget=forms.PasswordInput)
class Meta:
model = Customer
fields = ['email', 'password']
def clean(self):
email = self.cleaned_data['email']
password = self.cleaned_data['password']
if not authenticate(email=email, password=password):
raise forms.ValidationError('Incorrect Login')
When User3 is logged in and admin is not logged in:
As soon as admin logged in:
User3 automatically logs out and admin logs in..

authenticate() not working properly for django

Basically what I have done so far is create a registration page where the user makes their username and password, then that password is stored in as a hashed password (md5 hasher). The problem I am having is logging in. The user inputs their username and password then the password is authenticated by using authenticate() method in django. The problem is that authenticate() is returning None instead of matching the user and password in the database. I dont know if this affects anything but I am using PostgreSQL.
models.py
class MyAccountManager(BaseUserManager):
def create_user(self, email,username,first_name,password= None):
if not email:
raise ValueError('User must have an email address')
if not username:
raise ValueError('User must have a username')
if not first_name:
raise ValueError('User must have a first name')
user= self.model(
email=self.normalize_email(email),
username= username,
first_name= first_name
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, first_name, password):
user= self.create_user(
email= self.normalize_email(email),
username=username,
first_name= first_name,
password= password,
)
user.is_admin= True
user.is_staff= True
user.is_superuser= True
user.save(using=self._db)
return user
class User(AbstractBaseUser, models.Model):
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
date_joined = models.DateTimeField(auto_now_add=True, verbose_name='date joined')
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
USERNAME_FIELD= 'username'
REQUIRED_FIELDS= ['email','first_name']
objects= MyAccountManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
forms.py
class LoginForm(forms.Form):
username = forms.CharField(initial='' ,label='Username:',max_length=30)
password = forms.CharField(max_length=20, widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username', 'password')
def clean(self):
cleaned_data = super(LoginForm, self).clean()
confirm_password = cleaned_data.get('password')
class SignUpForm(forms.ModelForm):
first_name = forms.CharField(required= True,initial='',max_length=20)
last_name = forms.CharField(required=True,max_length=30, initial='')
username = forms.CharField(max_length=30,initial='', required=True)
password = forms.CharField(max_length= 20, initial='', widget = forms.PasswordInput())
password2= forms.CharField(max_length=20, initial='',widget = forms.PasswordInput())
email = forms.EmailField(max_length=60, initial='',)
class Meta:
model = User
fields = ('first_name', 'last_name','username','password2','email')
def clean(self):
cleaned_data = super(SignUpForm,self).clean()
password = cleaned_data.get('password')
confirm_password = cleaned_data.get('password2')
if(password != confirm_password):
raise forms.ValidationError(
'Password and Confirm Password do not match.'
)
views.py
def signin_and_signup(request):
if request.method == 'POST':
logout(request)
sign_in = LoginForm(request.POST)
signup = SignUpForm(request.POST)
if 'sign-in-name' in request.POST:
if sign_in.is_valid():
username = request.POST.get('username')
password= request.POST.get('password')
user = authenticate(username= username, password= password)
if user:
return HttpResponse('success')
else:
return HttpResponse('fail')
elif 'sign-up-input-name' in request.POST:
if(signup.is_valid()):
user = signup.save(commit=False)
nonHashed = signup.cleaned_data['password']
varhash = make_password(nonHashed, None, 'md5')
user.set_password(varhash)
user.save()
else:
print("Ran3<------------")
signup = SignUpForm()
else:
sign_in = LoginForm()
signup = SignUpForm()
context = {'signin':sign_in, 'signup':signup}
return render(request, 'home.html', context)
Why are you substituting the user model that django provides if you have the same attributes?
This is done in case you want to extend or add new properties to the user, for example, license number, avatar, position.
Anyway, your authenticate() maybe doesn't work because you haven't registered your new model in settings.py.
AUTH_USER_MODEL = 'name_of_the_app.User'
I recommend that you take a look at the official documentation
https://docs.djangoproject.com/en/3.1/topics/auth/customizing/
Antoher thing it could be your authentication backend:
Try:
settings.py
AUTHENTICATION_BACKENDS = [
'name_of_the_app.admin.LoginBackend',
]
Where you want for example admin.py
from django.contrib.auth.backends import ModelBackend, UserModel
from django.db.models import Q
class LoginBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try: # to allow authentication through phone number or any other field, modify the below statement
user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
except UserModel.DoesNotExist:
UserModel().set_password(password)
except MultipleObjectsReturned:
return models.User.objects.filter(email=username).order_by('id').first()
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
def get_user(self, user_id):
try:
user = UserModel.objects.get(pk=user_id)
except UserModel.DoesNotExist:
return None
return user if self.user_can_authenticate(user) else None
As you can see, you can also login with the email

UNIQUE constraint failed on Posting form

I am trying to post a simle form to create a user. but whenever i try to save the form data it always gives me UNIQUE constraint failed error even if i pass the new mobile number that does not exist on database.
ERROR IS: UNIQUE constraint failed: core_user.mobile_no
models.py
Manager Class is:
class UserManager(BaseUserManager):
def create_user(self, username, password=None, **extra_fields):
"""Creates and saves a new user"""
if not password:
raise ValueError("User must have a password")
if not username:
raise ValueError("User must have an username")
user = self.model(username=username, **extra_fields)
user.set_password(password)
user.save(using=self.db)
return user
def create_staff_user(self, username, password=None, **kwargs):
user = self.create_user(username, password, is_staff=True, **kwargs)
return user
def create_super_user(self, username, password=None):
user = self.create_user(self, username=username, password=password, is_staff=True, is_super_user=True)
return user
Model class is:
class User(AbstractBaseUser):
user_types = (
("staff", "Staff"),
("super_user", "Super User"),
)
first_name = models.CharField(max_length=100)
middle_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
username = models.CharField(max_length=100, unique=True)
email = models.EmailField()
mobile_no = models.CharField(max_length=10, unique=True)
is_active = models.BooleanField(default=True) # can login
is_staff = models.BooleanField(default=False) # staff user
is_super_user = models.BooleanField(default=False) # super user
created_date = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'username'
objects = UserManager()
# USERNAME_FIELD and password are required by default
REQUIRED_FIELDS = [] # e.g full_name
def __str__(self):
return self.username
Views.py
class UserCreationView(CreateView):
template_name = "form.html"
form_class = UserCreationForm
success_url = "/"
def form_valid(self, form):
username = form.cleaned_data['username']
password = form.cleaned_data['password']
first_name = form.cleaned_data['first_name']
middle_name = form.cleaned_data['middle_name']
last_name = form.cleaned_data['last_name']
mobile_no = form.cleaned_data['mobile_no']
email = form.cleaned_data['email']
user_type = form.cleaned_data['user_type']
user_data = {
"first_name": first_name,
"middle_name": middle_name,
"last_name": last_name,
"mobile_no": mobile_no,
"email": email
}
if user_type == 'super-user':
user = User.objects.create_super_user(username, password, **user_data)
else:
user = User.objects.create_staff_user(username, password, **user_data)
form.instance.user = user
form.instance.is_active = True
form.save()
return super().form_valid(form)
Questions are:-
As far as i tried to debug, it could be the reason that create_staff_user and create_super_user functions have already created a row in database and now form.save() is also trying to insert the row again. (not sure)
do i need to do form.save() as i found that super().form_valid(form) also have implemented form saving function within it ?
In your view, you should only call save once, but you are calling it twice
form.save() # this line saves it to the database
super().form_valid(form) # and this line does that too
so after calling form.save() return response.
update, your code to
class UserCreationView(CreateView):
template_name = "form.html"
form_class = UserCreationForm
success_url = "/"
def form_valid(self, form):
username = form.cleaned_data['username']
password = form.cleaned_data['password']
first_name = form.cleaned_data['first_name']
middle_name = form.cleaned_data['middle_name']
last_name = form.cleaned_data['last_name']
mobile_no = form.cleaned_data['mobile_no']
email = form.cleaned_data['email']
user_type = form.cleaned_data['user_type']
user_data = {
"first_name": first_name,
"middle_name": middle_name,
"last_name": last_name,
"mobile_no": mobile_no,
"email": email
}
if user_type == 'super-user':
user = User.objects.create_super_user(username, password, **user_data)
else:
user = User.objects.create_staff_user(username, password, **user_data)
form.instance.user = user
form.instance.is_active = True
form.save()
return HttpResponseRedirect(self.get_success_url())
mobile number should be unique for every user
class UserForm(forms.ModelForm):
class Meta:
model = User
exclude = ('is_staff', 'is_superuser',)
def clean_mobile_no(self):
mobile_number = self.cleaned_data.get('mobile_no')
user = User.objects.filter(mobile_no=mobile_number)
if user:
raise forms.ValidationError(
"mobile no is taken"
)
return mobile_number
Well, as for your first question, it could be the problem. I guess before you created a custom User model, you makes migrations and pushed them to your database. So, that is the part where Django also creates its own User model, with all the available columns and attributes. I would suggest to DELETE your currently Users table, and run the makemigrations and migrate again.
As for your second question, the best practice and advice that I could give you is to first add an if clause, to check if the form data are valid, and then save the form and post the data. Although my advice does not really relate to your question, the point is to always validate the form's data and after you retrieve them, save the form (post the data).
In the documentation it says that the FormView class on success will redirect the user and on error, it will redisplay the form. However, the CreateView will only display the errors and save the object, it will not redirect to anything. Although with the CreateView you can automatically save the form and its data, it will not redirect the user. I suggest you using the FormView class that will show if there any errors and will redirect the user on success, but be careful and save the form data at the end of the POST function.
I hope that helps! Please let me know if there is anything else I can help you with.

unable to save data before saving models in django

I am trying to build a single custom registration form for companies, admin, and staff. When I create my superuser, my 'Account type' is 'admin', but when I try to register as a a company my 'Account type' is empty.
I can set a default value in my model class, but I would like to add more different types of 'Account type' in the future.
I also don't want to have a dropdown for the field
models.py
from django.db import models
from django.contrib.auth.models import (
BaseUserManager,
AbstractBaseUser
)
# Create your models here.
class UserManager(BaseUserManager):
def create_user(self, email, first_name, last_name, account_type=None, password=None):
if not email:
raise ValueError('Email address is required')
user = self.model(
email = self.normalize_email(email),
first_name = first_name,
last_name = last_name,
account_type = account_type
)
user.set_password(password)
user.save(using=self._db)
return user
def create_staffuser(self, email, first_name, last_name, password):
user = self.create_user(
email,
first_name = first_name,
last_name = last_name,
account_type = 'staff',
password = password
)
user.staff = True
user.save(using=self._db)
return user
def create_superuser(self, email, first_name, last_name, password):
user = self.create_user(
email,
first_name = first_name,
last_name = last_name,
account_type = 'admin',
password = password
)
user.staff = True
user.admin = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
email = models.CharField(max_length=255, unique=True)
first_name = models.CharField(max_length=64)
last_name = models.CharField(max_length=64)
account_type = models.CharField(max_length=32)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name']
def __str__(self):
return self.email
def get_full_name(self):
return "%s %s" % (self.first_name, self.last_name)
def get_short_name(self):
return self.first_name
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_admin(self):
return self.admin
#property
def is_staff(self):
return self.staff
#property
def is_active(self):
return self.active
views.py
from django.shortcuts import render
from accounts.forms import RegisterForm
# Create your views here.
def register(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
password = form.cleaned_data.get('password')
user = form.save(commit=False)
user.account_type = 'company'
user.set_password(password)
user.save()
return HttpResponse('account created')
else:
form = RegisterForm();
context = {
'form' : form
}
return render(request, 'accounts/form.html', context)

Django authentication is alway false for non superuser

here is the trouble i try to autheticate the users for my website but authenticate() return alway the None value for the user created with the registration page. I can correctly log user after their user user creation and the entry is in the database. I have a custom user model extended form AbstractBaseUser. So here is the portion of code not working :
from django.contrib.auth import login as authlog
def login(request):
error = False
if request.method == "POST":
form = forms.LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data["username"]
password = form.cleaned_data["password"]
user = authenticate(username=username, password=password)
print("Validated form.")
print(username)
print(password)
print(user)
if user:
print("Logged user.")
authlog(request, user)
return redirect(to='home')
else:
print("Not logged user.")
error = True
else:
form = forms.LoginForm()
return render(request, 'users/login.html', locals())
And in the following block of code the user is sccessfully logged after it's registration.
from django.contrib.auth import login as authlog
def register(request):
form = forms.RegisterForm(request.POST or None)
if form.is_valid():
user = form.save()
authlog(request, user)
return redirect(to='home')
print('Registered new user')
return render(request, 'users/register.html', locals())
What i don't understant is why it the admin account i created with ./manage.py createsuperuser work and not the others.
And also i can't create user in the admin panel and i don't know why.
Thanks :D
EDIT: My forms
class CreateUserForm(forms.ModelForm):
pass1 = forms.CharField(label="Password", widget=forms.PasswordInput)
pass2 = forms.CharField(label="Password Check", widget=forms.PasswordInput)
class Meta:
model = models.User
fields = '__all__'
def clean_pass2(self):
pass1 = self.cleaned_data.get('pass1')
pass2 = self.cleaned_data.get('pass2')
if pass1 and pass2 and pass1 != pass2:
raise forms.ValidationError("Passwords don't match")
return pass2
def save(self, commit=True):
user = super(UserCreationForm, self)
if user.exte:
user.promo = None
user.login = None
user.save(commit=False)
user.set_password(self.cleaned_data["pass1"])
if commit:
user.save()
return user
class RegisterForm(CreateUserForm):
class Meta:
model = models.User
fields = ('email', 'lname', 'fname', 'exte', 'promo', 'login')
class LoginForm(forms.Form):
username = forms.EmailField(label='Email')
password = forms.CharField(label='Mot de passe', widget=forms.PasswordInput)
About the cleaned data i log the data i get for debug purpose and they're right.
EDIT2: My User Model
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True, verbose_name='e-mail')
fname = models.CharField(max_length=64, verbose_name='first name', null=False, blank=False)
lname = models.CharField(max_length=64, verbose_name='last name', null=False, blank=False)
login = models.CharField(max_length=64, null=True, blank=True, verbose_name="login")
promo = models.CharField(max_length=64, null=True, blank=True, verbose_name="promotion")
exte = models.BooleanField(default=False, verbose_name="externe")
joined = models.DateTimeField(auto_now_add=True)
avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
is_active = models.BooleanField(default=True, verbose_name='active user')
is_staff = models.BooleanField(default=False, verbose_name='admin user')
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['fname', 'lname']
def get_full_name(self):
return "{0} {1}".format(self.fname, self.lname)
def get_short_name(self):
return self.lname
def __str__(self):
return self.get_full_name()
def has_perm(self, perm, obj=None):
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
# Simplest possible answer: Yes, always
return True
You have an indentation problem on your form. Your save method (as well as the clean_pass2 method) are wrongly indented inside the inner Meta class, so it won't be seen by the form itself. This means that set_password won't be called when you create the user, so the password will not be hashed.
Move those methods one indent to the left.

Categories

Resources