I am trying to create a profile model for all of my users. I have the following code in which I get one custom field birth_date, but cannot seem to get any of my other custom fields to work:
forms.py:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class SignUpForm(UserCreationForm):
birth_date = forms.DateField(help_text='Required. Format: YYYY-MM-DD')
class Meta:
model = User
fields = ('username', 'first_name','last_name', 'birth_date','location', 'password1', 'password2', )
models.py:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
views.py
from django.contrib.auth import login, authenticate
from django.shortcuts import render, redirect
from django.http import HttpResponse
from .forms import SignUpForm
def home(request):
return HttpResponse('fd')
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.profile.birth_date = form.cleaned_data.get('birth_date')
user.profile.college = form.cleaned_data.get('college')
user.save()
raw_password = form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user)
return redirect('home')
else:
form = SignUpForm()
return render(request, 'accounts/profile.html', {'form': form})
urls.py
urlpatterns = [
url(r'^register/$', views.signup, name='profile'),
url(r'^home/$', views.home, name='home'),
]
If I were to remove locationfrom forms.py, the form would load properly and allow me to fill it out and upon submission all data, including the custom field birth_date would save. But when I try to add location to the form, I get the following error:
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/forms/models.py", line 262, in __new__
raise FieldError(message)
django.core.exceptions.FieldError: Unknown field(s) (location) specified for User
I am not sure why I cannot add the location field to the form.
Because it's not a field on User. You need to do the same as you have for birth_date - declare it separately in the form class, and save it explicitly to the profile in the view.
Related
please help me with one question, if possible.
I have a profile model that has a OneToOneField to User and there is a team field in the Profile model, there is also a Team model with a name, tag, etc. I would like to ask how to make the user who creates the team immediately be in it, so that the team field of the Profile model is assigned this team automatically, so that he is its creator and captain immediately. Maybe someone can help, explain, throw a banal example for understanding.
The creation was done like this, in a separate application. But I don't understand how to give the browser the created tim.
models.py
from django.db import models
from django.contrib.auth.models import User
from slugify import slugify
from django.urls import reverse
class BaseModel(models.Model):
objects = models.Manager()
class Meta:
abstract = True
class Profile(BaseModel):
user = models.OneToOneField(
User, on_delete=models.CASCADE, null=True, blank=True
)
nickname = models.CharField(max_length=30, unique=True, null=True)
team = models.ForeignKey('Team', on_delete=models.SET_NULL, blank=True, null=True)
def save(self, *args, **kwargs):
super(self.__class__, self).save(*args, **kwargs)
if self._state.adding is True:
Profile.objects.create()
def __str__(self):
return self.nickname
class Meta:
verbose_name = "Автор"
verbose_name_plural = "Авторы"
class Team(BaseModel):
name = models.CharField('Название', max_length=50)
tag = models.CharField('Тег', max_length=16, unique=True)
slug = models.SlugField(unique=True, blank=True, null=True)
def __str__(self):
return f'{self.name} [{self.tag}]'
def get_absolute_url(self):
return reverse("team_detail", kwargs={"slug": self.slug})
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Team, self).save(*args, **kwargs)
class Meta:
verbose_name = "Команда"
verbose_name_plural = "Команды"
forms.py
from django import forms
from django.contrib.auth.models import User
from django.forms import TextInput, Textarea, FileInput, IntegerField
from django.forms import TextInput, Textarea, FileInput, Select
from .models import *
class CreateTeamForm(forms.ModelForm):
class Meta:
model = Team
fields = {
'name', 'tag', 'slug'
}
views.py
from django.conf import settings
from django.contrib.auth import authenticate, login, get_user_model
from django.http import HttpResponseRedirect, Http404, HttpResponse
from django.shortcuts import render, redirect, resolve_url
from django.utils.http import url_has_allowed_host_and_scheme
from django.views.generic.base import View
from django.views.generic import DetailView, ListView
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.views.decorators.csrf import csrf_exempt
from .models import *
from .forms import *
# Create your views here.
class CreateTeam(View):
def get(self, request):
form = CreateTeamForm(request.POST)
context = {'form': form}
return render(request, 'team/home.html', context)
def post(self, request):
if request.method == 'POST':
form = CreateTeamForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
return redirect('home')
I'm just learning django, so it's hard to implement everything at once, and I'll be happy to help.
NEW CODE
forms.py
class JoinTeamForm(forms.ModelForm):
key = forms.CharField(label='key', max_length=20)
class Meta:
model = Team
fields = {'key'}
I tried without key = forms.CharField(label='key', max_length=20), but in html {{ form.key }} didn't work.
views.py
class JoinTeam(LoginRequiredMixin, View):
def get(self, request, pk):
print(f'post:{request.POST}, get:{request.GET}')
form = JoinTeamForm(request.POST or None)
team = Team.objects.get(id=pk)
context = {'form': form,
'team': team
}
return render(request, 'team/team_detail.html', context)
def post(self, request, pk):
print(f'post: {request.POST} team_id: {Team.objects.get(id=pk).key}')
profile = request.user.profile
error_msg = 'Неверный код'
if request.method == 'POST':
form = JoinTeamForm(request.POST)
role = Role.objects.get(id=2)
team = Team.objects.get(id=pk)
if form.is_valid():
key = form.save()
if key == team.key:
profile.team = team
profile.role = role
profile.save()
return redirect(team.get_absolute_url())
else:
return HttpResponse(error_msg)
return redirect(team.get_absolute_url())
Could you edit your view to update the user's profile after the team is created?
class CreateTeam(View):
def get(self, request):
form = CreateTeamForm(request.POST)
context = {'form': form}
return render(request, 'team/home.html', context)
def post(self, request):
profile = request.user.profile
if request.method == 'POST':
form = CreateTeamForm(request.POST)
if form.is_valid():
team = form.save()
profile.team = team
profile.save()
return redirect('home')
return redirect('home')
Please note, the way you have this set up is that each profile can only be on one team. If that's your intent, great, but if not you may want to set up a many to many model here so a user can be associated with multiple teams.
Right now, if I enter invalid data into my UserCreationForm and submit it, the page reloads but doesn't show any error. I would like the EmailValidator validator in Django to show the error. I have tried adding the validators attribute to the email field, but it didn't do anything.
Here are my views:
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import render
from django.urls import reverse
from .models import CustomUserCreationForm
# Create your views here.
def register(request):
if request.user.is_authenticated:
return HttpResponseRedirect(reverse('index'))
elif request.method == 'GET':
form = CustomUserCreationForm()
elif request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
form.save()
context = {
'user': request.user,
}
return HttpResponseRedirect(reverse('index'), context)
else:
return HttpResponseRedirect(reverse('register'))
else:
return HttpResponse("Project 3: TODO")
context = {
'form': form,
}
return render(request, 'registration/signup.html', context)
def logout_view(request):
logout(request)
return HttpResponseRedirect(reverse('login'))
And here are my models:
from django.contrib.auth.models import AbstractUser, AbstractBaseUser
from django import forms
from django.contrib.auth.models import User
from django.db import models
from django.contrib.auth.forms import UserCreationForm
from django.core.validators import EmailValidator
# Create your models here.
# Customer class.
class CustomUser(User):
REQUIRED_FIELDS = ['email', 'first_name', 'last_name']
# Create user registration form class.
class CustomUserCreationForm(UserCreationForm):
first_name = forms.CharField(required=True, max_length=150, help_text='Required.')
last_name = forms.CharField(required=True, max_length=150, help_text='Required.')
email = forms.CharField(required=True, max_length=150, help_text='Required.', validators=[EmailValidator], error_messages={'invalid': 'This does not look like an email address.'})
class Meta:
model = User
fields = UserCreationForm.Meta.fields + ('first_name', 'last_name', 'email',)
# TODO: show an error message when email is incorrectly formatted.
# TODO: make email field unique and show an error message when it was already used.
Use built in EmailField of Django in CustomUserCreationForm
email = forms.EmailField(...)
See this too (validation of email) (form.clean), read this for showing errors of individual form fields
Can someone help me figure out what i am doing wrong trying to setup authentication and signals to work along with the models created in django 2.0.
models.py
from django.db import models
from django.conf import settings.AUTH_USER_MODEL
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
bio = models.TextField(foo)
location = models.CharField(foo)
# Override save method
# Run after the method is saved to add signal functionality below
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
else:
instance.profile.save()
forms.py
from django import forms
from django.contrib.auth import get_user_model
from django.forms import ModelForm
from .models import Profile
Profile = get_user_model()
class UserRegisterForm(forms.ModelForm):
email = forms.EmailField(foo)
first_name = forms.CharField(foo)
last_name = forms.CharField(foo)
password = forms.CharField(foo)
password2 = forms.CharField(foo)
class Meta:
model = Profile
fields = [
'username',
'first_name',
'last_name',
'email',
'password1',
'password2'
]
views.py
from django.shortcuts import render, redirect
from django.contrib.auth import get_user_model
from .forms import UserRegisterForm
from .models import Profile
from django.conf import settings
def register(request):
next = request.GET.get('next')
form = UserRegisterForm(request.POST or None)
if form.is_valid():
user = form.save(commit=False)
password = form.cleaned_data.get('password')
user.set_password(password)
user.save()
new_user = authenticate(username=user.username, password=password)
login(request, new_user)
if next:
return redirect(next)
return redirect('accounts:login')
context = {
'form': form,
}
return render(request, "accounts/register.html", context)
Foo = just a placeholder
The code above create the user but not the profile associated to it.
Any help would be much appreciated.
new to django. I am building a form for user to save to the database. the save to database part is working. However, I want to be able to view and edit the data on two separate template. let's call them view_self_eval.html and edit_self_eval.html. I am stuck.
following is my code for Models.py, Forms.py and View.py for the particular form
Models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.forms import ModelForm
class self_eval(models.Model):
Owner = models.OneToOneField(User, on_delete=models.CASCADE, default=None)
First_Name = models.CharField(max_length=100, default=None)
Last_Name = models.CharField(max_length=100, default=None)
Current_Role = models.CharField(max_length=100)
My_Strengths = models.CharField(max_length=1000)
Improvement = models.CharField(max_length=4000)
Goals = models.CharField(max_length=4000)
Profesional_Certification = models.CharField(max_length=4000)
Important_discussion = models.CharField(max_length=4000)
def __str__(self):
return self.Owner.username
def create_self_eval(sender, **kwargs):
if kwargs['created']:
self_eval = self_eval.objects.create(user=kwargs['instance'])
post_save.connect(create_self_eval, sender=User)
Forms.Py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from accounts.models import self_eval
class SelfEvalForm(forms.ModelForm):
class Meta:
model = self_eval
fields=(
'First_Name',
'Last_Name',
'Current_Role',
'My_Strengths',
'Improvement',
'Goals',
'Profesional_Certification',
'Important_discussion'
)
def save(self, commit=True):
self_eval = super(SelfEvalForm, self).save(commit=False)
self_eval.First_Name = self.cleaned_data['First_Name']
self_eval.Last_Name = self.cleaned_data['Last_Name']
self_eval.Current_Role = self.cleaned_data['Current_Role']
self_eval.My_Strengths = self.cleaned_data['My_Strengths']
self_eval.Improvement = self.cleaned_data['Improvement']
self_eval.Goals = self.cleaned_data['Goals']
self_eval.Profesional_Certification = self.cleaned_data['Profesional_Certification']
self_eval.Important_discussion = self.cleaned_data['Important_discussion']
if commit:
self_eval.save()
return self_eval
Views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse
from accounts.forms import (
RegistrationForm,
EditProfileForm,
SelfEvalForm,
EditSelfEvalForm
)
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserChangeForm, PasswordChangeForm
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.decorators import login_required
from .models import self_eval
from django.views.generic import UpdateView
def self_eval(request):
if request.method == 'POST':
form = SelfEvalForm(request.POST)
if form.is_valid():
#save form data to DB
instance = form.save(commit=False)
instance.Owner=request.user
instance.save()
return redirect(reverse('accounts:self_eval'))
else:
form = SelfEvalForm()
args = {'form': form}
return render(request, 'accounts/self_eval_form.html', args)
def edit_self_eval(request, Owner_id):
self_eval = get_object_or_404(self_eval, pk=Owner_id)
if request.method == 'POST':
form = SelfEvalForm(request.POST, instance=Current_Role, Owner=request.user)
if form.is_valid():
self_eval = form.save()
else:
form = SelfEvalForm(intance=self_eval, Owner=request.user)
args = {'form':form,
'Current_Role':Current_Role
}
return render(request, 'accounts/edit_self_eval.html', args)
I am trying to extend the User model to create a Profile model. The following code successfully displays a form with the additional fields I specified as location and bio. But when I submit the form only the original username, first_name, last_name, email, and password fields are stored in the database at http://127.0.0.1:8000/admin, none of my custom fields are stored in the Profile section I added to admin . I also get the following error:
IntegrityError at /accounts/register/
NOT NULL constraint failed: accounts_profile.user_id
Request Method: POST
Request URL: http://127.0.0.1:8000/accounts/register/
Django Version: 1.11.2
Exception Type: IntegrityError
Exception Value:
NOT NULL constraint failed: accounts_profile.user_id
Exception Location: /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py in execute, line 328
Python Executable: /Library/Frameworks/Python.framework/Versions/3.6/bin/python3.6
models.py:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
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 RegistrationForm(UserCreationForm):
email = forms.EmailField(required = True)
class Meta:
model = User #model User comes with username, email, first name, last name , pass1 and pass2 fields
fields = (
'username',
'email',
'first_name',
'last_name',
'password1',
'password2'
)
def save(self, commit = True):
user = super(RegistrationForm, self).save(commit = False)
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('location','bio')
views.py:
from django.shortcuts import render, redirect
from .forms import RegistrationForm,ProfileForm
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
profile_form = ProfileForm(request.POST)
if form.is_valid() and profile_form.is_valid():
form.save()
profile_form.save()
return redirect('login')
else:
form = RegistrationForm()
profile_form = ProfileForm()
return render(request, 'accounts/register.html', {'form': form, 'profile_form': profile_form})
urls.py:
from django.conf.urls import url
from django.contrib.auth.views import login
from . import views
urlpatterns = [
# /accounts/
url(r'^$', views.index, name = 'accounts'),
# /accounts/register/
url(r'^register/$', views.register, name='register'),
url(r'^login/$', login, {'template_name': 'accounts/login.html'}, name='login'),
]
admin.py:
from django.contrib import admin
from .models import Profile
# Register your models here.
admin.site.register(Profile)
# Register your models here.
Any help would be greatly appreciated.
you have to set the relation manually then your view should look like this:
if form.is_valid() and profile_form.is_valid():
user_object = form.save()
a = profile_form.save(commit=False)
a.user = user_object
a.save()
return redirect('login')
you can't do register and profile POST at a time.because your profile model is 1to1field it belongs to Userwhich means existing user can create one user profile.So initially user should create their registered account than only they can create profile.