IntegrityError at /auth/userreg/ (1048, "Column 'user_id' cannot be null") - python

I am a newbie in django, I am at learning stage I am creating a project appointment system where user and doctor can login . I want to register them as multiuser type for that I have extended abstract class and given one to one relation to other tables but when The code is execute and I click submit This error appears.
all fields are correct there is no error in the code everything is working correct just this integrity error is not getting solved. I have not created any foriegn key just trying to create user at of the user registration .
authenticate.models
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.models import User
# Create your models here.
class User(AbstractUser):
is_user = models.BooleanField('user', default=False)
is_doctor = models.BooleanField('doctor', default=False)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
class User_reg(models.Model):
user = models.OneToOneField('User',on_delete=models.CASCADE, primary_key=True)
fname = models.CharField(max_length=50,blank=False)
lname = models.CharField(max_length=50,blank=False)
email = models.EmailField(max_length=100,blank=False)
address = models.TextField(max_length=500,blank=False)
gender = models.CharField(max_length=7, blank=False)
phone = models.CharField(max_length=12,unique=True,blank=False)
Username = models.CharField(max_length=100,blank=False,unique=True)
Userpassword = models.CharField(max_length=100,blank=False)
views.py
from django.shortcuts import render
from django.contrib import messages
# from django.contrib.auth.models import get_user_model
from django.contrib.auth.models import User
from authenticate_me.models import User_reg, dr_reg
def login(request):
return render(request, 'user/login.html')
def register(request):
if request.method == "POST":
fname = request.POST.get('fname')
lname = request.POST.get('lname')
email = request.POST.get('email')
address = request.POST.get('add')
gender = request.POST.get('sex')
phone = request.POST.get('phone')
username = request.POST.get('uname')
userpassword = request.POST.get('upass')
register = User_reg(fname=fname,lname=lname,email=email,address=address,gender=gender,phone=phone,Username=username,Userpassword=userpassword)
register.save()
myuser = User.objects.create_user(username, email, userpassword)
myuser.first_name = fname
myuser.last_name = lname
myuser.save()
messages.success(request, 'Register successful')
return render(request,'user/login.html')
else:
return render(request, 'user/register.html')
setting
AUTH_USER_MODEL = "authenticate_me.User"

You should first create the User, and then the User_reg object such that you can populate the user field with the myuser object.
def register(request):
if request.method == 'POST':
fname = request.POST.get('fname')
lname = request.POST.get('lname')
email = request.POST.get('email')
address = request.POST.get('add')
gender = request.POST.get('sex')
phone = request.POST.get('phone')
username = request.POST.get('uname')
userpassword = request.POST.get('upass')
myuser = User.objects.create_user(
username, email, userpassword, first_name=fname, last_name=lname
)
User_reg.objects.create(
fname=fname,
lname=lname,
email=email,
address=address,
gender=gender,
phone=phone,
Username=username,
Userpassword=userpassword,
user=myuser
)
messages.success(request, 'Register successful')
return redirect('login')
return render(request, 'user/register.html')
It is however "odd" and a bit "ugly" to have two model objects, especially since you store the same information in both models. This is a form of data duplication which often eventually will make it harder to keep the data in sync.
Storing the password as plain text is also a severe security issue: Django will hash the password in the user mode with .create_user(…). That is not the case with how you store it in your model.
Furthermore I strongly advise to work with a form to process, validate and clean the user input: right now if a parameter is missing, it will error. Furthermore people can enter whatever they want: the email address does not need to be text that is formatted as an email address, and one can use any gender as "free text".

Related

Django save user IP each new Sign In

Each time the user logs in, I want to store the IP address in a list of the respective user, so that each user has a list with all IP addresses used during login.
How could I do this?
Custom User Model
class NewUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('E-Mail'), unique=True)
username = models.CharField(max_length=150, unique=True)
start_date = models.DateTimeField(default=timezone.now)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
last_login = models.DateTimeField(default=timezone.now)
code = models.ImageField(blank=True, upload_to='code')
objects = CustomAccountManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', ]
Views SingIn
def signin_view(request):
if request.user.is_authenticated:
return HttpResponseRedirect('/')
form = SigninForm(request.POST or None)
if form.is_valid():
time.sleep(2)
email = form.cleaned_data.get("email")
password = form.cleaned_data.get("password")
user = authenticate(request, email=email, password=password)
if user != None:
login(request, user)
return redirect("/dashboard/")
else:
request.session['invalid_user'] = 1
return render(request, "signin.html", {'form': form})
I know how to get the IP but I want to know how I save it in something like a list
The user IP address is stored within the request object. You can access it in this way:
request.META.get("REMOTE_ADDR")
If you are using PostgreSQL as your database you can use a JSONField or an ArrayField. PostgreSQL specific fields
I have never used an ArrayField but I think for this particular use case it would be more indicated than a JSONField, unless you want to store some additional information about each user's IP address.
So let's proceed:
# Step 1: Add an ArrayField of CharFields to your NewUser model
from django.contrib.postgres.fields import ArrayField
class NewUser(AbstractBaseUser, PermissionsMixin):
...
ip_address_list = ArrayField(models.CharField(max_length=15))
...
# Step 2: Refactor your view
# Here i made a little function to store the IP address because
# I had to run it twice
def store_ip_address(request):
new_user = request.user
new_user.ip_address_list.append(request.META.get('REMOTE_ADDR'))
new_user.save()
def signin_view(request):
if request.user.is_authenticated:
store_ip_address(request) ### New ###
return HttpResponseRedirect('/')
form = SigninForm(request.POST or None)
if form.is_valid():
time.sleep(2)
email = form.cleaned_data.get("email")
password = form.cleaned_data.get("password")
user = authenticate(request, email=email, password=password)
if user != None:
login(request, user)
store_ip_address(request) ### New ###
return redirect("/dashboard/")
else:
request.session['invalid_user'] = 1
return render(request, "signin.html", {'form': form})
I haven't tested this, let me know if it doesn't work

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.

