Integrity error with django user model - python

I'm working through https://bixly.com/blog/awesome-forms-django-crispy-forms/ , trying to set up a bootstrap 3 form using django crispy forms.
in app1/models.py, I have set up my model:
from django.db import models
from django.contrib.auth.models import User
from django.contrib.auth.models import AbstractUser
from django import forms
class User(AbstractUser):
# Address
contact_name = models.CharField(max_length=50)
contact_address = models.CharField(max_length=50)
contact_email = models.CharField(max_length=50)
contact_phone = models.CharField(max_length=50)
......
app1/forms.py:
class UserForm(forms.ModelForm):
class Meta:
model = User # Your User model
fields = ['contact_name', 'contact_address', 'contact_email', 'contact_phone']
helper = FormHelper()
helper.form_method = 'POST'
helper.form_action = "/contact/"
helper.form_id = 'form' # SET THIS OR BOOTSTRAP JS AND VAL.JS WILL NOT WORK
helper.add_input(Submit('Submit', 'Submit', css_class='btn-primary'))
app1/views.py:
def contact(request):
django_query_dict = request.POST
message = django_query_dict.dict()
if request.method == 'POST':
print "im in contact "+str(message)
form = UserForm(request.POST)
if form.is_valid():
form.save()
else:
print('invalid')
I've been able to get it working for the first record (screenshot above). However because I'm using/extending the user model I'm running into problems with the built in user registration functionality. When I try to add a second record I get:
Exception Type: IntegrityError at /contact/
Exception Value: column username is not unique
Request information:
GET: No GET data
I can see that this is true because I am not getting data for username in the form, so a blank will be entered both the first and second record causing the integrity error the second time. How can I fix this. Should I even be using the built in user model?

Related

'RegisterForm' object has no attribute 'is_valid'

This Is models.py
from django.db import models
class RegisterForm(models.Model):
fname = models.CharField(max_length=100)
lname = models.CharField(max_length=100)
pno = models.CharField(max_length=100)
email = models.EmailField(max_length=200)
pass1 = models.CharField(max_length=100)
pass2 = models.CharField(max_length=100)
This is my Views.py
from django.shortcuts import render
from .models import RegisterForm
# Create your views here.
def registerView(request):
if request.method=='POST':
fm = RegisterForm(request.POST)
if fm.is_valid():
fname = fm.cleaned_data['fname']
lname = fm.cleaned_data['lanme']
pno = fm.cleaned_data['pno']
email = fm.cleaned_data['email']
pass1 = fm.cleaned_data['pass1']
pass2 = fm.cleaned_data['pass2']
reg = RegisterForm.save(fname = fname,lname=lname,pno=pno,email=email,pass1=pass1,pass2=pass2)
reg.save()
fm = RegisterForm()
else:
fm = RegisterForm()
return render(request, 'register.html', {})
Request Method: POST
Request URL: http://127.0.0.1:8000/
Django Version: 3.2
Exception Type: AttributeError
Exception Value: 'RegisterForm' object has no attribute 'is_valid'
Exception Location: H:\Django\authetication\users\views.py, line 7, in registerView
You created a model, not a form.
Now you need to create forms.py in-app
from django import forms
from .models import Profile
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = '__all__'
You can use all for all fields in the model but you can put only chosen fields in the form via tuple ('field_name', 'field_name')
Your RegisterForm is a model, not a model form, hence RegisterForm(request.POST) makes no sense, and your RegisterForm has no .is_valid(…) method. A model deals with storing data in the database, whereas a form will receive, validate and clean data.
It looks like you want to define a profile, so you can implement a Profile model:
# app_name/models.py
from django.db import models
class Profile(models.Model):
fname = models.CharField(max_length=100)
lname = models.CharField(max_length=100)
pno = models.CharField(max_length=100)
email = models.EmailField(max_length=200)
pass1 = models.CharField(max_length=100)
pass2 = models.CharField(max_length=100)
and then define a ModelForm based on that model:
# app_name/forms.py
from django import forms
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = '__all__'
Then in the view you can work with:
from django.shortcuts import render
from .forms import ProfileForm
def registerView(request):
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid():
form.save()
return redirect('name-of-some-view')
else:
form = ProfileForm()
return render(request, 'register.html', {'form': form})
You however should probably make modifications to your model: only use one field where you store the password, and likely the password should be hashed to prevent a data leak in case data of your database got stolen. Django already has a user model, and thre documentation has a section named Customizing authentication in Django. That can help you define a model for a user, and register that user.
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.

How do I add username of logged in user to model field in django

