How to edit user's profile page on django? - python

My django project has multiple functions, one of them lets the user update its profile(User model"first_name, username and email" Profile model" bio and profile picture") this used to perfectly work until I added a follow sistem, it is like the whole Profile and User model doesnt exist anymore so when trying to edit those fields, the code returns a AttributeError: 'User' object has no attribute 'profile' error, saying this line of code on the views.py file is wrong form1 = UpdateProfileForm(request.POST or None, request.FILES, instance=request.user.profile), I think I am missing something on there or there is probably there is something wrong.
views.py
def profile(request, username=None):
profile, created = Profile.objects.get_or_create(user=request.user)
user = User.objects.get(username=username)
if username:
post_owner = get_object_or_404(User, username=username)
user_posts = Profile.objects.filter(user_id=post_owner)
is_following = Following.objects.filter(user=request.user, followed=user)
following_obj = Following.objects.get(user=user)
follower = following_obj.follower.count()
following = following_obj.followed.count()
else:
post_owner = request.user
user_posts = Profile.objects.filter(user=request.user)
args1 = {
'post_owner': post_owner,
'user_posts': user_posts,
'follower': follower,
'following': following,
'connection': is_following,
}
return render(request, 'profile.html', args1)
def edit_profile(request):
profile, created = Profile.objects.get_or_create(user=request.user)
if request.method == 'POST':
form = EditProfileForm(request.POST, instance=request.user)
form1 = UpdateProfileForm(request.POST or None, request.FILES, instance=request.user.profile)
if form.is_valid and form1.is_valid:
form.save()
form1.save()
return redirect('profile')
else:
form = EditProfileForm(instance=request.user)
form1 = UpdateProfileForm(instance=request.user)
args = {
'form': form,
'form1': form1,
}
return render(request, 'profile-edit.html', args)
models.py
class Profile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
profile_pic = models.ImageField(upload_to='profile_pics', null=True, blank=True, default='default.png')
bio = models.CharField(max_length=400, default=1, null=True)
connection = models.CharField(max_length = 100, blank=True)
follower = models.IntegerField(default=0)
following = models.IntegerField(default=0)
def __str__(self):
return f'{self.user.username} Profile'
class Following(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
followed = models.ManyToManyField(User, related_name="followed")
follower = models.ManyToManyField(User, related_name="follower")
#classmethod
def follow(cls, user, another_account):
obj, create = cls.objects.get_or_create(user = user)
obj.followed.add(another_account)
print("followed")
#classmethod
def unfollow(cls, user, another_account):
obj, create = cls.objects.get_or_create(user = user)
obj.followed.remove(another_account)
print("unfollowed")
def __str__(self):
return f'{self.user.username} Profile'
forms.py
class EditProfileForm(UserChangeForm):
class Meta:
model = User
fields = (
'first_name',
'username',
'email',
)
exclude = ('password',)
class UpdateProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = (
'bio',
'profile_pic',
)
If you need to see more code please let me know;)

Try this:
def edit_profile(request):
profile, created = Profile.objects.get_or_create(user=request.user)
if request.method == 'POST':
form = EditProfileForm(request.POST, instance=request.user)
form1 = UpdateProfileForm(request.POST or None, request.FILES, instance=request.user.profile)
if form.is_valid() and form1.is_valid():
form.save()
form1.save()
return redirect('profile')
else:
form = EditProfileForm(instance=request.user)
form1 = UpdateProfileForm(instance=profile)
args = {
'form': form,
'form1': form1,
}
return render(request, 'profile-edit.html', args)

The solution I found temporarily to solve this problem is to just changed Profile's user object to OneToOneField and Following's user model to ForeignKey.

Related

How to test registration form in django?