How create a user and a profile with a single form in Django?

I have created a Clients model in models.py that is intended to be a Client (user) Profile.
class Clients(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
first_name = models.CharField(max_length=30, verbose_name="Primeiro Nome")
last_name = models.CharField(max_length=30, verbose_name="Apelido")
address = models.CharField(max_length=200, verbose_name="Morada")
nif = models.CharField(max_length=9, verbose_name="NIF", validators=[RegexValidator(r'^\d{1,10}$')], primary_key=True)
mobile = models.CharField(max_length=9, verbose_name="Telemóvel", validators=[RegexValidator(r'^\d{1,10}$')])
email = models.CharField(max_length=200, null=True, verbose_name="Email")
avatar = models.ImageField(null=True)
def __str__(self):
return "%s %s" % (self.first_name, self.last_name)
class Meta:
verbose_name_plural = "Clientes"
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Clients.objects.create(user=instance)
instance.profile.save()
This model is connected to the Django Users through a OneToOneField called user.
I created a form that is capable of adding data to the Clients model in forms.py:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django.core.validators import RegexValidator
class SignUpForm(UserCreationForm):
first_name = forms.CharField(max_length=30, label="Primeiro Nome")
last_name = forms.CharField(max_length=30, label="Apelido")
address = forms.CharField(max_length=200, label="Morada")
nif = forms.CharField(max_length=9, label="NIF", validators=[RegexValidator(r'^\d{1,10}$')])
mobile = forms.CharField(max_length=9, label="Telemóvel", validators=[RegexValidator(r'^\d{1,10}$')])
email = forms.CharField(max_length=200, label="Email")
class Meta:
model = User
fields = ('username', 'password1', 'password2', 'first_name', 'last_name', 'address', 'nif', 'mobile', 'email')
How can I, through this single form, add a username and password field so that, through the OneToOneField, it creates an user connected to this profile?
EDIT
The new version of the files above. Now, it creates the user, but all other fields for the Clients get passed empty.
My views.py
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save()
user.refresh_from_db() # load the profile instance created by the signal
user.first_name = form.cleaned_data.get('first_name')
user.last_name = form.cleaned_data.get('last_name')
user.address = form.cleaned_data.get('address')
user.nif = form.cleaned_data.get('nif')
user.mobile = form.cleaned_data.get('mobile')
user.email = form.cleaned_data.get('email')
user.save()
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user)
return redirect('clientes')
else:
form = SignUpForm()
return render(request, 'backend/new_client.html', {'form': form})
The fields you added are just regular form fields, django doesn't know anything about where to save these values. So you need to override the form's save() method or save them in your view. Here's how to save them in your view, since this is what you started to do:
if form.is_valid():
user = form.save() # this creates the user with first_name, email and last_name as well!
user.refresh_from_db() # load the profile instance created by the signal
user.clients.address = form.cleaned_data.get('address')
user.clients.nif = form.cleaned_data.get('nif')
user.clients.mobile = form.cleaned_data.get('mobile')
user.clients.save()
login(request, user)
return redirect('clientes')
Note: I don't do anything with first_name, last_name and email in the view, they are fields of the User model so they will already be saved automatically when you do form.save(). You should remove them from your Clients model.
Note 2: Renaming your Clients model to Client would make your code more readable. You should always use singular for your models. This way you can do user.client.address which makes more sense than user.clients.address since it's a one-to-one field.
Alternatively, you can override the form's save() method, which is a method I would prefer as I don't think the view should care about how to save the user's profile:
# in SignupForm(UserCreationForm):
def save(self, commit=True):
user = super().save(commit) # this creates the new user
if commit:
user.refresh_from_db() # not sure if this is needed
user.clients.nib = self.cleaned_data.get('nib')
user.clients.address = self.cleaned_data.get('address')
user.clients.mobile = self.cleaned_data.get('mobile')
user.clients.save()
return user