How to add username of currently logged in user to field in my model? For example, I need to store info about user like name, email and so on in model, other than default Django user model, but I still use default one to store credentials. I want to establish relationship between those, so I created username field in my model. How do I fill it with current user's username upon saving the corresponding form?
My model
class ApplicantProfile(models.Model):
name = models.CharField(max_length = 50)
dob = models.DateField()
email = models.EmailField()
description = models.TextField()
username = <something>
What do I change <something> with?
My form
class ApplicantProfileEdit(forms.ModelForm):
class Meta:
model = ApplicantProfile
fields = [
'name',
'dob',
'email',
'description',
]
My view
def ApplEditView(request):
form = ApplicantProfileEdit(request.POST or None)
if form.is_valid():
form.save()
form = ApplicantProfileEdit()
context = {
'form':form
}
return render(request, "applProfileEdit.html", context)
P.S. I tried to import models straight to my views.py, and assign request.user.username to username field of the model in my view, but it didn't work, just left that field empty. I had username as CharField when I tried this.
It is not a good idea to save the username itself, or at least not without a FOREIGN KEY constraint. If later a user changes their name, then the username now points to a non-existing user, if later another user for example changes their username to thatusername, then your ApplicantProfile will point to the wrong user.
Normally one uses a ForeignKey field [Django-doc], or in case each ApplicantProfile points to a different user, a OneToOneField [Django-doc]:
from django.conf import settings
from django.db import models
class ApplicantProfile(models.Model):
name = models.CharField(max_length = 50)
dob = models.DateField()
email = models.EmailField()
description = models.TextField()
# maybe a OneToOneField
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
In the view:
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
#login_required
def appl_edit_view(request):
if request.method == 'POST':
form = ApplicantProfileEdit(request.POST)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('some-view-name')
else:
form = ApplicantProfileEdit()
context = {
'form':form
}
return render(request, 'applProfileEdit.html', context)
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].

Save data in associative model using one query in django

I am working on registration module in django project. for registering user i am using auth_user table for extending this table i have created one more model Profile
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
start_date = models.DateField()
phone_number = models.CharField(max_length=12)
address = models.CharField(max_length=225)
subscription = models.BooleanField(default=False)
Profile table has been created successfully. Now what i want to do is when i submit the registration form, the fields related to Profile model within registration form should be inserted automatically after inserting fields related to auth_user model.
Means i don't want to first insert data in auth_user model and then after getting it's id again insert data in Profile table.
I want to insert complete record in one query. Is it possible ?
I think you can define a registration form and override the form save method to save the Profile when creating the User model. Sample code for your reference:
class RegistrationForm(forms.ModelForm):
start_date = forms.DateField()
phone_number = forms.CharField()
address = forms.CharField()
subscription = forms.BooleanField()
class Meta:
model = User
def save(self, commit=True):
instance = super(RegistrationForm, self).save(commit=commit)
profile = Profile(user=instance, start_date=self.cleaned_data['start_date'], phone_number=self.cleaned_data['phone_number'], address=self.cleaned_data['address'], subscription=self.cleaned_data['subscription'])
profile.save()
return instance
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = form.save()
# do anything after user created
else:
raise Error('form validate failed')
else:
# handling the GET method

Django 1.9 using django sessions in two page forms

How can I use Django sessions to have a user be able to start a form on one page, and move to the next page and have them complete the form?
I have looked into pagination and wizard forms, but I don't get them at all.
When I have one page with a small portion of a model I'm using - in forms - and another page with the rest of the model - forms.py with the rest of the model info - I can use the first form perfectly.
But when I move to the next page, I get an error saying (1048, "Column 'user_id' cannot be null").
My best guess is to use Django sessions to fix this issue. I don't want the user to have to put in their username and password a second time to get this to work. Any ideas?
my models/forms.py:
class Contact(models.Model):
user = models.OneToOneField(User)
subject = models.CharField(max_length=100, blank=True)
sender = models.EmailField(max_length=100, blank=True)
message = models.CharField(max_length=100, blank=True)
def __str__(self):
return self.user.username
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = Contact
fields = ('username', 'password', 'email')
class ContactForm1(forms.Form):
class Meta:
model = Contact
fields = ('subject', 'sender')
class ContactForm2(forms.Form):
message = forms.CharField(widget=forms.Textarea)
class Meta:
model = Contact
fields = ('message',)
views:
def contact(request):
registered = False
if request.method =='POST':
user = UserForm(request.POST)
contact = ContactForm1(request.POST)
if user.is_valid() and contact.is_valid():
user = user.save()
user.set_password(user.password)
user.save()
contact = contact.save(commit=False)
contact.user = user
registered = True
return render(request, 'mysite/contact.html', {'user': user, 'contact': contact, 'registered': registered})
def contact_second(request):
if request.method =='POST':
contact = ContactForm2(request.POST)
if contact.is_valid():
contact = contact.save(commit=False)
contact.save()
return render(request, 'mysite/contact_two.html', {'contact': contact}
I think it's a good idea to use sessions to store the forms because you don't want on each page to store the user input into the database because what if s/he change mind in the 3rd page and s/he wants to discard the registration or whatever it is?
I think is better to store the forms in session until you get in the last page, you ensure that everything is valid and then save the data in the database.
So let's say that the bellow code is in one of the view that will serve the first form/page. You retrieve the data from the POST request and you check if the given data are valid using the form.is_valid(), you then store the form.cleaned_data (which contains the user's validated data) to a session variable.
form = CustomForm(request.POST)
...
if form.is_valid():
request.session['form_data_page_1'] = form.cleaned_data
Note here that you may need to add code to redirect the user to the next page if form.is_valid() is true, something like this:
if form.is_valid():
request.session['form_data_page_1'] = form.cleaned_data
return HttpResponseRedirect(reverse('url-name-of-second-page'))
Then in any other view let's say in the view that is going to serve the second page you can retreive the from data from the first page like this:
first_page_data = request.session['form_data_page_1']
And you can do whatever you want with them as if it was after you executed the form.is_valid() in the first view.

