How to retrieve data from extended user model - django

I am trying to make a simple signup/login page through django.
I have used UserCreationForm and used a model UserProfile to extend the user model.
I want to retrieve the data posted from form i.e department at my home page after user logged in.
I am new to django so brief explanation would be appreciated.
Thanks in advance
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from mysite.core.models import UserProfile
from django.db import models
class SignUpForm(UserCreationForm):
first_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
department = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
email = forms.EmailField(max_length=254, help_text='Required. Inform a valid email address.')
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email','password1', 'password2', 'department',)
def save(self, commit=True):
# Save the provided password in hashed format
user = super(SignUpForm, self).save(commit=False)
user_profile = UserProfile(user=user, department=self.cleaned_data['department'])
user.save()
user_profile.save()
return user, user_profile
views.py
from django.contrib.auth.decorators import login_required
from django.contrib.auth import login, authenticate
from django.shortcuts import render, redirect
from mysite.core.forms import SignUpForm
#login_required
def home(request):
return render(request, 'home.html')
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user,user_profile = form.save(commit=False)
username = user.cleaned_data.get('username')
raw_password = user.cleaned_data.get('password1')
user = authenticate(username=username, password=raw_password)
login(request, user)
return redirect('home')
else:
form = SignUpForm()
return render(request, 'signup.html', {'form': form})
models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE,unique=True)
department = models.CharField(max_length=500, blank=True)
home.html in templates:
{% extends 'base.html' %}
{% block content %}
<h2>Welcome, <small>{{ user.username }}</small>!</h2>
<p>Your email address: {{ user.email }}</p>
<p>Department: {{ user_profile.department }}</p>
{% endblock %}
I am able to print username and email but department is coming empty.

Firstly, you have the wrong relationship. There is a one-to-one relationship between User and UserProfile; a user can only have one profile, and a profile can only belong to one user. The way you have it now, a user can have many profiles, which doesn't make sense.
You should replace the ForeignKey with a OneToOneField.
Once you have done that, you will be able to access the profile data via the relationship: user.userprofile.department, and so on.

Related

How to register user using your own Model Django

I am having trouble registering a user as a PetOwner. I'm not sure what I am suppose to code in my signup view. I can signup a user and that user does not have admin or staff status which is great because they should not have these privileges. Problem is that I do not just want them to be a user but I want them to be a PetOwner. Currently, they are only a User not a PetOwner. What am I doing wrong here or what do I have to add.
in models.py
from django.db import models
from django.urls import reverse
from django.contrib.auth.models import User
class PetOwner(models.Model):
"""Model representing a pet owner."""
user = models.OneToOneField(User, on_delete=models.CASCADE)
first_name = models.CharField(max_length=50, help_text="Enter owner's first name")
last_name = models.CharField(max_length=50, help_text="Enter owner's last name")
email = models.EmailField(
max_length=50, blank=True, unique=True, help_text="Enter owner's email"
)
phone_number = models.CharField(
max_length=15, blank=True, unique=True, help_text="Enter owner's phone number"
)
address = models.ForeignKey(
"Address", on_delete=models.SET_NULL, null=True, blank=True
)
class Meta:
"""Controls default ordering of records when querying the Model type."""
ordering = ["first_name", "last_name"]
def __str__(self):
"""String for representing the Model object."""
return self.first_name
def get_absolute_url(self):
"""Returns the url to access a detail record of this pet owner."""
return reverse("petowner_detail", args=[str(self.id)])
in views.py
from django.shortcuts import render, redirect
from django.views import generic
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import PetOwner, Pet, Breed, Address
def signup(request):
if request.method == "POST":
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password1")
user = authenticate(username=username, password=password)
login(request, user)
return redirect("/")
else:
return render(request, "signup.html", {"form": form})
else:
form = UserCreationForm()
return render(request, "signup.html", {"form": form})
in urls.py
path("signup/", views.signup, name="signup"),
in signup.html
{% extends 'base.html' %}
<h1>Sign Up Page</h1>
{% block content %}
<form method="post">
{% csrf_token %} {{ form.as_p }}
<button type="submit">Register</button>
</form>
{% endblock content %}
You need save the related PetOwner after the user.
if form.is_valid():
user = form.save()
# Create the related data here...
petOwner = PetOwner(
user=user,
first_name=user.first_name,
last_name=user.last_name
)
petOwner.save()
login(request, user)
return redirect("/")
you should use Foreign key instate of one to one field to pet owner and give them roll as pet owner example is below
from django.db import models
from django.urls import reverse
from django.contrib.auth.models import User
roll={petowner, roll1, roll2}
user = models.OneToOneField(User, on_delete=models.CASCADE, add roll here)
in views.py just check roll and create pet owner object in pet owner model
also you can do this without roll just write logic for if user created then when user will be added it should create a pet owner object automatically
for example
if user:
classrooms = Classroom.objects.filter(id=id, is_active=True)
if users.exists():
user = users.first()
is_user = (user.user==request.user)
if not pet_owner:
pet_owner.objects.create(user=user, user=request.user).save()
this is just an example names and model can be changed