I have a test to check if registration form works correctly but user doesn't create. I don't understand why. For example if in test I use assertEqual(Profile.objects.last().user, 'test1'), it is said that it's Nonetype object. If I check response's status code, it is 200. So I can be sure that page works.
And finally If I go to this register page and create a user with the same information by myself it will be created successfully.
What is the problem and how can I solve it?
Model:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
city = models.CharField(max_length=36, blank=True)
phone = models.IntegerField(blank=True)
verification = models.BooleanField(default=False)
quantity_posts = models.IntegerField(default=0)
def __str__(self):
return str(self.user)
def get_absolute_url(self):
return reverse('information', args=[str(self.pk)])
Form:
class RegisterForm(UserCreationForm):
city = forms.CharField(max_length=36, required=False, help_text='Город')
phone = forms.IntegerField(required=False, help_text='Сотовый номер')
class Meta:
model = User
fields = ('username', 'city', 'phone', 'password1', 'password2')
View:
def register_view(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
user = form.save()
city = form.cleaned_data.get('city')
phone = form.cleaned_data.get('phone')
Profile.objects.create(
user=user,
city=city,
phone=phone,
)
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password1')
user = authenticate(username=username, password=password)
login(request, user)
return redirect('/')
else:
form = RegisterForm()
return render(request, 'users/register.html', {'form': form})
part of main urls:
path('users/', include('app_users.urls'))
part of app urls:
path('register/', register_view, name='register')
test:
def test_if_can_register_profile(self):
self.client.post('/users/register/', {
'username': 'test1',
'city': 'pavlodar',
'phone': 87055551122,
'password': 'Mypassword777',
'password confirmation': 'Mypassword777'
})
self.assertTrue(Profile.objects.filter(user__username='test1').exists())

Django - Error received when anonymous user submits form

In one of my views I have a form where when a user logs in and submits the form, it works fine.
However, when an anonymous user submits the form I get the following error:
Cannot assign "<SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x1052fd3a0>>": "User_Inquiries.user" must be a "CustomUser" instance.
This form needs to be submitted whether a user is anonymous or logged in.
What do I need to do in order to resolve this issue?
Code below.
Any help is gladly appreciated. Thanks!
views.py
def account_view_contact(request):
form = ContactUsForm(request.POST or None, request.FILES or None,)
user_profile = User_Inquiries.objects.all()
user_profile = User_Info.objects.all()
user = request.user
if request.method == "POST": # checking if request is POST or Not
# if its a post request, then its checking if the form is valid or not
if form.is_valid():
contact_instance = form.save(commit=False) # "this will return the 'Listing' instance"
contact_instance.user = user # assign 'user' instance
contact_instance.save() # calling 'save()' method of model
return redirect("home")
context = {
'form': form, 'user_profile': user_profile
}
return render(request, 'contact.html', context)
models.py
class User_Inquiries(models.Model):
email = models.EmailField(max_length=100, null=True)
name = models.CharField(max_length=100, null=True)
subject = models.CharField(max_length=100, null=True)
message = models.CharField(max_length=100, null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=False, on_delete=models.CASCADE)
date_submitted = models.DateTimeField(auto_now_add=True, null=True)
class Meta:
verbose_name_plural = "User Inquiries"
#property
def user_message(self):
return truncatechars(self.message, 30)
What you can do is :
First, add a user field with null=True
class User_Inquiries(models.Model):
# ....
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE)
# ...
Second, in your view, you need to provide the user field only if the user is authenticated. Because AnonymousUser can be saved in the database.
def account_view_contact(request):
user_profile = User_Info.objects.all()
# If it's a post request
if request.method == "POST":
form = ContactUsForm(request.POST, request.FILES or None,)
if form.is_valid():
if request.user is authenticated:
# Only authenticated user can be assigned
contact_instance = form.save(commit=False)
contact_instance.user = request.user
contact_instance.save()
return redirect("home")
else:
# Save the form without user because no user is logged in
form.save()
# Handle no POST request
else:
form = ContactUsForm()
context = {
'form': form, 'user_profile': user_profile
}
return render(request, 'contact.html', context)
the User_Inquiries model user should be blank = True and null = True. In the view check if the user is logged in before setting the contact_instance.user to user.
models.py
class User_Inquiries(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.CASCADE)
views.py
def account_view_contact(request):
form = ContactUsForm(request.POST or None, request.FILES or None,)
user_profile = User_Inquiries.objects.all()
user_profile = User_Info.objects.all()
# check if the user is authenticated
if request.user.is_authenticated:
user = request.user
if request.method == "POST": # checking if request is POST or Not
# if its a post request, then its checking if the form is valid or not
if form.is_valid():
contact_instance = form.save(commit=False) # "this will return the 'Listing' instance"
contact_instance.user = user # assign 'user' instance
contact_instance.save() # calling 'save()' method of model
return redirect("home")
context = {
'form': form, 'user_profile': user_profile
}
return render(request, 'contact.html', context)
check if user is authenticated in django
set null and blank = True
I tried the above solutions and it worked. I also used CreateView to figure this out and it worked flawlessly. Code below:
class account_view_contact(CreateView):
model = User_Inquiries
form_class = ContactUsForm
template_name = "contact.html"
success_url = reverse_lazy("home")
def form_valid(self, form):
if self.request.user.is_authenticated:
self.object = form.save(commit=False)
self.object.created_by = self.request.user
self.object.save()
else:
self.object = form.save(commit=False)
self.object.save()
return super().form_valid(form)
Thanks Everyone!

