I've been trying creating a user profile form using built-in User of django.contrib.auth.models. Everything is working fine but after filling the fields into the form(which is displaying), I am encountering an INTEGRITY ERROR AT / saying NOT NULL CONSTRAINT failed.
You can see this image using this link to know exactly what the error is showing.
This is my models.py file
from django.db import models
from django.contrib.auth.models import User
from django.core.validators import MaxValueValidator
# Create your models here.
class UserProfileInfo(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE, null=True)
phone_number = models.PositiveIntegerField(validators=
[MaxValueValidator(9999999999)],blank=True)
def __str__(self): #This will print out this model
return self.user.username
This is my forms.py file.
from django import forms
from django.contrib.auth.models import User
from Login_Signup_Form.models import UserProfileInfo
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model=User
fields=('first_name','last_name','username','email','password',)
class UserProfileForm(forms.ModelForm):
class Meta:
model=UserProfileInfo #this is model
fields=('phone_number',)
This is my views.py file.
from django.shortcuts import render
from Login_Signup_Form.forms import UserForm,UserProfileForm
from Login_Signup_Form.models import UserProfileInfo
# Create your views here.
def index(request):
return render(request,'base.html')
def register(request):
registered=False
if request.method == 'POST':
user_form = UserForm(data=request.POST)
user_phone_number=UserProfileForm(data=request.POST)
if user_form.is_valid() and user_phone_number.is_valid():
user=user_form.save()
user.set_password(user.password)
user.save()
phone = user_phone_number.save()
phone.user=user
else:
#Printing the errors
print(user_form.errors,user_phone_number.errors)
else:
user_form = UserForm()
user_phone_number = UserProfileForm()
return render(request, 'base.html',{'user_form':user_form, '
phone_number':user_phone_number})
The error probably comes from an empty phone number in your form. You allow an empty phone_number in your form with blank=True but you don't allow it on the database level, you need to add null=True as well:
phone_number = models.PositiveIntegerField(validators=
[MaxValueValidator(9999999999)], blank=True, null=True)
See this great answer.
With blank=True the field is not required and the form will validate but it will raise the integrity error because null=True is not here. That wouldn't happen with a CharField though, the blank value would be stored as empty string. This only happens because of the PositiveIntegerField.
Related
I'm trying to make some forms that will allow users to add some objects, delete them or edit but I've stucked with thing like author of model. Let's say we got model Shot which got field
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
Because I've created custom user model to expand user by some fields that I want, and then we creating modelForm, creating views etc. and finally got form. When we will try to submit this form, it won't add this object submited in form to db because form has no filled field author author which means this field == Null and that's why it won't add this to db. So my question is how to get it dynamic, for example when user with nick "thebestuser" will try to add this modelForm it will work and mark author as "thebestuser"? Ofc I could add to form field author, but it's the worst way in my opinion and every user would be allowed then to add object for example as a another user, let's say user with nick "anothernick" could add form as a user with "thebestuser" which is In my opinion not acceptable.
models.py
from django.db import models
from django.contrib.auth.models import User
from streamers.models import Streamer
from django.conf import settings
from django.utils import timezone
class Shot(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=70)
url = models.CharField(max_length=100)
streamer = models.ForeignKey(Streamer, on_delete=models.CASCADE)
published_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
forms.py
from django import forms
from .models import Shot
class AddShot(forms.ModelForm):
class Meta:
model = Shot
fields = [
'title',
'url',
'streamer',
]
views.py
#login_required
def add_shot(request):
form = AddShot(request.POST or None)
if form.is_valid():
form.save()
instance = form.save(commit=False)
instance.published_date = request.published_date
instance.author = request.user
instance.save()
context = {
'form': form
}
return render(request, 'shots/add_shot.html', context)
You'll need to do it in your view. When you save your form pass commit=False to your save method, add your user, then save the returned instance.
def my_view(request):
form = AddShot(request.POST)
instance = form.save(commit=False)
instance.author = request.user
instance.save()
Documented here: https://docs.djangoproject.com/en/2.1/topics/forms/modelforms/#the-save-method
I have this problem:::
IntegrityError at /addproject/
NOT NULL constraint failed: BekanSite_project.owner_id. I do not know how I can fix this problem.
This is my model ::
from django.db import models
from django import forms
from django.contrib.auth.models import User
from django.core.validators import URLValidator
class Project(models.Model):
project_name = models.CharField(verbose_name='Имя
проекта',max_length=200, default='')
project_cost = models.IntegerField(verbose_name='Сумма
инвестиции',default='')
investor = models.IntegerField(verbose_name='Долья
инвестерa',default='')
email = models.EmailField(verbose_name='Почта',max_length=50,
default='')..other fields
owner = models.ForeignKey(User)
def __str__(self):
return self.owner
views.py
#login_required
def addproject(request):
if request.POST:
form = ProjectForm(request.POST, request.FILES)
if form.is_valid():
form.owner = request.user
addproject = form.save()"<<<<where it fails"
addproject.save()
return HttpResponseRedirect(reverse('accounts:profile'))
else:
form = ProjectForm()
return render(request, 'BekanSite/addproject.html',
{'form':form,'username':auth.get_user(request).username})
forms.py
from django.db import models
from django import forms
from .models import Project
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from PIL import Image
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = ['project_name','project_cost',...(other fields),]
I think it is somehow related to ForeignKey. Please help. Thanks beforehand.
You might want to attach the user before you check form is valid:
if request.POST:
form = ProjectForm(request.POST, request.FILES)
form.owner = request.user
if form.is_valid():
addproject = form.save()"<<<<where it fails"
addproject.save()
return HttpResponseRedirect(reverse('accounts:profile'))
And you dont have to call addproject.save() since form.save() does that already.
I have solved it. I don't know how it works, but I just added commit=False addproject = form.save(commit=False). I found it in the book "python-crash-course-a-hands-on-eric-matthes ". now it works.Also Thank you RajKris for your effort to solve this problem.Good luck.
I want to create a messaging function in ma django app. User should be able to write other users a textmessage.
models.py
from django.contrib.auth.models import User
class Message(models.Model):
recipient = models.ForeignKey(User, null=True)
contentDescription = models.CharField(max_length=1000, null=True)
By default, with no forms.py entry I get a selection, which will be unuseful with many users. I want the message sender to type in the user name, or in the first step the user id (which I could resolve with ajax from the name) .
Integer
But with forms.py
recipient = forms.IntegerField( widget=forms.NumberInput , required=False,)
I get:
Cannot assign "11": "Transport.recipient" must be a "User" instance.
ChoiceField and NumberInput
with:
recipient = forms.ChoiceField( widget=forms.NumberInput, required=False,)
I get the error message "not valid"
Is it possible to write the foreignkey 'manually' at all?
Try this:
recipient = forms.ModelChoiceField(queryset=User.objects.all(), widget=forms.Select, required=False)
considering your
models.py -
from django.contrib.auth.models import User
class Message(models.Model):
recipient = models.ManytoMany(User, null=True)
contentDescription = models.TextField()
forms.py
from .models import Message
from django import forms
from django.contrib.auth.models import User
class MailForm(forms.ModelForm):
recipient = forms.Charfield()
class Meta:
model = Message
fields = ('contentDescription',)
def clean_recipient(self):
user_list = self.cleaned_data.get('recipient')
# considering you post user_list of usernames as 'username1,username2,username3'
if user_list is not None:
user_list = user_list.split(',')
user_qs = User.objects.filter(username__in=userlist)
else:
raise forms.ValidationError('Error in this field')
return user_qs
def save(self, user_qs):
self.instance.user = user_qs
return super().save()
in views.py -
from .forms import MailForm
def your_view(request):
form = MailForm(request.POST or None)
if form.is_valid():
user_qs=form.cleaned_data.get('recipient')
form.save(user_qs)
#return render here
else:
#create your context here and return render
This is not perfect but can give you an idea how to implement. With the details you gave this is the best I can do for now.
Since django User model had only few fields in it, I made a custom model and used it's ModelForm to save data to User model and the custom model. The models.py is as shown below
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
import datetime
class Post(models.Model):
Author=models.ForeignKey(User)
title=models.CharField(max_length=66)
content=models.TextField()
created_date=models.DateField(default=datetime.datetime.now())
published_date=models.DateField()
def publish(self):
self.published_date=datetime.datetime.now()
self.save()
class UserDetails(models.Model): #the custom model
uname=models.CharField(max_length=55)
first_name=models.CharField(max_length=55)
last_name=models.CharField(max_length=55)
age=models.IntegerField()
contact=models.CharField(max_length=13)
email=models.EmailField()
pword=models.CharField(max_length=55)
modelform :
class RegisterForm(ModelForm):
class Meta:
model=UserDetails
fields=['uname','pword','first_name','last_name','email','contact']
the views.py is like this
from django.shortcuts import render
from .models import UserDetails
# Create your views here.
from django.contrib.auth import authenticate,login,logout
from .forms import RegisterForm,LoginForm,PostForm
from django.contrib.auth.models import User
from django.db import IntegrityError
def register(request):
if request.method=='POST':
form=RegisterForm(request.POST)
try:
if form.is_valid():
form.save()
uname=form.cleaned_data['uname']
fname=form.cleaned_data['first_name']
pword=form.cleaned_data['pword']
email=form.cleaned_data['email']
contact=form.cleaned_data['contact']
lname=form.cleaned_data['last_name']
user=User.objects.create_user(uname,password=pword,email=email)
user.last_name=lname
user.save()
#form.save()
#stuff after registration
message="registration done! login again"
return render(request,'register.html',locals())
except IntegrityError:
message="username already exists!! try another"
else:
form=RegisterForm()
return render(request,'register.html',locals())
The problem is that even if I make a fresh entry to the RegisterForm, the 'message' I get is, username already exists!! try another. The auth.User model is getting updated but UserDetails is not. What am I doing wrong? (spare me if this is a stupid question :) )
update: 1
from django.shortcuts import render
from .models import UserDetails
# Create your views here.
from django.contrib.auth import authenticate,login,logout
from .forms import RegisterForm,LoginForm,PostForm
from django.contrib.auth.models import User
from django.db import IntegrityError
def register(request):
if request.method=='POST':
form=RegisterForm(request.POST)
try:
if form.is_valid():
form.save()
uname=form.cleaned_data['uname']
fname=form.cleaned_data['first_name']
pword=form.cleaned_data['pword']
email=form.cleaned_data['email']
contact=form.cleaned_data['contact']
lname=form.cleaned_data['last_name']
if not User.objects.filter(username=uname,email=email).exists():
user=User.objects.create_user(uname,password=pword,email=email)
user.last_name=lname
user.save()
message="registration done! login again"
return render(request,'register.html',locals())
except IntegrityError:
message="username already exists!! try another"
else:
form=RegisterForm()
return render(request,'register.html',locals())
if form.is_valid():
# save a UserDetails obj (data are automatically get from the form) to db.
form.save()
# Get data from form
uname = form.cleaned_data['uname']
fname = form.cleaned_data['first_name']
pword = form.cleaned_data['pword']
email = form.cleaned_data['email']
contact = form.cleaned_data['contact']
lname = form.cleaned_data['last_name']
# Check if user already exists. If it doesn't, create it
if not User.objects.filter(username=uname, email=email).exists():
user=User.objects.create_user(uname, password=pword, email=email)
#stuff after registration
message = "registration done! login again"
return render(request,'register.html',locals())
See more on the ModelForm's save() method.
However, I noticed that the age model field is required. So, the save() will complain. You should better make it as: age = models.IntegerField(blank=True, null=True) or define a default value like this age = models.IntegerField(default=20). Although, defining a default age is awkward, better follow the blank=True null=True to allow empty ages.
Age was missing in model form Fields
I'm been using the default user model in django for quite a abit and I realize , if I need to further enhance it , I would have to create my own custom User Model in django 1.5 .
I created my custom user model and I have a function which allows users to sign in .
I think my custom user model is incompatible with my function because it wouldn't allow me to do request.user . How can I fix this so I can use request.user again?
views
def LoginRequest(request):
form = LoginForm(request.POST or None)
if request.user.is_authenticated():
username = User.objects.get(username=request.user)
url = reverse('world:Profile', kwargs = {'slug': person.slug})
return HttpResponseRedirect(url)
if request.POST and form.is_valid():
user = form.authenticate_user()
login(request, user)
username= User.objects.get(username=request.user)
person = Person.objects.get(user=request.user)
url = reverse('world:Profile', kwargs = {'slug': person.slug})
return HttpResponseRedirect(url)
return render(request, 'login.html',{'form': form})
models
class PersonManager(BaseUserManager):
def create_user(self, email,date_of_birth, username,password=None,):
if not email:
msg = 'Users must have an email address'
raise ValueError(msg)
if not username:
msg = 'This username is not valid'
raise ValueError(msg)
if not date_of_birth:
msg = 'Please Verify Your DOB'
raise ValueError(msg)
user = self.model(
email=PersonManager.normalize_email(email),username=username,date_of_birth=date_of_birth)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self,email,username,password,date_of_birth):
user = self.create_user(email,password=password,username=username,date_of_birth=date_of_birth)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class Person(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(verbose_name='email address',max_length=255,unique=True,db_index=True,)
username = models.CharField(max_length=255, unique=True)
date_of_birth = models.DateField()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'date_of_birth',]
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
objects = PersonManager()
def get_full_name(self):
return self.email
def get_short_name(self):
return self.email
def __unicode__(self):
return self.email
The problem is that User refers to django.contrib.auth.models.User and now you have got a Custom User pet.Person assuming you have in the settings.py
AUTH_USER_MODEL = "pet.Person"
you have to define User with the Custom User model and you can do this with get_user_model at the top of the file where you use User
from django.contrib.auth import get_user_model
User = get_user_model()
now you will be able to use Custom User model and the problem has been fixed.
For anyone else who might come across this problem, I also solved it by simply doing this on forms.py:
add this at the top of the forms.py file
from .models import YourCustomUser
and then add this to your forms.py CustomUser form:
class SignUpForm(UserCreationForm):
#profile_year = blaaa blaa blaaa irrelevant.. You have your own stuff here don't worry about it
# here is the important part.. add a class Meta-
class Meta:
model = YourCustomUser #this is the "YourCustomUser" that you imported at the top of the file
fields = ('username', 'password1', 'password2', #etc etc, other fields you want displayed on the form)
BIG NOTES, ATTENTION:
This code worked for my case. I have a view for signing users up, I had a problem here and I solved it, I haven't tried it for logging in users.
The include = () part is required, or you can add exclude = (), but you have to have one
Important caveat to update the above solutions...
If you're facing this kind of problem, you've probably tried various solutions around the web telling you to add AUTH_USER_MODEL = users.CustomUser to settings.py and then to add the following code to views.py forms.py and any other file that calls User:
from django.contrib.auth import get_user_model
User = get_user_model()
And then you scratch your head when you get the error:
Manager isn't available; 'auth.User' has been swapped for 'users.User'
Anytime your code references User such as:
User.objects.get()
Cause you know you already put objects = UserManager() in your custom user class (UserManager being the name of your custom manager that extends BaseUserManager).
Well as it turns out doing:
User = get_user_model() # somewhere at the top of your .py file
# followed by
User.objects.get() # in a function/method of that same file
Is NOT equivalent to:
get_user_model().objects.get() # without the need for User = get_user_model() anywhere
Perhaps not intuitive, but it turns out that that in python, executing User = get_user_model() once at the time of import does not then result in User being defined across subsequent calls (i.e. it does not turn User into a "constant" of sorts which you might expect if you're coming from a C/C++ background; meaning that the execution of User = get_user_model() occurs at the time of imports, but is then de-referenced before subsequent called to class or function/method in that file).
So to sum up, in all files that reference the User class (e.g. calling functions or variables such as User.objects.get() User.objects.all() User.DoesNotExist etc...):
# Add the following import line
from django.contrib.auth import get_user_model
# Replace all references to User with get_user_model() such as...
user = get_user_model().objects.get(pk=uid)
# instead of user = User.objects.get(pk=uid)
# or
queryset = get_user_model().objects.all()
# instead of queryset = User.objects.all()
# etc...
Hope this helps save others some time...
In forms.py
# change
from django.contrib.auth.models import User
# to
from django.contrib.auth import get_user_model
Then add the following code at the top
User = get_user_model()
All the solutions provided above did not work in my case. If you using Django version 3.1 there is another solution for you:
In auth/forms, comment out line 10 and change the model in line 104 & 153 to your defined model.