'Custom user with this Email address already exists' error when trying to update email using forms. Django

please read through my code, my question with screenshots and things i've already tried are after my code.
managers.py:
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import ugettext_lazy as _
class CustomUserManager(BaseUserManager):
def create_user(self, email, password, **extra_feilds):
if not email:
raise ValueError(_('The Email must be set'))
email = self.normalize_email(email)
user = self.model(email=email, **extra_feilds)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_feilds):
extra_feilds.setdefault('is_staff', True)
extra_feilds.setdefault('is_superuser', True)
extra_feilds.setdefault('is_active', True)
if extra_feilds.get('is_staff') is not True:
raise ValueError(_('Superuser must have is_staff = True'))
if extra_feilds.get('is_superuser') is not True:
raise ValueError(_('Superuser must have is_superuser=True'))
return self.create_user(email, password, **extra_feilds)
models.py:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.utils.translation import gettext_lazy as _
from .managers import CustomUserManager
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
first_name = models.CharField(max_length=40)
last_name = models.CharField(max_length=40)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
forms.py
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser, StripeConnectSetup
from django import forms
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm):
model = CustomUser
fields = ('email', 'first_name', 'last_name')
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ('email','first_name', 'last_name')
views.py
from django.shortcuts import render, redirect
from .forms import CustomUserCreationForm, CustomUserChangeForm, StripeConnectSetupForm
from .models import CustomUser
from django.contrib.auth import login, logout
from django.contrib.auth.forms import AuthenticationForm
def update_user_view(request):
obj = CustomUser.objects.get(email=request.user.email)
data = {'email': obj.email, 'first_name': obj.first_name, 'last_name': obj.last_name}
form = CustomUserChangeForm(initial=data)
if request.method == 'POST':
form = CustomUserChangeForm(request.POST, request.FILES)
if form.is_valid():
obj = CustomUser.objects.get(email=request.user.email)
obj.email = form.cleaned_data['email']
obj.first_name = form.cleaned_data['first_name']
obj.last_name = form.cleaned_data['last_name']
obj.save()
return redirect('accounts:update_user')
context = {
'form': form
}
return render(request, 'accounts/update_user.html', context)
update_user.html:
<h1>Update User Profile</h1>
<hr>
<form method="POST" enctype="multipart/form-data"> {% csrf_token %}
{{form.as_p}}
<button type="submit" class="btn btn-primary">Update</button>
</form>
the problem:
when trying to update my account, if i don't wish to change my email (just my first name or lastname) it displays the error 'Custom user with this Email address already exists'
i have searched for many solutions and the only one that seemed to work is passing through the clean function on the update form as shown below:
forms.py
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ('email','first_name', 'last_name')
def clean(self):
pass
this fixes the issue and allows you to update your first or last name without updating your email.
However, this causes another bug.
when i try to change my email to a differnt email that already exists in my database instead of getting the 'Custom user with this Email address already exists' error, it loads this screen instead
error that is occuring with clean function fix in place
so the question is how do i stop the 'Custom user with this Email address already exists' error when im not updating my email but allow the error when i am changing my email and that email already exists.
Since you want to update the object you should simply pass the keyword argument instance to the form instead of passing initial. You get the error 'Custom user with this Email address already exists' because when you write CustomUserChangeForm(request.POST, request.FILES) and it tries to validate the form it considers this as creating a new user and this gives you an error.
From the documentation on The save() method of ModelForm:
A subclass of ModelForm can accept an existing model instance as
the keyword argument instance; if this is supplied, save()
will update that instance. If it’s not supplied, save() will
create a new instance of the specified model
So your view should be like:
def update_user_view(request):
obj = CustomUser.objects.get(email=request.user.email)
form = CustomUserChangeForm(instance=obj)
if request.method == 'POST':
form = CustomUserChangeForm(request.POST, request.FILES, instance=obj)
if form.is_valid():
obj = form.save()
return redirect('accounts:update_user')
context = {
'form': form
}
return render(request, 'accounts/update_user.html', context)
Next change your form back so that the clean method is unchanged:
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ('email','first_name', 'last_name')

How to add 2 models in a registration form in Django?

I want to create a Registration form which includes two models. One model is my custom model (Profile) and the other is the default User model in Django. I created two separate forms within the same template but the data is not successfully stored. This is what I had done so far:
models.py:
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
company = models.CharField(max_length=100, blank=True, null=True)
address = models.TextField()
views.py:
def register(request):
if request.method == 'POST':
user_form = UserForm(request.POST)
profile_form = ProfileForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
return redirect('login')
else:
user_form = UserForm()
profile_form = ProfileForm()
return render(request, 'register_page.html', {'user_form': user_form, 'profile_form': profile_form})
forms.py:
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import Profile
class UserForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['company', 'address']
However, when I tried to register a new user, the data gets saved in the User model (username, email, password) but not in the Profile model (company, address).
I am getting this error instead:
RelatedObjectDoesNotExist at /
Profile has no user.
What should I do?
Since your Profile model is connected to the User model through OneToOne relation so you need to assign the user to your profile like this.:
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
profile = profile_form.save(commit = False)
# assign user to your profile
profile.user = user
profile.save()
return redirect('login')