Tango With Django: User Authentication - User being saved but not receiving confirmation

I am on chapter 9 of Tango With Django:
http://www.tangowithdjango.com/book17/chapters/login.html#demo
Whenever I create a user, I get an error page on my browser as shown below:
IntegrityError at /rango/register/
rango_userprofile.user_id may not be NULL
Request Method: POST
Request URL: http://127.0.0.1:8000/rango/register/
Django Version: 1.7.1
Exception Type: IntegrityError
Exception Value:
rango_userprofile.user_id may not be NULL
Exception Location: C:\Python27\lib\site-packages\django\db\backends\sqlite3\base.py in execute, line 485
Python Executable: C:\Python27\python.exe
Python Version: 2.7.8
Python Path:
['C:\\Users\\Paul.Zovighian\\desktop\\tango\\tango_with_django_project',
'C:\\Python27\\lib\\site-packages\\pandas-0.14.1-py2.7-win32.egg',
'C:\\Python27\\lib\\site-packages\\pytz-2014.7-py2.7.egg',
'C:\\Windows\\system32\\python27.zip',
'C:\\Python27\\DLLs',
'C:\\Python27\\lib',
'C:\\Python27\\lib\\plat-win',
'C:\\Python27\\lib\\lib-tk',
'C:\\Python27',
'C:\\Python27\\lib\\site-packages',
'C:\\Python27\\lib\\site-packages\\win32',
'C:\\Python27\\lib\\site-packages\\win32\\lib',
'C:\\Python27\\lib\\site-packages\\Pythonwin']
Server time: Fri, 12 Dec 2014 16:50:14 +0000
I can see that there is an integrity error, but I am not sure why this is the message I get. If I try registering that user again, it won't let me because it says that that username already exists. So it's like, working for registering new users, but it just doesn't acknowledge the successful registration.
Here is my code:
models.py
from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
def __unicode__(self):
return self.name
class Page(models.Model):
category = models.ForeignKey(Category)
title = models.CharField(max_length=128)
url = models.URLField()
views = models.IntegerField(default=0)
def __unicode__(self):
return self.title
class UserProfile(models.Model):
# This line is required. Links UserProfile to a User model instance.
user = models.OneToOneField(User)
# The additional attributes we wish to include.
website = models.URLField(blank=True)
picture = models.ImageField(upload_to='profile_images', blank=True)
# Override the __unicode__() method to return out something meaningful!
def __unicode__(self):
return self.user.username
views.py
from django.http import HttpResponse
from django.shortcuts import render
from rango.models import Category
from rango.models import Page
from rango.forms import CategoryForm
from rango.forms import PageForm
from rango.forms import UserForm, UserProfileForm
def index(request):
# Query the database for a list of ALL categories currently stored.
# Order the categories by no. likes in descending order.
# Retrieve the top 5 only - or all if less than 5.
# Place the list in our context_dict and dictionary which will be passed to the template engine.
category_list = Category.objects.order_by('-likes')[:5]
page_list = Page.objects.order_by('-views')[:5]
context_dict = {'categories': category_list, 'pages': page_list}
# Render the response and send it back!
return render(request, 'rango/index.html', context_dict)
def about(request):
context_dict = {'italicmessage': "I am italicised font from the context"}
return render(request, 'rango/about.html', context_dict)
def category(request, category_name_slug):
# Create a context dictionary which we can pass to the template rendering engine
context_dict = {}
try:
# Can we find a category name slug with the given name?
# If we can't, the .get() method raises a DoesNotExist exception.
# So the .get() method returns one model instance or raises an exception.
category = Category.objects.get(slug=category_name_slug)
context_dict['category_name'] = category.name
# Retrieve all the associated pages.
# Note that filter returns >= 1 model instance.
pages = Page.objects.filter(category=category)
# Adds our results list to the template context under name pages.
context_dict['pages'] = pages
# We also add the category object from the database to the context dictionary.
# We'll use this in the template to verify that the category exists.
context_dict['category'] = category
context_dict['category_name_slug'] = category_name_slug
except Category.DoesNotExist:
# We get here if we didn't find the specified category.
# Don't do anything - the template displayes the "no category message for us."
pass
# Go render the response and return it to the client.
return render(request, 'rango/category.html', context_dict)
def add_category(request):
# A HTTP POST?
if request.method == 'POST':
form = CategoryForm(request.POST)
# Have we been provided with a valid form?
if form.is_valid():
# save the new category to the database.
form.save(commit=True)
# Now call the index() view.
# The user will be shown the homepage.
return index(request)
else:
# The supplied form contained errors - just print them to the terminal.
print form.errors
else:
# If the request was not a POST, display the form to enter details.
form = CategoryForm()
# Bad form (or form details), no form supplied...
# Render the form with error messages (if any).
return render(request, 'rango/add_category.html', {'form': form})
def add_page(request, category_name_slug):
try:
cat = Category.objects.get(slug=category_name_slug)
except Category.DoesNotExist:
cat = None
if request.method == 'POST':
form = PageForm(request.POST)
if form.is_valid():
if cat:
page = form.save(commit=False)
page.category = cat
page.views = 0
page.save()
return category(request, category_name_slug)
else:
form = PageForm()
context_dict = {'form': form, 'category': cat, 'category_name_slug': category_name_slug}
return render(request, 'rango/add_page.html', context_dict)
def register(request):
# A boolean value for telling the template whether the registration was successful.
# Set to False initially. Code changes value to True when registration succeeds.
registered = False
# If it's a HTTP POST, we're interested in processing form data.
if request.method == 'POST':
# Attempt to grab information from the raw form information
# Note that we make use of both UserForm and UserProfileForm.
user_form = UserForm(data=request.POST)
profile_form = UserProfileForm(data=request.POST)
# If the two forms are valid...
if user_form.is_valid() and profile_form.is_valid():
# Save the user's form data to the database.
user = user_form.save()
# Now we hash the password with the set_password method.
# Once hashed, we can update the user object.
user.set_password(user.password)
user.save()
# Now we sort out the UserProfile instance.
# Since we need to set the user attribute ourselves, we set commit=False
# This delays saving the model until we're ready to avoid integrity problems.
profile = profile_form.save()
profile.user = user
# Did the user provide a profile picture?
# If so, we need to get it from the input form and put it in the UserProfile model.
if 'picture' in request.FILES:
profile.picture = request.FILES['picture']
# Now we save the UserProfile model instance.
profile.save()
# Update our variables to tell the template registration was successful.
registered = True
# Invalid form or forms - mistakes or something else?
# Print problems to the terminal.
# They'll also be shown to the user.
else:
print user_form.errors, profile_form.errors
# Not a HTTP POST, so we render our form using two ModuleForm instances.
# These forms will be blank, ready for user input.
else:
user_form = UserForm()
profile_form = UserProfileForm()
# Render the template depending on the context.
return render(request,'rango/register.html', {'user_form': user_form, 'profile_form': profile_form, 'registered': registered} )
forms.py
from django import forms
from django.contrib.auth.models import User
from rango.models import Page, Category, UserProfile
class CategoryForm(forms.ModelForm):
name = forms.CharField(max_length=128, help_text="Please enter the category name.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
likes = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
slug = forms.CharField(widget=forms.HiddenInput(), required=False)
# An inline class to provide additional information on the form.
class Meta:
# Provide an association between the ModelForm and a model
model = Category
fields = ('name',)
class PageForm(forms.ModelForm):
title = forms.CharField(max_length=128, help_text="Please enter the title of the page.")
url = forms.URLField(max_length=200, help_text="Please enter the URL of the page.")
views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
class Meta:
model = Page
exclude = ('category',)
# or specify the fields to include (.i.e. not include the category field)
#fields = ('title', 'url', 'views')
def clean(self):
cleaned_data = self.cleaned_data
url = cleaned_data.get('url')
# If url is not empty and doesn't start with 'http://', prepend 'http://'.
if url and not url.startswith('http://'):
url = 'http://' + url
cleaned_data['url'] = url
return cleaned_data
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username','email','password')
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('website', 'picture')
I think I have all relevant files included here, but let me know if I could provide any other info to clear things up!
Thanks in advance
Your comment says "Since we need to set the user attribute ourselves, we set commit=False", but you don't actually do that. It should be:
profile = profile_form.save(commit=False)
In future, please cut your code down to the minimum that exhibits your problem: the error was occurring on register, you didn't need to show all the code relating to categories.

Categories