Beginner here in Django.
Goal:
I would like to get a multiple checkbox selection for favorite categories and save those in
the database.
Problem
Right now I have a profile form and model, and the CheckboxSelectMultiple widget is not working like I want it to work. The categories are stored in another model which I reference in the user profile.
# # # # user/forms/profile_form.py
class ProfileForm(ModelForm):
class Meta:
model = Profile
exclude = [ 'id', 'user']
widgets = {
'favourite_categories': widgets.CheckboxSelectMultiple(attrs={'class': 'form-control'}),
'profile_picture': widgets.TextInput(attrs={'class': 'form-control'})
}
# # # # user/models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
first_name = models.CharField(max_length=200, blank=True)
last_name = models.CharField(max_length=200, blank=True)
favorite_categories = models.ManyToManyField(Category, blank=True)
profile_image = models.CharField(max_length=200, null=True, blank=True)
# # # # user/views.py
# login_required
def profile(request):
user_profile = Profile.objects.filter(user=request.user).first()
if request.method == 'POST':
form = ProfileForm(instance=user_profile, data=request.POST)
if form.is_valid():
user_profile = form.save(commit=False)
user_profile.user = request.user
user_profile.save()
return redirect('profile')
return render(request,
'user/profile.html',
context={"form": ProfileForm(instance=user_profile)})
# # # # templates/user/profile.html
<div class="shadow p-4 mb-5 mx-5 bg-body rounded">
<form class="form form-horizontal" method="post">
{% csrf_token %}
{{ form|crispy }}
<input type="submit" class="btn btn-primary" value="Update" />
</form>
</div>
The output of this can be seen in the picture.
PS. I also don't know how to use ImageField for inserting a profile image. I am using a google cloud database and the ImageField needs the variable upload_to, which specifies where the image will be uploaded to. I would like to store the image on the cloud database as all other data is.
It seems you'd have to write your own custom CheckboxSelectMultiple widget. You can see the answer of this post.
Related
I am trying to update a userprofile model that i used to save additional information over the inbuilt User model, now when i am trying to update it , the image does not gets saved. I need help to resolve this issue
# In views.py
#login_required(login_url=LOGIN_REDIRECT_URL)
def update_user_profile(request):
userobj = get_object_or_404(UserProfile, user=request.user)
form = UserProfileForm(data = request.POST or None,files= request.FILES or None, instance=userobj)
if request.method=='POST':
print(form.is_valid())
if form.is_valid():
profile = form.save(commit=False)
profile.picture = form.cleaned_data['picture']
profile.about = form.cleaned_data['about']
profile.save()
else:
print("NO picure")
return HttpResponseRedirect("/blog/profile/")
return render(request, "blog/post_update.html", {'form':form})
#models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
about = models.CharField(max_length=200, null=True, blank=True)
picture = models.ImageField(upload_to="profile_images/", blank=True)
def __str__(self):
return str(self.user)
#In forms.py
class UserProfileForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(UserProfileForm, self).__init__(*args, **kwargs)
self.fields['about'].widget.attrs.update({'class': 'form-control '})
self.fields['picture'].widget.attrs.update({'class': 'form-control-file'})
class Meta:
model = UserProfile
fields = ('about', 'picture')
# userprofileform.html
{% extends 'base.html' %}
{% block content %}
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="btn btn-primary" value="Create Profile">
</form>
{% endblock %}
please take a look at the code and help. while registering if the image was uploaded it get's saved , but when i try to update the userprofile directly in profile section image does not get changed and shows the same as one saved while user registration else it shows None.
I did some changes on templates in settings.py and got my project runnning. Issue was that i was not mentioning the Templates directory properly
I'm trying to update a user's profile photo after they've already created their account. I'm using an abstract user model connected to a model called Person. For additional context, I have my application connected to AWS to deploy to Heroku.
I have a form, model, url and view set up but I'm sure I'm missing some piece to the puzzle.
<form action="{% url 'update-photo' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<table class="table-form">
{{ form|crispy }}
</table>
<input type="submit" class="btn btn-lg custom-bg">
<br><br>
</form>
class User(AbstractUser):
is_active = models.BooleanField(default=False)
class Person(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
upload = models.FileField(default='core/static/images/default_avatar.png')
class UpdatePhotoForm(forms.ModelForm):
class Meta:
model = Person
fields = ('upload',)
#login_required
def update_photo(request):
person = Person.objects.get(user=request.user)
from core.forms import UpdatePhotoForm
if request.method == "POST":
form = UpdatePhotoForm(data=request.POST, instance=request.user.person)
if form.is_valid():
person = form.save(commit=False)
person.save()
return redirect('profile')
else:
form = UpdatePhotoForm()
return render(request, 'core/edit_profile.html', {'form': form})
path('update_photo/', core_views.update_photo, name='update-photo'),
The form submits without any error but does not actually update the user's photo. I can change the photo in the admin site but not via the form. Any help would be greatly appreciated!
You will have to fetch file field from request Object with following code:
form = UpdatePhotoForm(data=request.POST, files=request.FILES, instance=request.user.person)
I have a edit page which you can edit your personal information that you register, such as username, first_name, last_name, email. But inside the page i have some extra field such as description, city, website field that you can add/edit into your profile if you wanted to.But after i edit the personal info and fill in the extra field for testing and press the confirm button, the personal information being edit succesfully and there is no error occur. But the problem is when i check the data at Django admin, the UserExtraField model is empty. I hope my explanation is good enough.
the problem is i cant save the extra field to the user that login, but the personal information edit work fine, just the extra field cannot be save to the person. i want the user able to edit their personal profile and also add/edit the extra field if they want to.when they edit their personal profile, i want to add some field so they can have more information in their profile.
there is a picture link at the below too.Thank you.
views.py file
def UserProfileEdit(request):
if request.method == 'POST':
form_edit = EditForm(request.POST, instance= request.user)
form_extra = UserExtra(request.POST,instance=request.user)
if form_edit.is_valid() and form_extra.is_valid():
edit = form_edit.save()
extra = form_extra.save()
extra.user = edit
return redirect('/userprofile/user')
else:
form_edit = EditForm(instance = request.user)
form_extra = UserExtra(instance = request.user)
user_edit = {'form_edit':form_edit,'form_extra':form_extra}
return render(request,'user_profile/user_edit.html',context=user_edit)
forms.py
class EditForm(UserChangeForm):
class Meta():
model = User
fields = ('username', 'first_name', 'last_name', 'email', "password")
#make another forms for extra profile imformation
class UserExtra(forms.ModelForm):
class Meta():
model = UserExtraProfile
fields = ('description','city','website')
models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
# Create your models here.
class UserExtraProfile(models.Model):
#inherit the User model pk
user = models.OneToOneField(User, on_delete = models.CASCADE)
description = models.CharField(max_length= 250,default= '')
city = models.CharField(max_length=250,default= '')
website = models.URLField(blank= True,default= '')
# image = models.ImageField(upload_to='media/profile_pic', blank=True)
def __str__(self):
return self.user.username
def create_profile(sender,**kwargs):
if kwargs['created']:
user_profile = UserExtraProfile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender = User)
user_edit.html
{% extends 'base.html'%}
{% load bootstrap3 %}
{% load staticfiles %}
{% block content %}
<div class="container">
<h1>User Profile Edit</h1>
<form method="POST">
{% csrf_token %}
{% bootstrap_form form_edit %}
{% bootstrap_form form_extra %}
<input type="submit" class="btn btn-default" value="Confirm">
</form>
</div>
{% endblock %}
enter image description here
You didn't save the extraprofile after assigning the user. Use commit=False in the form save so you don't hit the db twice.
user = form_edit.save()
extra = form_extra.save(commit=False)
extra.user = user
extra.save()
Also, you need to pass the profile, not the user, to the profile form.
form_extra = UserExtra(request.POST, instance=request.user.userextraprofile)
My site is set up so there is no username (or rather user.username = user.email). Django has an error message if a user tries to input a username that is already in the database, however since I'm not using a username for registration I can't figure out how to do this.
Just like the default settings already is, I don't want to reload the page to find out if there is an email address already associated with a user. My guess is to use Ajax, but I can't figure out how to do it. Ive looked at other posts, but there doesn't seem to be anything recent.
How can I check to see if an email address already exists, and if so, give an error message for the user to input a new email address?
models.py:
class MyUsers(models.Model):
user = models.OneToOneField(User)
first_name = models.CharField(max_length=100, blank=True)
last_name = models.CharField(max_length=100, blank=True)
email = models.EmailField(max_length=100, blank=True, unique=True)
company = models.CharField(max_length=100, blank=True, null=True)
website = models.URLField(max_length=100, blank=True, null=True)
phone_number = models.CharField(max_length=100, blank=True, null=True)
def __str__(self):
return self.user.username
forms.py:
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('email',)
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('first_name', 'last_name', 'company', 'website', 'phone_number')
views.py:
def index(request):
registered = False
if request.method == 'POST':
user_form = UserForm(data=request.POST)
profile_form = UserProfileForm(data=request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.password = ""
user.username = user.email
user.save()
profile = profile_form.save(commit=False)
profile.user = user
profile.email = user.email
profile.save()
user.first_name = profile.first_name
user.last_name = profile.last_name
user.save()
registered = True
return HttpResponseRedirect(reverse('registration'))
else:
print user_form.errors, profile_form.errors
else:
user_form = UserForm()
profile_form = UserProfileForm1()
context = {'user_form': user_form, 'profile_form': profile_form, 'registered': registered}
return render(request, 'mysite/register.html', context)
register.html:
{% extends 'mysite/base.html' %}
{% load staticfiles %}
{% block title_block %}
Register
{% endblock %}
{% block head_block %}
{% endblock %}
{% block body_block %}
<form id="user_form" method="post" action="/mysite/" enctype="multipart/form-data">
{% csrf_token %}
{{ user_form.as_p }}
{{ profile_form.as_p }}
<input type="submit" name="submit" value="Register" />
</form>
{% endblock %}
You can override the clean_<INSERT_FIELD_HERE>() method on the UserForm to check against this particular case. It'd look something like this:
forms.py:
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('email',)
def clean_email(self):
# Get the email
email = self.cleaned_data.get('email')
# Check to see if any users already exist with this email as a username.
try:
match = User.objects.get(email=email)
except User.DoesNotExist:
# Unable to find a user, this is fine
return email
# A user was found with this as a username, raise an error.
raise forms.ValidationError('This email address is already in use.')
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('first_name', 'last_name', 'company', 'website', 'phone_number')
You can read more about cleaning specific fields in a form in the Django documentation about forms.
That said, I think you should look into creating a custom user model instead of treating your User Profile class as a wrapper for User.
I'm trying to write a small Django system. After logging into the system, a user can edit and save his/her own profile information. The fields involved are: username, email, first name, last name, website and picture.
The problem: The picture cannot be updated (After selecting an image and clicking "update" button, it shows "No file selected". The profile picture displayed on the page is still the old one). But the other fields are all OK.
Here are my codes:
models.py:
class UserProfile(models.Model):
user = models.OneToOneField(User)
website = models.URLField(blank=True)
picture = models.ImageField(upload_to="profile_images", blank=True)
def __str__(self):
return self.user.username
forms.py:
class UserForm2(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'email', 'first_name', 'last_name')
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('website', 'picture')
views.py:
#login_required
def update_user(request):
try:
user_profile = UserProfile.objects.get(user=request.user)
except UserProfile.DoesNotExist:
return HttpResponse("invalid user_profile!")
if request.method == "POST":
update_user_form = UserForm2(data=request.POST, instance=request.user)
update_profile_form = UserProfileForm(data=request.POST, instance=user_profile)
if update_user_form.is_valid() and update_profile_form.is_valid():
user = update_user_form.save()
profile = update_profile_form.save(commit=False)
profile.user = user
if 'picture' in request.FILES:
profile.picture = request.FILES['picture']
profile.save()
else:
print(update_user_form.errors, update_profile_form.errors)
else:
update_user_form = UserForm2(instance=request.user)
update_profile_form = UserProfileForm(instance=user_profile)
return render(request,
'userprofile/update_user.html',
{'update_user_form': update_user_form, 'update_profile_form': update_profile_form}
)
update_user.html:
<form id="update_user_form" method="POST" action="/userprofile/update_user/">
{% csrf_token %}
{{ update_user_form.as_p }}
{{ update_profile_form.as_p }}
<img src="{{ update_profile_form.instance.picture.url }}" />
<br />
<input type="SUBMIT" name="submit" value="Update"/>
</form>
How can I make it work properly?
To upload the file you should add the enctype attribute to the <form> tag:
<form id="update_user_form" method="POST" action="/userprofile/update_user/"
enctype="multipart/form-data">