To make my question simple I have A Form That user can upload their cv's into databse.
My forms.py
class resume_upload(forms.ModelForm):
cv = forms.FileField(required = True)
job_title = forms.CharField(required = True)
def save(self, commit=False):
cvs = super(resume_upload, self).save(commit=False)
cvs.cv = self.cleaned_data['cv']
cvs.job_title = self.cleaned_data['job_title']
if commit:
cvs.save()
class Meta:
model = Cv
fields = ('cv', 'job_title',)
My models.py
class Cv(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
cv = models.FileField(upload_to='cvs', default='', validators=[validate_file_extension])
job_title = models.CharField(max_length=100, default='')
def __str__(self):
return self.job_title
and my views.py
def upload_resume(request):
if request.method == 'POST':
form = resume_upload(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect('/')
else:
messages.error(request,"Oops! That didn't work. Please try again")
else:
form = resume_upload()
return render(request, 'upload_resume.html',{'form':form,})
And the problem is it redirect to home page but i cant find object in admin panel
You're overriding the save method like so,
def save(self, commit=False):
cvs = super(resume_upload, self).save(commit=False)
cvs.cv = self.cleaned_data['cv']
cvs.job_title = self.cleaned_data['job_title']
if commit:
cvs.save()
You're therefore passing a an optional parameter commit which is False by default.
You'll need to provide a True parameter when calling save if you want it to actually be saved.
form.save(commit=True)
EDIT
Also, there seems to be a problem with your code. This is probably what you intended,
def upload_resume(request):
if request.method == 'POST':
form = resume_upload(request.POST, request.FILES)
if form.is_valid():
cv_form = form.save() # commit is False in this case.
cv_form.user = request.user
form.save(commit=True)
return redirect('/')
else:
messages.error(request,"Oops! That didn't work. Please try again")
else:
form = resume_upload()
return render(request, 'upload_resume.html',{'form':form,})
Basically here you're patching the user to the form before it is actually saved to the database. This is exactly the purpose of your boolean switch commit.
EDIT 2
To overcome your 'NoneType' object has no attribute 'user' error, you would need to add this in your save override to return your object.
def save(self, commit=False):
cvs = super(resume_upload, self).save(commit=False)
cvs.cv = self.cleaned_data['cv']
cvs.job_title = self.cleaned_data['job_title']
if commit:
cvs.save()
return cvs
Related
forms.py
class UserForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ('username','email','password1','password2')
def save(self,commit=True):
user = super(UserForm,self).save(commit=False)
user.set_password = self.cleaned_data['password1']
user.email = self.cleaned_data['email']
if commit:
user.save()
views.py
def register_view(request):
form = UserForm()
if request.method == 'POST':
form = UserForm(request.POST)
if form.is_valid():
user = form.save()
customer_group = Group.objects.filter(name='CUSTOMER').exists()
if customer_group:
Group.objects.get(name='CUSTOMER').user_set.add(user)
else:
Group.objects.create(name='CUSTOMER')
Group.objects.get(name='CUSTOMER').user_set.add(user)
messages.success(request,'註冊成功! 請按指示登入!')
return redirect('login')
else:
messages.error(request,'註冊無效! 請再試過!')
context = {'form':form}
return render(request,'customer/register.html',context)
When I try to register a new user, the form can be successfully saved and the group CUSTOMER can be added but I have a problem if I want to add that user to the group so are there any methods in order to add the user to the group automatically after that user had registered a new account along with the User model?
As #Iain Shelvington says, the form.save() method should return the user object. But there is no need to override the save() method: the UserCreationForm already does that.
class UserForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ('username','email')
# no save method
In the view you can simplify the logic to:
def register_view(request):
form = UserForm()
if request.method == 'POST':
form = UserForm(request.POST)
if form.is_valid():
user = form.save()
customer_group, __ = Group.objects.get_or_create(name='CUSTOMER')
customer_group.user_set.add(user)
messages.success(request,'註冊成功! 請按指示登入!')
return redirect('login')
else:
messages.error(request,'註冊無效! 請再試過!')
context = {'form':form}
return render(request,'customer/register.html',context)
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Customer(models.Model):
user = models.OneToOneField(User,null=True,blank=True,on_delete=models.CASCADE)
name = models.CharField(max_length=200,null=True)
## phone = models.IntegerField(null=True)
email = models.EmailField(max_length=250)
profile_pic = models.ImageField(default='default_pic.png',null=True,blank=True)
date_created = models.DateTimeField(auto_now_add=True,null=True)
def __str__(self):
return self.name
class Task(models.Model):
customer = models.ForeignKey(Customer,on_delete=models.CASCADE,null=True)
title = models.CharField(max_length=200)
description = models.TextField(null=True,blank=True)
complete = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Meta:
ordering = ['complete']
views.py
#login_required(login_url='login')
def taskCreate(request):
if request.method == 'POST':
form = TaskForm(request.POST or None)
if form.is_valid():
form.instance.customer = request.user
form.save()
return redirect('tasks')
else:
form = TaskForm()
context = {'form':form}
return render(request,'todo_list/task_create.html',context)
Error:
ValueError at /create_task/
Cannot assign "<SimpleLazyObject: <User: Dominic>>": "Task.customer" must be a "Customer" instance.
I am trying to link the username in the user account to be shown on the model Task.customer that represents the post is created by that user. May I ask any methods could be done in order to specify the customer in the model Task? Also I do not understand the error message in detail because my admin panel already has the current username in the Customer model. However if I used request.user.customer the username does not show up instead returning None so how to solve this issue?
I don't know form.instance.customer = request.user
but I think I understood what you meant and the below code does the same thing
#login_required(login_url='login')
def taskCreate(request):
if request.method == 'POST':
form = TaskForm(request.POST or None)
if form.is_valid():
t = form.save(commit = False)
t.customer = request.user # assigning current user to created task.customer
t.save()
return redirect('tasks')
else:
form = TaskForm()
context = {'form':form}
return render(request,'todo_list/task_create.html',context)
if the code is still not working then try changing your line
customer = models.ForeignKey(Customer,on_delete=models.CASCADE,null=True) to
customer = models.ForeignKey(User,on_delete=models.CASCADE,null=True) in your models.py
The error comes from the following snippet
form.instance.customer = request.user
request.user is not a Customer instance, you can try extracting the information from request.user and create a Customer object from it and then assign it back
I have a model Client which uses a #receiver signal to update its fields whenever a User is created, so it creates a Client profile.
class Client(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
address = models.CharField(max_length=200, verbose_name="Morada")
city = models.CharField(max_length=200, verbose_name="Cidade")
postal = models.CharField(max_length=8, validators=[RegexValidator(r'^\d{4}(-\d{3})?$')], verbose_name="Código Postal")
nif = models.CharField(max_length=9, verbose_name="NIF", validators=[RegexValidator(r'^\d{1,10}$')], unique=True, null=True)
mobile = models.CharField(max_length=9, verbose_name="Telemóvel", validators=[RegexValidator(r'^\d{1,10}$')])
def __str__(self):
return "%s %s" % (self.user.first_name, self.user.last_name)
class Meta:
verbose_name_plural = "Clientes"
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Clients.objects.create(user=instance)
instance.clients.save()
Is there a way to only run this if the user created belongs to the Clients group? Because if a user is created in the Employees group, I don't want to create a profile.
This is the view that creates the Client in the Clients group:
#login_required(login_url='./accounts/login/')
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save() # this creates the user with first_name, email and last_name as well!
group = Group.objects.get(name='Clients')
user.groups.add(group)
user.refresh_from_db() # load the profile instance created by the signal
user.clients.address = form.cleaned_data.get('address')
user.clients.city = form.cleaned_data.get('city')
user.clients.postal = form.cleaned_data.get('postal')
user.clients.nif = form.cleaned_data.get('nif')
user.clients.mobile = form.cleaned_data.get('mobile')
return redirect('clients')
else:
form = SignUpForm()
return render(request, 'backend/new_client.html', {'form': form})
Doing it in the view (without signal):
#login_required(login_url='./accounts/login/')
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save()
group = Group.objects.get(name='Clients')
user.groups.add(group)
client = Client.objects.create(
user=user,
address=form.cleaned_data.get('address')
city=form.cleaned_data.get('city')
postal=form.cleaned_data.get('postal')
nif=form.cleaned_data.get('nif')
mobile=form.cleaned_data.get('mobile')
)
return redirect('clients')
else:
form = SignUpForm()
return render(request, 'backend/new_client.html', {'form': form})
Then you can choose to move all the code under user = form.save() in the form's itself (I assume it's a custom ModelForm):
# forms.py
class SignUpForm(models.Form):
# your existing code here
def save(self):
# NB if you're still using py2 you'll need
# `user = super(SignUpForm, self).save()` instead
user = super().save()
group = Group.objects.get(name='Clients')
user.groups.add(group)
cleaned_data = self.cleaned_data
client = Client.objects.create(
user=user,
address=cleaned_data.get('address')
city=cleaned_data.get('city')
postal=cleaned_data.get('postal')
nif=cleaned_data.get('nif')
mobile=cleaned_data.get('mobile')
)
return user
And your view becomes:
#login_required(login_url='./accounts/login/')
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
form.save()
return redirect('clients')
else:
form = SignUpForm()
return render(request, 'backend/new_client.html', {'form': form})
Both options are correct and functionnaly equivalent, but the second one is IMHO more maintainable - first because a form is easier to test than a view (you don't need to create a request object), and also because it encapsulate the whole domain logic in the same place (the form) instead of scattering it between the form and the view. The only downside is that you loose the ability to pass the commit=False arg to form.save(), but since this form has obviously no other purpose you wouldn't use this feature anyway.
Trying to implement a file upload for a user profile page. I am recieving the following error:
null value in column "user_id" violates not-null constraint
DETAIL: Failing row contains (35,
profile/{now:%Y/%m/YmdHMSext_xg2iZ6M, null, null).
I've read that it probably has something to do with the User_ID, I tried passing form.user = request.user, but that didn't work. There are also two nulls, not just one.
Models.py
class User(AbstractUser):
# First Name and Last Name do not cover name patterns
# around the globe.
name = models.CharField(_('Name of User'), blank=True,
max_length=255)
#accepted_terms_of_service = models.Booleanfield()
def __str__(self):
return self.username
def get_absolute_url(self):
return reverse('users:detail', kwargs={'username':
self.username})
# Profile Image
def upload_to(instance, filename):
now = timezone_now()
base, ext = os.path.splitext(filename)
ext = ext.lower()
return "profile/{now:%Y/%m/%Y%m%d%H%M%S}{ext}"
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,
on_delete='CASCADE', related_name='user_profile')
school = models.CharField(max_length=30, null=True, blank=True)
image = models.ImageField(_("Picture"), upload_to=upload_to,
null=True, blank=True)
def __str__(self):
return self.user.username
views.py
#login_required
def add_image(request):
form = ProfileImageForm()
#form.user = request.user
if request.method == "POST":
form = ProfileImageForm(data=request.POST, files=request.FILES)
if form.is_valid():
form.save()
return redirect('userPage')
else:
return render(request, "users/user_image_form.html", {"form": form
})
forms.py
class ProfileImageForm(forms.ModelForm):
class Meta:
model = Profile
fields = ["image"]
This is because in your Profile model you add user column as ForeignKey which enforce to NOT NULL so the error throw.
To solve this you need to modify add_image method something like this
#login_required
def add_image(request):
form = ProfileImageForm()
#form.user = request.user
if request.method == "POST":
form = ProfileImageForm(data=request.POST, files=request.FILES)
if form.is_valid():
form = form.save(commit=False) # change is here
form.user=request.user.pk # change is here
form.save()
return redirect('userPage')
else:
return render(request, "users/user_image_form.html", {"form": form
The request.user.pk value get if you are logged in. But if you are logged in you need to assisn form.user = your_specified_id which id exists in User table.
If your case is, you are admin and you need to add an image to other users, so that you need to pass the user id in your add_image method.
Add in ProfileImageForm.py
add user in field list
I think its not necessary to have both Profile Model and Custom User Model. Because, as you are customizing the User model already, why not put Profile model's fields to User model as well. You can approach like this:
# model
def upload_to(instance, filename):
now = timezone_now()
base, ext = os.path.splitext(filename)
ext = ext.lower()
return "profile/{now:%Y/%m/%Y%m%d%H%M%S}{ext}"
class User(AbstractUser):
name = models.CharField(_('Name of User'), blank=True,
max_length=255)
school = models.CharField(max_length=30, null=True, blank=True)
image = models.ImageField(_("Picture"), upload_to=upload_to,
null=True, blank=True)
def __str__(self):
return self.username
def get_absolute_url(self):
return reverse('users:detail', kwargs={'username':
self.username})
# views
#login_required
def add_image(request):
form = ProfileImageForm(data=request.POST or None, file=request.FILES or None, instance=request.user)
if request.method == "POST":
if form.is_valid():
form.save()
return redirect('userPage')
return render(request, "users/user_image_form.html", {"form": form
})
# forms.py
class ProfileImageForm(forms.ModelForm):
class Meta:
model = User
fields = ["image"]
Update
You can create a post_save signal, which will create a Profile Instance after each User is created.
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile = Profile(user=instance)
profile.save()
post_save.connect(create_user_profile,
sender=User,
dispatch_uid="profilecreation-signal")
Now in your form, you can directly pass this Profile instance:
#login_required
def add_image(request):
form = ProfileImageForm(data=request.POST, files=request.FILES, instance=request.user.profile)
if request.method == "POST":
if form.is_valid():
form.save()
return redirect('userPage')
else:
return render(request, "users/user_image_form.html", {"form": form
})
For existing user, you can create Profile from shell:
for user in User.objects.all():
Profile.objects.get_or_create(user=user)
I can create model objects through admin panel. But I want it to be created on website. The code below allows me to enter values of a model, and when I submit it, it redirects to the written url, which happens after form.save. This is the message from server "POST /taskcreate HTTP/1.1" 302 0. But there is no changes in database. How to solve this issue? Any thoughts... Thanks
models.py
class Task(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=1000)
pub_date = models.DateTimeField('date_published', auto_now_add = True)
cost = models.IntegerField()
def __str__(self):
return '%s' % (self.name)
forms.py
class TaskCreateForm(forms.ModelForm):
class Meta:
model = Task
fields = ('name', 'description', 'cost')
views.py
def TaskCreateView(request):
if request.method == 'POST':
form = TaskCreateForm(request.POST)
if form.is_valid():
form.save
return redirect('home')
else:
form = TaskCreateForm()
return render(request, 'employer/create_task.html')
You didn't actually call the save method.
if form.is_valid():
form.save()
return redirect('home')
When you use ModelForm you just need to write form.save() method right after if is_valid() if case. In your case, you are missing curly brackets after save.
def TaskCreateView(request):
if request.method == 'POST':
form = TaskCreateForm(request.POST)
if form.is_valid():
form.save() # here you were missing curly brackets
return redirect('home')
else:
form = TaskCreateForm()
return render(request, 'employer/create_task.html')