Issues with auth_user table

I wanted to insert the user details in auth_user table, but it gives the error of create_user() got an unexpected keyword argument 'first_name'
forms.py
from django import forms
from django.contrib.auth.models import User
from django.forms import ModelForm
from customer_reg.models import Customer
class Registration_Form(ModelForm):
first_name = forms.CharField(label=(u'First Name'))
last_name = forms.CharField(label=(u'Last Name'))
username = forms.CharField(label=(u'User Name'))
email = forms.EmailField(label=(u'Email Address'))
password = forms.CharField(label=(u'Password'), widget=forms.PasswordInput(render_value=False))
class Meta:
model=Customer
exclude=('user',)
def clean_username(self):
username=self.cleaned_data['username']
try:
User.objects.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError("The Username is already taken, please try another.")
def clean_password(self):
password=self.cleaned_data['password']
return password
views.py
from django.contrib.auth.models import User
from customer_reg.models import Customer
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext
from customer_reg.forms import Registration_Form
def CustomerRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect('/customer_profile/')
if request.method == 'POST':
form = Registration_Form(request.POST)
if form.is_valid():
user=User.objects.create_user(first_name=form.cleaned_data['first_name'], last_name=form.cleaned_data['last_name'], username=form.cleaned_data['username'], email=form.cleaned_data['email'], password = form.cleaned_data['password'])
user.save()
customer=user.get_profile()
customer.birthday=form.cleaned_data['birthday']
customer.website=form.cleaned_data['website']
customer.store=form.cleaned_data['store']
customer.welcomemail=form.cleaned_data['welcomemail']
customer.save()
return HttpResponseRedirect('/customer_profile/')
else:
return render_to_response('customer_register.html',{'form':form} , context_instance=RequestContext(request))
else:
''' user is not submitting the form, show them a blank registration form '''
form = Registration_Form()
context={'form':form}
return render_to_response('customer_register.html',context , context_instance=RequestContext(request))
If I edit the views.py as
user=User.objects.create_user(username=form.cleaned_data['username'], email=form.cleaned_data['email'], password = form.cleaned_data['password'])
then it works successfully
I have already tried firstname as well as first_name
any idea where I have done the mistake
The create_user manager method only accepts three arguments, username, email (optional), and password (optional).
Once you have created a user, you can modify the other fields, then save again.
user=User.objects.create_user(username=form.cleaned_data['username'], email=form.cleaned_data['email'], password = form.cleaned_data['password'])
user.first_name = form.cleaned_data['first_name']
user.last_name = form.cleaned_data['last_name']
user.save()
If you want to be able to register using admin interface you gonna have to change the admin.py inside your app

Taking User Input to create Users in Django

I would like to create/add new users to my app in Django using the user input. I am using the default login provided by django. I am trying to add users to the default login. The example in https://docs.djangoproject.com/en/dev/topics/auth/:
>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('john', 'lennon#thebeatles.com', 'john password')
passes the username and password. But i would like this to happen with user input. How do i do this?
Need some guidance...
I tried this but it doesn't seem to work:
def lexusadduser(request):
"""
add user
"""
if request.method == "POST":
user.save()
auth_user = authenticate(username=user.username,password=user.password)
if auth_user is not None:
lexusmain(request)
else:
return render('adduser.html')
First thing you need to do is create a ModelForm:
forms.py
from django.contrib.auth.models import User
class UserForm(ModelForm):
class Meta:
model = User
fields = ('username', 'email', 'password')
A ModelForm automatically builds your form off a model you provide. It handles the validations based on the fields.
views.py
from forms import UserForm
from django.contrib.auth import login
from django.http import HttpResponseRedirect
def lexusadduser(request):
if request.method == "POST":
form = UserForm(request.POST)
if form.is_valid():
new_user = User.objects.create_user(**form.cleaned_data)
login(new_user)
# redirect, or however you want to get to the main view
return HttpResponseRedirect('main.html')
else:
form = UserForm()
return render(request, 'adduser.html', {'form': form})
If its a POST request, we create a UserForm from the POST values. Then we check if its a valid form. If it is, we create the user, otherwise we return the form with the errors. If its not a POST request, we send a clean form
template
<form method="post" action="">
{% csrf_token %}
{{ form }}
<input type="submit" value="Create new user account" />
</form>
Use a form. Air coding here:
class SignupForm(forms.Form):
username = forms.CharField()
email = forms.EmailField()
password = forms.CharField(widget=forms.PasswordInput)