I'm new to django and currently following a tutorial where it uses a ModelForm for a User Profile where a user can upload an avatar. I want to be able to update the file that they upload to a generated id. I'm just not sure where and how to do capture and update the file.
My Model
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
avatar = models.ImageField(default='avatar_default.jpg', upload_to='profile_images')
def save(self,*args, **kwargs):
super().save()
img = Image.open(self.avatar.path)
if img.height > 300 or img.width > 300:
output_size = (300,300)
img.thumbnail(output_size)
img.save(self.avatar.path)
def __str__(self):
return f'{self.user.username} Profile'
Form
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['avatar']
View
#login_required
def user_profile(request):
if request.method == 'POST':
user_form = UserUpdateForm(request.POST, instance=request.user)
profile_form = ProfileUpdateForm(request.POST,
request.FILES,
instance=request.user.profile)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
messages.success(request, f'Your profile has been updated')
return redirect('users_profile')
else:
user_form = UserUpdateForm(instance=request.user)
profile_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'user_form': user_form,
'profile_form': profile_form
}
return render(request, "users/profile.html", context)
I tried to apply some recommendations online where you do a Commit=False when saving the form and store that in a variable and renaming the file, it was a whole lot of confusion in the end.
Related
I would like users to have the ability to update their email address. I created a profile that has fields, but the email address is in the users table. I created a form that adds a custom form field and it works for update. However, I can't find a way to pre-populate this field on a REQUEST.GET.
# forms.py
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('name', 'timezone')
class ProfileUpdateForm(ProfileForm):
email = forms.EmailField(max_length=254)
class Meta(ProfileForm.Meta):
fields = ProfileForm.Meta.fields + ('email',)
# views.py
#login_required
#require_http_methods(["GET","POST"])
def profile_update_view(request):
context = {}
# Get the logged in users profile
profile_object = Profile.objects.get(user=request.user.id)
if request.method == 'GET':
profile_form = ProfileUpdateForm(None, instance=profile_object)
context["form"] = profile_form
# how can I add User.objects.get(id=request.user.id).email to the custom field
if request.method == 'POST':
profile_form = ProfileUpdateForm(request.POST or None, instance=profile_object)
context["form"] = profile_form
if profile_form.is_valid():
try:
# email address exists
user = User.objects.get(email=profile_form.cleaned_data.get('email'))
messages.error(request, 'Failed profile update. Email address already exists.')
except:
# email address available
# get user object
user = User.objects.get(id=request.user.id)
user.email = profile_form.cleaned_data.get('email')
# update user object
user.save()
profile_form.save()
messages.success(request, 'Successful profile update.')
return render(request, "profile.html", context)
I tend to favour class-based views, and things like this are where they come into their own. The form:
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('name', 'timezone')
email = forms.EmailField(max_length=254) #add non-model form field
And a class-based view. Handle the initial value for email in get_initial(), and updating of self.request.user in form_valid():
class ProfileUpdateView( UpdateView):
model = Profile
form_class = ProfileUpdateForm
template_name = 'profile.html' # profiles/update_profile.html would be better
# other declarations ...?
def get_initial(self):
initial = super().get_initial()
initial['email'] = self.request.user.email
return initial
# #transaction.atomic might be a good idea
def form_valid(self, form):
new_email = form.cleaned_data['email']
user = self.request.user
if user.email != new_email: # don't do a pointless non-update save
user.email = new_email
user.save()
return super().form_valid( form) # will save the profile
# forms.py
def __init__(self, *args, **kwargs):
self.email = kwargs.pop("email")
super(ProfileUpdateForm, self).__init__(*args, **kwargs)
self.initial['email'] = self.email
# views.py
if request.method == 'GET':
profile_form = ProfileUpdateForm(None, instance=profile_object, email=request.user.email)
context["form"] = profile_form
if request.method == 'POST':
profile_form = ProfileUpdateForm(request.POST or None, instance=profile_object, email=request.POST.get('email'))
context["form"] = profile_form
I have an app that if a user signs up, the app will automatically make a profile page for it, the sign up and login part works correctly but it doesn't make a profile page, I have to do it in the admin page. How should I solve this problem?
this is my models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
def __str__(self):
return f'{self.user.username} Profile'
def save(self):
super().save()
img = Image.open(self.image.path)
if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.image.path)
this is my views.py
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your Acount Has Been Created You Are Now Be Able to Login')
return redirect('login')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form':form})
#login_required
def profile(request):
if request.method == 'POST':
u_form = UserUpdateForm(request.POST, instance=request.user)
p_form = ProfileUpdateForm(request.POST ,request.FILES , instance=request.user.profile)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
messages.success(request, f'Your Acount Has Been Updated')
return redirect('profile')
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'u_form':u_form,
'p_form':p_form
}
return render(request, 'users/profile.html', context)
this is my forms.py
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email']
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['image']
this is my signals.py
#receiver(post_save, sender=User)
def create_profile(sender, instance, created , **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
and this is my apps.py:
class UsersConfig(AppConfig):
name = 'users'
def ready(self):
import users.signals
The only reason I can see that would cause this is that the signals aren't registering properly, make sure the config is referenced in the app's init.py file:
# my_app.__init__.py
default_app_config = 'my_app.apps.MyAppConfig'
Alternatively, move the signals to the models.py file and see if they fire when the User is created. As a last resort, try creating the profile in the view when the User form is saved.
hello everyone it's been a while since I haven't coded but I noticed some pref changes so I have some problem with the profile application edited the profile my code
views
#login_required
def edit_profile(request):
if request.method =='POST':
user_form =UserEditForm(data=request.POST or None, instance=request.user)
profile_form=ProfileEditForm(data=request.POST or None, instance=request.user.profile ,files =request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
else:
user_form=UserEditForm(instance=request.user)
profile_form=ProfileEditForm(instance=request.user.profile)
context ={
'user_form':user_form,
'profile_form':profile_form,
}
return render(request,'accounts/edit_profile.html',context)
form
class UserEditForm(forms.ModelForm):
class Meta:
model=User
fields=('username', 'email')
class ProfileEditForm(forms.ModelForm):
class Meta:
model=Profile
fields=('description', 'image')
another try to see the same error
form
class EditProfileForm(UserChangeForm):
class Meta:
model=User
fields=('username', 'email')
view
#login_required
def edit_profile(request):
if request.method =='POST':
form= EditProfileForm(request.POST,instance=request.user)
if form.is_valid():
form.save()
return redirect("/profile/")
else:
form=EditProfileForm(instance=request.user)
args={'form': form}
return render(request,'accounts/edit_profile.html',args)
error
The view accounts.views.edit_profile didn't return an HttpResponse object. It returned None instead.
As the error says the view did not return a response.
Your return render... was indented under your POST method:
#login_required
def edit_profile(request):
# You need to define these before the POST method
user_form=UserEditForm(instance=request.user)
profile_form=ProfileEditForm(instance=request.user.profile)
if request.method =='POST':
user_form =UserEditForm(data=request.POST or None, instance=request.user)
profile_form=ProfileEditForm(data=request.POST or None, instance=request.user.profile ,files =request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
# I would return a success message here
else:
# Inform the user their form was not valid
context = {
'user_form':user_form,
'profile_form':profile_form,
}
return render(request,'accounts/edit_profile.html',context)
Trying to save data with login user. Tried as below.
models.py
class MyModel(TimeStamped):
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
title = models.CharField(max_length=250)
forms.py
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
exclude = ['user']
views.py
def add(request):
if request.method == 'GET':
form = MyForm()
else:
form = MyForm(request.POST, request.FILES)
if form.is_valid():
form.save(commit=False)
form.save()
messages.success(request, 'Message Sent Successfully')
redirect('home')
return render(request, "add.html", {'form': form})
It saved data. But problem is user is not setting to login user. Tried adding in view form.user = request.user. still is not saving.
Try this.
def add(request):
if request.method == 'GET':
form = MyForm()
else:
form = MyForm(request.POST, request.FILES)
if form.is_valid():
obj = form.save(commit=False)
obj.user = request.user
obj.save()
messages.success(request, 'Message Sent Successfully')
redirect('home')
return render(request, "add.html", {'form': form})
I have a strange issue when saving a model form. I have a form, which consists of two model forms and I am trying to save them at the same time. For clarity, below is my code
Views.py
def create_user(request):
if request.method == 'POST':
user_form = UserForm(request.POST)
my_user_form = MyUsersForm(request.POST)
if user_form.is_valid() and my_user_form.is_valid():
us = user_form.save()
my_us = my_user_form.save(commit=False)
my_us.user = us
my_us.save()
return HttpResponse('You have successfully created a user')
else:
return HttpResponse(' My_user_form is not validated')
else:
user_form = UserForm()
my_user_form = MyUsersForm(user=request.user)
return render(request, 'create_user.html', {'user_form': user_form, 'my_user_form': my_user_form})
my_user_form is not validated when I override the init method of MyUsersForm to filter the queryset of the foreign key(created_by) but when I don"t filter the queryset, my_user_form is validated and the form is saved.
What I don't understand is when I don"t filter the query set how come my_user_form is validated?
The data which is sent via the request.post to my_user_form is somehow lost (when I filter the queryset). any clue in the right direction is highly appreciated. Thank you for your valuable inputs.
Forms.py
class MyUsersForm(ModelForm):
class Meta:
model = MyUsers
fields = ['created_by', ]
def __init__(self, user=None, **kwargs):
super(MyUsersForm, self).__init__(**kwargs)
if user is not None:
self.fields['created_by'].queryset = User.objects.filter(username=user)
Models.py
class MyUsers(models.Model):
user = models.OneToOneField(User, blank=True, null=True)
created_by = models.ForeignKey(User, related_name="created_by", blank=True, null=True)
def create_user(request):
if request.method == 'POST':
user_form = UserForm(request.POST)
my_user_form = MyUsersForm(request.POST)
if user_form.is_valid() and my_user_form.is_valid() and User.objects.filter(username=request.POST.get('user')).exists():
us = user_form.save()
my_us = my_user_form.save(commit=False)
my_us.user = us
my_us.save()
return HttpResponse('You have successfully created a user')
else:
return HttpResponse(' My_user_form is not validated')
else:
user_form = UserForm()
my_user_form = MyUsersForm(user=request.user)
return render(request, 'create_user.html', {'user_form': user_form, 'my_user_form': my_user_form})
why my_user_form is not validated and saved. instead of modifying the queryset in the init i did it in the view itself using the statement
my_user_form.fields['created_by'] = forms.ModelChoiceField(User.objects.filter(username=request.user))
and this solves my problem. but i still don't know why it didn't work in the init method of the MyUsersForm?.