null value in column "user_id" violates not-null constraint Django form

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)

Django auth.models User One-To-Many (1048, "Column 'user_id' cannot be null")

I'm new to django and my task is to make user able to create a lot profiles after registration when he's logged in.
This is my models.py:
class Profile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(blank=False, max_length=100)
lastname = models.CharField( blank=False, max_length=100)
city = models.CharField( blank=True, max_length=100)
country = models.CharField( blank=True, max_length=100)
phonenumber = models.CharField(blank=False, null=True, max_length=20)
email = models.EmailField(blank=False, max_length=100)
date_of_birth = models.DateField( blank=True, null=True)
date_of_addition = models.DateField(auto_now=True, editable=False, null=True)
When I create my user, do login and press create profile button I get :
django.db.utils.IntegrityError: (1048, "Column 'user_id' cannot be null")
This is my views.py:
#login_required
def profile_create(request):
data = dict()
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid():
form.save()
data['form_is_valid'] = True
profiles = Profile.objects.all()
data['html_profile_list'] = render_to_string('basic_app/users_list_1_10.html', {'profiles': profiles})
else:
data['form_is_valid'] = False
else:
form = ProfileForm()
context = {'form': form}
data['html_form'] = render_to_string('basic_app/partial_profile_create.html', context, request=request)
return JsonResponse(data)
def register(request):
registered = False
if request.method == "POST":
user_form = UserForm(data=request.POST)
if user_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
registered = True
else:
print(user_form.errors)
else:
user_form = UserForm()
return render(request,'basic_app/registration.html',{'user_form':user_form,'registered':registered})
This is my forms.py:
from django import forms
from django.forms import ModelForm
from django.contrib.auth.models import User
from .models import Profile
class ProfileForm(ModelForm):
class Meta:
model = Profile
fields = ('name', 'lastname', 'city', 'country', 'phonenumber', 'email', 'date_of_birth')
class UserForm(ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
username = forms.CharField(help_text=False)
class Meta():
model = User
fields = ('username','password')
Thanks
It happens because in your Profile model you have user field which is ForeignKey. In Django ForeignKey is required by default, which means that you can't create new Profile without specifying user field. But you don't provide user in ProfileForm.
You can either provide user in ProfileForm or set user field as not required by adding:
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
I should request user before saving ProfileForm:
#login_required
def profile_create(request):
data = dict()
if request.method == 'POST':
form = ProfileForm(request.POST)
if form.is_valid():
add = form.save(commit=False)
add.user = request.user
add.save()
data['form_is_valid'] = True
profiles = Profile.objects.all()
data['html_profile_list'] = render_to_string('basic_app/users_list_1_10.html', {'profiles': profiles})
else:
data['form_is_valid'] = False
else:
form = ProfileForm()
context = {'form': form}
data['html_form'] = render_to_string('basic_app/partial_profile_create.html', context, request=request)
return JsonResponse(data)

Allow user's change from the frontend reflect on the backend(Django Admin)

I'm trying to let my users update their profile from the front-end allowing it to reflect at the django admin particularly updating of profile image. The change of user.first_name and user.last_name works fine except from the image which also doesn't reflect at the back end.
I think i'm missing something plus when the fields for firstname and lastname are empty it post as null I think I'd use an exception for that but i'm more concerned with the profile image. Please Help me I'm not getting it
here is my code
#views.py
def edit_user_profile(request, username):
user = request.user
form = EditProfileForm(request.POST or None, request.FILES, initial={'first_name': user.first_name, 'last_name': user.last_name})
if request.method == 'POST':
if form.is_valid():
# user.photo = UserExtended(photo=request.FILES['photo'] or None, )
photo = UserExtended.objects.get(user=user)
user.first_name = request.POST['first_name']
user.last_name = request.POST['last_name']
# username = request.POST['username']
photo.save()
user.save()
context = {
'form': form,
}
return render(request, 'accounts/profile_updated.html', context)
context = {
'form': form,
'username': username,
}
return render(request, 'accounts/edit_profile.html', context)
#model.py
#python_2_unicode_compatible # only if you need to support Python 2
class UserExtended(models.Model):
user = models.OneToOneField(User, related_name='user')
photo = models.ImageField(upload_to='media/user_media/users', verbose_name='Profile Picture',
default='/media/user_media/avatars/avatar.png', blank=True)
address = models.CharField(max_length=255)
phoneNumber = models.CharField(max_length=11)
class Meta:
verbose_name_plural = _("user")
def __str__(self):
return self.user.username
def image_tag(self):
if self.photo:
return mark_safe('<img src="/media/%s" width="150" height="150" />' % self.photo)
else:
return mark_safe('<img src="/media/user_media/avatars/avatar.png" width="150" height="150" />')
image_tag.allow_tags = True
image_tag.short_description = 'Profile Avatar'
def create_profile(sender, **kwargs):
user = kwargs["instance"]
if kwargs["created"]:
user_extended = UserExtended(user=user)
user_extended.save()
post_save.connect(create_profile, sender=User)
#forms.py
class EditProfileForm(forms.ModelForm):
first_name = forms.CharField(label='First Name', widget=forms.TextInput(attrs={'class': 'form-control'}),
required=False)
last_name = forms.CharField(label='Last Name', widget=forms.TextInput(attrs={'class': 'form-control'}),
required=False)
# username = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'}), required=True)
photo = forms.ImageField(label='Change Profile Image', required=False)
class Meta:
model = User
fields = ['photo', 'first_name', 'last_name', ] # 'username',
"""
Thank you in advance..
OK so while debugging with PyCharm, I discovered I was using the instance of my User class instead of my UserExtended which had the photo. I guess I got too comfortable since I was posting user.fist_name and user.last_name. This is the solution:
#views.py
def edit_user_profile(request, username):
user = request.user
form = EditProfileForm(request.POST or None, request.FILES, initial={'first_name': user.first_name, 'last_name': user.last_name})
if request.method == 'POST':
if form.is_valid():
#photo = UserExtended(photo=request.FILES['photo'] or None, )
user_extended = UserExtended.objects.get(user=user)
user.first_name = request.POST['first_name']
user.last_name = request.POST['last_name']
user_extended.photo = form.cleaned_data["photo"]
# username = request.POST['username']
user_extended.save()
user.save()
context = {
'form': form,
}
return render(request, 'accounts/profile_updated.html', context)
context = {
'form': form,
'username': username,
}
return render(request, 'accounts/edit_profile.html', context)

Categories

Resources