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())
Related
I wrote an edit test, the response status code is working very fine which is 302 but I went ahead to assertEquals to the updated content but it was throwing assertion error.
MODELS
class Banner(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=150 , unique=True)
description = RichTextField(blank=True, null=True)
category = models.CharField(max_length=200)
tag = models.CharField(max_length=200)
image = models.ImageField(upload_to='banner-images/')
slug = models.SlugField(unique=True, max_length=100)
def __str__(self):
return self.name
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)
return super(Banner, self).save(*args, **kwargs)
VIEWS
#login view
def loginPage(request):
context = {}
if request.user.is_authenticated:
return redirect('home')
if request.method == 'POST':
email = request.POST.get('email')
password = request.POST.get('password')
try:
user = User.objects.get(email=email)
except:
messages.error(request, 'User does not exist')
user = authenticate(request, email=email, password=password)
if user is not None:
login(request, user)
return redirect('home')
return render(request,'registration/login.html', context)
#edit banner view
#login_required(login_url='login')
def editBanner(request, slug):
banner = get_object_or_404(Banner.objects.all(), slug=slug)
if request.user == banner.user:
form = BannerForm(instance = banner)
if request.method =="POST":
form = BannerForm(request.POST, request.FILES, instance = banner)
if form.is_valid():
form.save()
return redirect('home')
context = {'form':form, 'banner':banner}
return render(request, 'edit-banner.html', context)
return redirect('home')
URLS
from django.urls import path
from . import views
urlpatterns = [
path('banner/<slug:slug>/edit/', views.editBanner, name='edit-banner'),
]
TEST
def test_edit_banner(self):
new_banner = Banner.objects.create(
name='The Test Banner',
description='Test Description',
category='testcategory',
user= self.user,
slug= 'the-test-banner',
tag='testtag',
image='testimage.jpg',
)
response = self.client.post(reverse('edit-banner', args=['the-test-banner']), {
'name': 'The Test Banner',
'description': 'Edited Test Description',
'category': 'testcategory',
'user': self.user,
'tag': 'testtag',
'image': 'testimage.jpg',
})
self.assertEquals(response.status_code, 302)
new_banner.refresh_from_db()
self.assertEquals(new_banner.description, 'Edited Test Description')
But I keep getting this error after many tweaking
I want to get the description of the edited version of the banner, thanks.
So, i have a problem. I have a login form, but when i try to login it writes that ' ' is already exists. How is it possible?If user has an account it means that it'll exists. But why i get this mistake?
views.py
def login(request):
if request.method == 'POST':
form = LoginForm(request.POST, request.FILES)
print(form.errors)
if form.is_valid():
cd = form.cleaned_data
user = authenticate(email=cd['email'], password=cd['password'])
if user is not None:
if user.is_active:
login(request, user)
return HttpResponse('Authenticated successfully')
else:
return HttpResponse('Disabled account')
else:
return HttpResponse('Invalid login')
else:
return HttpResponse('Form is not valid')
else:
form = LoginForm()
return render(request, 'account/login.html', {'form': form})
I get a mistake:
<ul class="errorlist"><li>email<ul class="errorlist"><li>User with this already exists.</li></ul></li></ul>
Login form
class LoginForm(ModelForm):
class Meta:
model = User
fields = ['email', 'password']
widgets = {
'email': EmailInput(attrs={
'class': 'form-email',
'placeholder': 'email'
}),
'password': PasswordInput(attrs={
'class': 'form-password',
'placeholder': 'password'
})
}
User model
class User(models.Model):
CHOICES = (
('1', 'Author'),
('2', 'Customer'),
('3', 'Author and Customer')
)
first_name = models.CharField(max_length=64, blank=False, verbose_name='')
last_name = models.CharField(max_length=64, blank=False, verbose_name='')
patronymic = models.CharField(max_length=64, blank=False, verbose_name='')
age = models.PositiveSmallIntegerField(verbose_name='', blank=False)
email = models.EmailField(unique=True, max_length=128, blank=False, verbose_name='')
password = models.CharField(max_length=32, blank=False, verbose_name='')
role = models.CharField(max_length=32, choices=CHOICES, default='Customer')
about = models.TextField(max_length=512, verbose_name='', blank=True)
When a ModelForm has no instance specified it means it is being used to create an instance and hence when is_valid is called on your form it finds that the username you provide already exists and hence it returns False. For this reason a form used to log a user in needs to be a plain Form class.
Moving further Django already provides a built in form that can be used for authentication django.contrib.auth.forms.AuthenticationForm [Django docs]. Looking at your implementation you have a custom user model with email as the USERNAME_FIELD? The AuthenticationForm is versatile enough to handle this so you can directly use that in your view (or if you want to customize the form widgets you may inherit from it).
If you want to set attributes on the widgets, simply inherit from AuthenticationForm and set them in the forms __init__ method:
from django.contrib.auth.forms import AuthenticationForm
class LoginForm(AuthenticationForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['username'].widget.attrs.update({'class': 'form-email', 'placeholder': 'email'})
self.fields['password'].widget.attrs.update({'class': 'form-password', 'placeholder': 'password'})
Next use this form in your view:
def login(request):
if request.method == 'POST':
form = LoginForm(request, request.POST, request.FILES)
print(form.errors)
if form.is_valid():
user = form.get_user()
if user is not None:
if user.is_active:
login(request, user)
return HttpResponse('Authenticated successfully')
else:
return HttpResponse('Disabled account')
else:
return HttpResponse('Invalid login')
else:
return HttpResponse('Form is not valid')
else:
form = LoginForm(request)
return render(request, 'account/login.html', {'form': form})
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.
I am trying to build multi vendor e-commerce using django rest-framework. I stuck at how to authenticate multi-users like i have customers and sellers . i have successfully created API's for sellers but i am unable to give roles to uses. (Basically we are building mobile app and web)
my models are:
from django.db import models
from django.contrib.auth.models import User
from django.db import models
# Create your models here.
class SellerProfile(models.Model):
user = models.OneToOneField(
User, blank=True, null=True, on_delete=models.SET_DEFAULT, default=None)
mobileNo = models.CharField(max_length=40, default=None)
cnic = models.CharField(max_length=30, default=None)
city = models.CharField(max_length=30, default=None)
address = models.CharField(max_length=30, default=None)
state = models.CharField(max_length=30, default=None)
shop_name = models.CharField(max_length=30, default=None)
def __str__(self):
return self.user.username
class ClientProfile(models.Model):
user = models.OneToOneField(User, models.SET_DEFAULT, default=None)
def __str__(self):
return self.user.username
and my serializers :
from profiles.models import SellerProfile, ClientProfile
from rest_framework import serializers, status
# from models import *
from django.contrib.auth.models import User
from django.contrib.auth.hashers import make_password
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(
write_only=True,
required=True,
help_text='password',
style={'input_type': 'password', 'placeholder': 'Password'}
)
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password')
def create(self, validated_data):
user = super().create(validated_data)
user.set_password(validated_data['password'])
user.save()
return user
# def __str__(self):
# return self.user
class ClientSerializer(serializers.ModelSerializer):
user = UserSerializer(required=True)
class Meta:
model = ClientProfile
fields = ['user']
def create(self, validated_data):
user_data = validated_data.pop('user')
user = UserSerializer.create(
UserSerializer(), validated_data=user_data)
buyer, created = ClientProfile.objects.update_or_create(
user=user,
# mobileNo=validated_data.pop('mobileNo'),
# location=validated_data.pop('location'),
# address=validated_data.pop('address'),
)
return buyer
class SellerSerializer(serializers.ModelSerializer):
user = UserSerializer(required=True)
class Meta:
model = SellerProfile
fields = ('user', 'mobileNo', 'cnic',
'city', 'address', 'state', 'shop_name')
def create(self, validated_data):
user_data = validated_data.pop('user')
user = UserSerializer.create(
UserSerializer(), validated_data=user_data)
seller, created = SellerProfile.objects.update_or_create(user=user,
mobileNo=validated_data.pop(
'mobileNo'),
cnic=validated_data.pop(
'cnic'),
city=validated_data.pop(
'city'),
address=validated_data.pop(
'address'),
shop_name=validated_data.pop(
'shop_name'),
)
return seller
here is my view set :
from .serializers import *
from profiles.models import *
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import status
class SellerViewSet(viewsets.ModelViewSet):
serializer_class = SellerSerializer
queryset = SellerProfile.objects.all()
def get(self, format=None):
seller = SellerProfile.objects.all()
serializer = SellerSerializer(seller, many=True)
return Response(serializer.data)
def post(self, request):
serializer = SellerSerializer(data=request.data)
if serializer.is_valid(raise_exception=ValueError):
serializer.create(validated_data=request.data)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.error_messages,
status=status.HTTP_400_BAD_REQUEST)
class BuyerViewSet(viewsets.ModelViewSet):
serializer_class = ClientSerializer
queryset = ClientProfile.objects.all()
def get(self, format=None):
seller = ClientProfile.objects.all()
serializer = UserSerializer(seller, many=True)
return Response(serializer.data)
def post(self, request):
serializer = ClientSerializer(data=request.data)
if serializer.is_valid(raise_exception=ValueError):
serializer.create(validated_data=request.data)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.error_messages,
status=status.HTTP_400_BAD_REQUEST)
here is views for web registration:
def registration(request):
if request.method == 'POST':
form = UserForm(request.POST)
sellerFrom = SellerFrom(request.POST)
if form.is_valid() and sellerFrom.is_valid():
user = form.save()
seller = sellerFrom.save()
seller.user = user
seller.save()
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password1')
# user = authentication(username=username, password=password)
# login(request, user)
messages.success(request, 'account was created for' + username)
form = UserForm()
sellerFrom = SellerFrom()
return redirect('login')
else:
form = UserForm()
sellerFrom = SellerFrom()
context = {'form': form, 'sellerForm': sellerFrom}
return render(request, 'gui/signup.html', context)
here is view for login :
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
if user is not None:
# if user.role == "seller_profile":
auth_login(request, user)
return redirect('home')
else:
messages.info(request, 'Username or password is incorrect')
context = {}
return render(request, 'gui/login.html', context)
Now what above coding is doing . actually it handling user registration and login but i want to give them role like seller = seller_role and client = client_role. and also want to know how to authenticate user while login whether it is seller or client.
i am looking for answer thank you so much and sorry for my bad english
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)