how to fix no null constraint in django - python

I am creating a user using OneToOne relationship , when I enter the data in the form and submit it, I'm getting no null constraint error
view.py
def registerUser(request):
if request.method=='POST':
form=UserCreationForm(request.POST)
form_class=ProfileForm(request.POST)
if form.is_valid() and form_class.is_valid():
form.save()
form_class.save()
return redirect('/home/')
else:
form=UserCreationForm()
form_class = ProfileForm()
return render(request,'register.html',{'form':form,'form_class':form_class})
form.py
class Registerform(UserCreationForm):
class Meta:
model=User
fields= ['username','first_name','last_name','password1','password2']
def save(self, commit=True):
user=super(Registerform, self).save(commit=False)
user.first_name=self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
if commit:
user.save()
return user
class ProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = [ 'location']
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
description = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
salary=models.CharField(max_length=120)
def __str__(self):
return self.location

Your UserProfile model requires a salary but your form only has a location field. So when your form is submitted with a location, it's valid, but the underlying model cannot be saved because salary will be None.
Add the salary field to your form, or make salary a nullable field.
Also, you need to assign the user field before saving the profile, since that also is not nullable. One way to do that is:
user = form.save() # this is the UserForm so when saving it returns the user
profile = form_class.save(commit=False)
profile.user = user
profile.save()
I would recommend you carefully read the Django documentation on model forms. The section on the save method in particular would explain you how to properly handle these cases.

Related

'User' object has no attribute 'user_type' - Django Custom User model issue