How to check username & password for custom login

models.py
class student(models.Model):
u_email = models.CharField(max_length=50)
u_username = models.CharField(max_length=50)
u_password = models.CharField(max_length=20)
view.py
def login_check(request, *args,**kwargs ):
if request.method == 'POST':
c_username= request.POST['username']
c_password = request.POST['password']
print(username,password)
how can i perform following query for authenticate student in django
"SELECT id FROM student WHERE u_username = c_username and password = c_password"
you can use django ORM and add this to your code:
students = student.objects.filter(u_username=c_username, u_password=c_password)
if students.exists():
# do whatever you like with list students .e.g:
# access to first one id with students[0].id
don't remember to add import statement in the view
from models import student
def login_check(request, *args,**kwargs ):
if request.method == 'POST':
c_username= request.POST['username']
c_password = request.POST['password']
students = student.objects.filter(u_username=c_username, u_password=c_password)
if students:
print(students[0].id)
# ...
NOTE: Please don't save your passwords as plain text. use hash functions and save their output instead (see this). you never need to know the user's password. You just want to verify an incoming user knows the password for an account.

Cannot login using user model Django

I have inserted data using User.objects.create() to the the User model and I cannot seem to login using the correct email and password. Whenever I try to Django always returns "wrong username or password" even though I have checked that the user exist using Django ORM.
However, if I register using the link on the webpage, I can login but it created a user with a blank username so I can only create one user, change the username using Django ORM, and then create another one. Is there anything I did wrong? Thanks in advance
Here is my User model:
from django.contrib.auth.models import AbstractUser, UserManager
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models import Q
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
class MyUserManager(UserManager):
def create_user(self, *args, **kwargs):
"""
Set username field as email.
"""
kwargs['email'] = self.normalize(kwargs['email'])
kwargs['username'] = self.normalize(kwargs['email'])
return super(MyUserManager, self).create_user(*args, **kwargs)
#python_2_unicode_compatible
class User(AbstractUser):
ADMIN_AREA = 'aa'
FINANCE = 'fn'
RELATIONSHIP_MANAGER = 'rm'
BUSINESS_MANAGER = 'bm'
SENIOR_BUSINESS_MANAGER = 'sbm'
ADMIN_INTERNAL = 'brm'
POSITION_CHOICES = {
(ADMIN_INTERNAL, 'Admin Internal'),
(SENIOR_BUSINESS_MANAGER, 'Senior Business Manager'),
(BUSINESS_MANAGER, 'Business Manager'),
(RELATIONSHIP_MANAGER, 'Relationship Manager'),
(FINANCE, 'Finance'),
(ADMIN_AREA, 'Admin Area')
}
name = models.CharField(_('Nama Lengkap'), blank=True, max_length=255)
phone = models.CharField('Nomor telepon', blank=True, max_length=20)
phone_alt = models.CharField('Nomor telepon alternatif', blank=True, max_length=20)
date_of_birth = models.DateField('Tanggal lahir', null=True)
leader = models.ForeignKey('self', on_delete=models.PROTECT, null=True, blank=True)
email = models.EmailField(max_length=255, unique=True)
position = models.CharField('Posisi', max_length=3, choices=POSITION_CHOICES, blank=True)
branch = models.ForeignKey(Branch, on_delete=models.PROTECT, blank=True, null=True)
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = []
def get_all_children(self, include_self=True):
"""Get all relationship manager under one user until second level."""
childs = User.objects.filter(leader=self)
if include_self:
childs = User.objects.filter(Q(id=self.id) | Q(leader=self))
return childs
objects = MyUserManager()
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('users:detail', kwargs={'email': self.email})
This is the script I used to insert the data into the model. Basically what I did is import a csv file and create a user based on the items in the file
import csv
from pertama.users.models import User
with open('zz_supporting_files/data.csv') as csvfile:
reader = csv.DictReader(csvfile)
password = "first123"
for row in reader:
name = row['NAMA']
if row['EMAIL'] == "":
email = name.split(' ')[0].lower() + "#firstone.com"
else:
email = row['EMAIL']
if row['JABATAN'] == "MARKETING":
position = "rm"
else:
position = "bm"
print(name, email, password, position) # for debugging
user = User.objects.create(
name=name,
email=email,
password=password,
username=email,
position=position,
)
user.save()
User.objects.all() # Debugging only
EDIT: Inserted the code for CSV file
You just need to tweak your command to User.objects.create_user() as this will take care of setting password correctly and you will be able to login your webpage.
Don't use User.objects.create()
The correct set of commands should be:
$ pyhton manage.py shell
Then in shell:
>>> from django.contrib.auth.models import User
>>> user=User.objects.create_user('foo', password='bar')
#Only if you want user to have superuser access, else skip this
>>> user.is_superuser=True
>>> user.is_staff=True
>>> user.save()

Categories

Resources