I've created a custom user abstract model and profile model to collect additional information once the user registers.
I am collecting "User type: Employer/employee" at the time of registration but this doesn't seem to be recognized in the profile view. Despite the user being correctly added into the DB (I checked via Admin).
For example, I created user: asus23910 (employer user type). But when I login and redirect to http://127.0.0.1:8000/employer_profile/asus23910/, I get following error:
'User' object has no attribute 'user_type'C:\Users\ASUS\PycharmProjects\Content\content\content\views.py, line 112, in employer_profile_view
1. Here's my employer_profile_view.py code:
def employer_profile_view(request, username):
user = User.objects.get(username=username)
if user.user_type != User.EMPLOYER:
# Redirect to the correct profile page if the user type is not employer
return redirect('employee_profile', username=request.user.username)
if request.method == 'POST':
form = EmployerProfileForm(request.POST, instance=user.employerprofile)
if form.is_valid():
employer_profile = form.save(commit=False)
employer_profile.user = user
employer_profile.save()
return redirect('employer_profile', username=request.user.username)
else:
form = EmployerProfileForm(instance=user.employerprofile)
context = {
'form': form,
'username': username,
}
return render(request, 'employer_profile.html', context)
2. Employer Profile model and connector
class EmployerProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
user_type = models.CharField(
max_length=10,
choices=User.USER_TYPE_CHOICES,
default=User.EMPLOYER
)
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
title = models.CharField(max_length=255)
company_name = models.CharField(max_length=255)
company_logo = models.ImageField(upload_to='company_logos/')
company_location = models.CharField(max_length=255)
company_website = models.URLField()
company_twitter = models.URLField()
#one-2-one connector
#receiver(post_save, sender=User)
def create_employer_profile(sender, instance, created, **kwargs):
if created:
EmployerProfile.objects.create(user=instance, user_type=instance.user_type)
print('Employer Profile created')
#receiver(post_save, sender=User)
def save_employer_profile(sender, instance, **kwargs):
instance.employerprofile.user_type = instance.user_type
instance.employerprofile.save()
print('Employer Profile saved')
3. User model
#model one to store the user into db
class User(AbstractUser):
EMPLOYER = "employer"
EMPLOYEE = "employee"
USER_TYPE_CHOICES = [
(EMPLOYER, "Employer"),
(EMPLOYEE, "Employee"),
]
user_type = models.CharField(
max_length=10,
choices=USER_TYPE_CHOICES,
default=EMPLOYEE
)
email = models.EmailField(default='example#example.com')
username = models.CharField(max_length=150, default='example_user')
password = models.CharField(max_length=128, default='!')
groups = models.ManyToManyField(
Group,
blank=True,
related_name='content_groups'
)
user_permissions = models.ManyToManyField(
Permission,
blank=True,
related_name='content_user_permissions'
)
`
**
What I've tried:**
Flushing and starting new DB (as I used in-built Django user model before and some old users weren't fairing well with the new user-type field).
Adding the user type with default employer option to employer view and fetching the usertype from user model.
**
What I expect:**
The profile view to connect with the custom user model and allow the user to add additional information to their user profile. And ofcourse the profile page to have the user-type attribute as initially stored from user class.
You probably import User not from your models file, but from django.
Anyway I highly recommend (if you overwrote AUTH_USER_MODEL) using built-in get_user_model() method from Django e.g.:
from django.contrib.auth import get_user_model
def employer_profile_view(request, username):
user = get_user_model().objects.get(username=username)
if user.user_type != User.EMPLOYER:
...
And don't use User name for model, I prefer to use CustomUser by myself but you can name it differently, just to avoid mistakes.

How to create sign up form for customer user model in Django?

I have extended the User Model provided by Django into Owner object. What I intend to do, is create a sign up form which creates a new user in my application and also fill up the custom fields defined in Owner object. My code is as follows -
model.py -
class Owner(BaseModel):
id = models.AutoField(primary_key=True)
gym = models.ForeignKey(Gym, on_delete = models.CASCADE)
# User model
user = models.OneToOneField(User, on_delete = models.CASCADE)
address = models.OneToOneField('Address', on_delete=models.CASCADE)
contact = models.BigIntegerField(null=False)
dob = models.DateTimeField(null=True)
gender = models.CharField(max_length=10, choices=GENDER_CHOICES, null=True, default=None)
profile_photo = models.ImageField( upload_to='static/images/gym_owner/profile', null=True, blank=True)
def __str__(self):
return f'{self.user.first_name} {self.user.last_name}'
class Meta:
verbose_name_plural = "Owner"
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Owner.objects.create(user=instance)
instance.owner.save()
SO basically, Owner model extends the User model via One-to-One relationship method. And there is a signal receiver method which creates the Owner object when User object is created.
Forms.py -
class OwnerForm(ModelForm):
class Meta:
model = Owner
fields = ('gym', 'address', 'contact', 'gender', 'profile_photo')
The form basically contains the fields that I want to extend the User model with.
And the view.py -
#transaction.atomic
def owner_signup(request):
if request.user.is_authenticated:
return redirect('dashboard')
if request.method == 'GET':
userForm = UserCreationForm()
ownerForm = OwnerForm()
return render(request, 'gym_owner/signup.html', {'userform': userForm, 'ownerForm': ownerForm})
if request.method == 'POST':
userForm = UserCreationForm(request.POST)
ownerForm = OwnerForm(request.POST)
if userForm.is_valid() and ownerForm.is_valid():
user = userForm.save()
user.refresh_from_db()
ownerForm = OwnerForm.save(request.POST, instance=user.owner)
ownerForm.full_clean()
ownerForm.save()
#form.save()
username = userForm.cleaned_data.get('username')
password = userForm.cleaned_data.get('password1')
user = authenticate(username=username, password=password)
login(request, user)
return render(request, 'gym_owner/dashboard.html')
else:
# If there were errors, we render the form with these
# errors
return render(request, 'gym_owner/signup.html', {'userform': userForm, 'ownerForm': ownerForm})
The above code uses this as reference.
The above code basically creates a UserCreationForm provided by Django which is used to create the user and once the user is saved to db, the Owner object is created on it. However, when I click on submit, error occurs.
When form is submitted - below is the form rendered by Django
Upon submission , I receive the following error -
IntegrityError at /owner/signup
NOT NULL constraint failed: gym_owner_owner.contact
Request Method: POST
Request URL: http://localhost:8000/owner/signup
Django Version: 2.2.2
Exception Type: IntegrityError
Exception Value:
NOT NULL constraint failed: gym_owner_owner.contact
Exception Location: C:\Users\Dev\Desktop\Django-Test\venv\lib\site-packages\django\db\backends\sqlite3\base.py in execute, line 383
Python Executable: C:\Users\Dev\Desktop\Django-Test\venv\Scripts\python.exe
Python Version: 3.6.6
Python Path:
['C:\\Users\\Dev\\Desktop\\Django-Test\\gym',
'C:\\Users\\Dev\\Desktop\\Django-Test\\venv\\Scripts\\python36.zip',
'C:\\Users\\Dev\\Desktop\\Django-Test\\venv\\DLLs',
'C:\\Users\\Dev\\Desktop\\Django-Test\\venv\\lib',
'C:\\Users\\Dev\\Desktop\\Django-Test\\venv\\Scripts',
'c:\\users\\Dev\\appdata\\local\\programs\\python\\python36-32\\Lib',
'c:\\users\\Dev\\appdata\\local\\programs\\python\\python36-32\\DLLs',
'C:\\Users\\Dev\\Desktop\\Django-Test\\venv',
'C:\\Users\\Dev\\Desktop\\Django-Test\\venv\\lib\\site-packages']
Server time: Thu, 20 Jun 2019 05:49:02 +0000
The contact field in the model should probably be a
Not requiring an input:
contact = models.CharField(max_length=10, null = True, blank = True)
Requiring an input:
contact = models.CharField(max_length=10)
If you use an IntegerField for the phone number, usually people will type in '-' or '.' between the sets of numbers (123-123-1234), this will result in an error.
But if you want to keep it as an Integer it would be:
contact = models.IntegerField()
Django docs for it are here https://docs.djangoproject.com/en/2.2/topics/db/models/#fields

How to set dynamic initial values to django modelform field

I'm kinda new to django, I need to set a dynamic initial value to my modelform field. I have a database field in my model name 'author' it has a foreignkey that connects it to the django user model. I need to automatically set this to the current user anytime a user fills in information into the form.
from what I gathered about this problem, I'd have to define an __init__ function inside the MyHouseEditForm below, I'm new to django and all the examples I've seen a pretty confusing.
forms.py
from django import forms
from django.contrib.auth.models import User
from .models import Myhouses
class MyHouseEditForm(forms.ModelForm):
class Meta:
model = Myhouses
fields = ('author','name_of_accomodation', 'type_of_room', 'house_rent', 'availability', 'location', 'nearest_institution', 'description', 'image')
i need to set the value of 'author' to the current user anytime a user logs in.
models.py
from django.db import models
from django.contrib.auth.models import User
class Myhouses(models.Model):
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='author')
Available = 'A'
Not_Available = 'NA'
Availability = (
(Available, 'Available'),
(Not_Available, 'Not_Available'),
)
name_of_accomodation = models.CharField(max_length=200)
type_of_room = models.CharField(max_length=200)
house_rent = models.IntegerField(null=True)
availability = models.CharField(max_length=2, choices=Availability, default=Available,)
location = models.CharField(max_length=200)
nearest_institution = models.CharField(max_length=200)
description = models.TextField(blank=True)
image = models.ImageField(upload_to='profile_image')
def __str__(self):
return self.name_of_accomodation
views.py
#login_required
def addlisting(request):
if request.method == 'POST':
form = MyHouseEditForm(request.POST, files=request.FILES)
if form.is_valid():
Houses = form.save(commit=False)
Houses.save()
return redirect('addlisting')
else:
form = MyHouseEditForm()
return render(request, 'houses/addlisting.html', {'form':form })
No need to show author field in form. It would automatically populate with logged in user.
request.user gives you logged in user object. So, you may remove 'author' filed from forms field section and do this:
Houses = form.save(commit=False)
Houses.author = request.user
Houses.save()
I did something like this in the serializer.
I defined a custom create method like this:
class MyhousesSerializer(FlexFieldsModelSerializer):
...
def create(self, validated_data):
validated_data['author'] = self.context['request'].user
newhouse = Myhouses.objects.create(**validated_data)
return newhouse
It shouldn't matter if you use a more regular model serializer.

Automatically attaching the logged in user to a post he/she creates

What a want to do: When a user is logged in, and he or she makes a post, the name of that user should automatically be assigned in my database posts.
What it's doing: It's not adding a user automatically, but i am able to assign a user manually, so I'm accessing the user database, and seeing whom i can attach to a newly made post.
My question is then, how can i get this process done automatically?
Here is my code from the model.py in the posts app:
from __future__ import unicode_literals
from django.conf import settings
from django.core.urlresolvers import reverse
from django.db import models
from django.contrib.auth.models import User
User = settings.AUTH_USER_MODEL
class Post(models.Model):
title = models.CharField(max_length=120)
content = models.TextField()
#email = models.EmailField(null=True, blank=True, default=None)
user = models.ForeignKey(User, null=True,)
#upload = models.FileField(null=True, blank=True, default=None)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=True, auto_now_add=False)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("posts:detail", kwargs={"id":self.id})
class Meta:
ordering = ["-timestamp", "-updated"]
I am getting the user class via User = settings.AUTH_USER_MODEL and the AUTH_USER_MODEL is referring in settings.py to a class called MyUser in another models.py who originates from an app called accounts.
here is the code from that class:
class MyUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
is_admin = models.BooleanField(_('staff status'), default=False,
help_text=_('Designates whether the user can log into this admin site.'))
is_active = models.BooleanField(_('active'), default=True,
help_text=_('Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.'))
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
USERNAME_FIELD = 'email'
Here is the code from views.py in the posts app:
def post_create(request):
form = PostForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
# Message succes
messages.success(request, "Succesfully Created ")
return HttpResponseRedirect(instance.get_absolute_url())
else:
messages.error(request, "Not Succesfully created")
context = {
'form': form,
}
return render(request, app_name+"/post_form.html", context)
Here is the forms.py in the posts app:
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = {
"title",
"content",
"user",
#"email",
#"upload",
}
Here are two pictures to illustrate my problem:
The post create site
The django administration
Let me now if any more code is needed, appreciate any feedback as well.
I don't have a lot of rep on stack overflow so please let me know if this is poorly explained, and i shall re right it.
Simply change:
instance = form.save(commit=False)
instance.save()
to
instance = form.save(commit=False)
if request.user.is_authenticated():
instance.user = request.user
instance.save()
If user is logged in, i think the Combobox should not
appear, so you can do that on forms.py
forms.py
class PostForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super(PostForm, self).__init__(*args, **kwargs)
if not self.user.is_authenticated():
self.fields['user'] = forms.ModelChoiceField(
required=True,
queryset=User.objects.all())
class Meta:
model = Post
fields = {
"title",
"content",
# "user",
#"email",
#"upload",
}
on views.py
def post_create(request):
form = PostForm(request.POST or None, user = request.user)
if form.is_valid():
if request.user.is_authenticated():
form.instance.user = request.user
form.save()
...
return render(request, app_name+"/post_form.html", context)
If you want the Combobox has selected with the user logged in, you can pass initial data on views.py, like this:
def post_create(request):
if request.method == 'GET':
form = PostForm(initial = {'user' : request.user})

How to make a Foreign Key with unique=true to be "optional" in Django?

I have a User Model (pre-defined by Django) and a UserProfile model connected via a ForeignKey.
I'm creating two separate ModelForms to use in a single template as a registration form of sorts.
models.py
class UserProfile(models.Model):
# This field is required.
user = models.ForeignKey(User, unique=True, related_name="connector")
location = models.CharField(max_length=20, blank=True, null=True)
forms.py
class UserForm(ModelForm):
class Meta:
model = User
class UserProfileForm(ModelForm):
class Meta:
model = UserProfile
However, when I load the page and fill in the form information, the UserProfileForm requires me to select / fill in the user field in order to validate.
This "user", however, is the one that is being created right now so I can't choose a "user" as it has not been created yet / is still being created.
I know this user is field has the attribute unique=true but there a way to make this field "optional"?
My view (below) should handle it such that once the user object is created, i will set the foreign key of UserProfile to this newly created user object (unless I am doing something wrong my views.py as well).
views.py
#csrf_protect
def register(request):
if request.method == 'POST':
form1 = UserForm(request.POST)
form2 = UserProfileForm(request.POST)
if form1.is_valid() and form2.is_valid():
#create initial entry for user
username = form1.cleaned_data["username"]
password = form1.cleaned_data["password"]
new_user = User.objects.create_user(username, password)
new_user.save()
#create entry for UserProfile (extension of new_user object)
profile = form2.save(commit = False)
profile.user = new_user
profile.save()
return HttpResponseRedirect("/books/")
else:
form1 = UserForm()
form2 = UserProfileForm()
c = {
'form1':form1,
'form2':form2,
}
c.update(csrf(request))
return render_to_response("registration/register.html", c)
Well you could set:
user = models.ForeignKey(User, unique=True, blank=True, null=True, related_name="connector")
which would make the user relationship optional, but I don't think this is what you need. Instead, why not just remove the user field from the UserProfile form and manually assign it, instead of letting the user see the dropdown at all. Then there would be no validation error.
class UserProfileForm(ModelForm):
class Meta:
model = UserProfile
exclude = ("user", )
Simply exclude the field from the form.
class UserProfileForm(ModelForm):
class Meta:
model = UserProfile
exclude = ('user',)

Categories

Resources