How to use Httprequest object in FormView? - django

i was converting the below function view in class based view :
but the problem was the below login code uses request object . so how to use this request in a form view .
Functional view i wanted to change to class based view :
def login(request):
if request.method == 'GET':
form = UserLoginForm()
elif request.method == 'POST':
form = UserLoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('name')
password = form.cleaned_data.get('password')
user = User.objects.filter(name=username, password=password).first()
if user is not None:
request.session['user'] = username
return redirect('index')
else:
messages.error(request, 'Username or password no matched')
return render(request, 'products_app/login.html', {'form': form})
FormView/class based view of the above code i changed to that gives error :
class Login(FormView):
template_name = 'products_app/login.html'
form_class = UserLoginForm
success_url = reverse_lazy('index')
def form_valid(self, form):
username = form.cleaned_data.get('name')
password = form.cleaned_data.get('password')
user = User.objects.filter(name=username, password=password).first()
if user is not None:
request.session['user'] = username
else:
messages.error(request, 'Username or password no matched')
super().form_valid(form)
here the problem is ,request is not being received unlike in the functional view of above def login(request). so gives error:
module 'django.http.request' has no attribute 'session'

The problem is you are using the request module as stated in the error. What you actually want is the request instance that invoked the class. Your code should be self.request.
I've eliminated all the superfluous code to only show the parts with request.
class Login(FormView):
...
def form_valid(self, form):
...
if user is not None:
self.request.session['user'] = username
else:
messages.error(self.request, 'Username or password no matched')
...

Related

Django testing view with pytest

Could you please helpe me debugging this test? I got this error (I don't know whay since, I
have no pk in view): django.contrib.auth.models.User.DoesNotExist: User matching query does not exist.I think the error is due to pk=request.user.id passed as argument in User objects in the view function.
class TestViews(TestCase):
def setUp(self):
self.client = Client()
self.create_campaign_naming_tool_url = reverse('create_campaign_naming_tool')
self.user = User.objects.create_user(
username = 'admin',
email = 'admin#sigma.fr',
password = '1234'
)
def test_create_campaign_naming_tool(self):
response = self.client.get(self.create_campaign_naming_tool_url)
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'form.html')
Here is my view
def create_campaign_naming_tool(request):
current_user = User.objects.get(pk=request.user.id)
form = CampaignNamingToolForm(initial={'user': current_user})
context = {
'form': form,
}
if request.method == 'POST':
campaign = CampaignNamingTool(user=current_user)
form = CampaignNamingToolForm(request.POST, instance=campaign)
if form.is_valid():
form.save()
messages.success(request, "Your campaign haven ben\
success fully created.")
return render(request, 'form.html', context)
return render(request, 'form.html', context)
You did not login the user in the test:
class TestViews(TestCase):
def setUp(self):
self.client = Client()
self.create_campaign_naming_tool_url = reverse('create_campaign_naming_tool')
self.user = User.objects.create_user(
username = 'admin',
email = 'admin#sigma.fr',
password = '1234'
)
self.client.login(username='admin', password='1234')
# …
It also makes no sense to do such query to fetch the user: request.user is a User object, so you can work directly with this:
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
#login_required
def create_campaign_naming_tool(request):
form = CampaignNamingToolForm(initial={'user': request.user})
if request.method == 'POST':
campaign = CampaignNamingTool(user=request.user)
form = CampaignNamingToolForm(request.POST, instance=campaign)
if form.is_valid():
form.save()
messages.success(request, 'Your campaign has been successfully created.')
return redirect('name-of-some-view')
context = {
'form': form,
}
return render(request, 'form.html', context)
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.

Django - How to allow registration only for predefined list of e-mails/usernames

I have a following simple view in my views.py for registration on my django site:
def register_user(request):
if request.method == "POST":
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
user = authenticate(username=username, password=password)
login(request, user)
messages.succes(request, ('You have registered'))
return redirect('home')
else:
form = UserCreationForm()
context = {'form': form}
return render(request, 'register.html', context)
That approach would allow anyone to register but I want to allow only selected people to be able to register. I have a simple model for my database
class EmailList(models.Model):
email_addres = models.CharField(max_length=300, blank=True)
def __str__(self):
return self.email_addres
with some e-mail addreses (my site doesn't have usernames, your username is an email addres) and I want to allow registration only for email addresses that are in that database. How would I perform such check?
There is a functionality in Django that limits an access to users that pass a certain test: https://docs.djangoproject.com/en/3.2/topics/auth/default/#limiting-access-to-logged-in-users-that-pass-a-test
You need to create a test function (verifying that the user is in allowed users list), and then use user_passes_test decorator on the view. In case you are using class based views, you need to use a UserPassesTestMixin.
Assuming your code works properly, just grab the contents of the AllowedUsers model and check whether the username is in the queryset.
models.py
class AllowedUsers(models.Model):
allowed_email = models.EmailField(max_length=256)
def __str__(self):
return self.allowed_email
views.py
def register_user(request):
if request.method == "POST":
form = UserCreationForm(request.POST)
if form.is_valid():
object = form.save(commit=False)
allowed_emails = [user.allowed_email for user in AllowedUsers.objects.all()]
if object['username'] in allowed_emails:
form.save()
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
user = authenticate(username=username, password=password)
login(request, user)
messages.success(request, ('You have registered'))
return redirect('home')
else:
return redirect('/login/?next=%s' % request.path)
I should say that if it were me, I'd be doing this while overriding the form_valid method of the default LoginView
Alternative views.py
from django.contrib.auth import views as auth_views
from django.forms import ValidationError
class LoginView(auth_views.LoginView):
def form_valid(self, form):
allowed_emails = [user.allowed_email for user in AllowedUsers.objects.all()]
if form.cleaned_data['username'] in allowed_emails:
return super().form_valid(form)
else:
self.add_error('username', ValidationError("The provided username is not allowed"))

passing object between forms and views

I have a problem with passing object between views and forms and back.
On first form i check token (GET) with email - if it's ok - you can go further. If not - go away :D
views.py:
def login(request):
try:
token = request.GET['token']
except:
return render(request,'error.html')
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
return HttpResponseRedirect('/vote/')
else:
form = LoginForm(initial={'token': request.GET['token']})
return render(request,'login.html', context = {'form':form})
forms.py:
class LoginForm(forms.Form):
email = forms.EmailField(label='Email', max_length=254,widget=forms.TextInput(attrs={'class':'required'}))
token = forms.CharField(widget=forms.HiddenInput())
def clean(self):
cleaned_data = super().clean()
try:
voter = Person.objects.get(email__iexact=cleaned_data['email'],token__exact=cleaned_data['token'])
except Person.DoesNotExist:
raise ValidationError('Invalid email')
It works.
But now i try to go to voting form.
And I want to use voter object (which is set in LoginForm). Of course this is different form, so I have to pass it. I thought about session, but there's no request.session in form. This is in view, but there's no voter... or is it?
As always when I'm stuck for many minutes, I wrote the question and after few minutes I got excellent solution, so I want to share it with you:
I moved checking into view and use form.add_error. And I don't need token hidden field anymore:
forms.py:
class LoginForm(forms.Form):
email = forms.EmailField(label='Email', max_length=254,widget=forms.TextInput(attrs={'class':'required'}))
views.py:
def login(request):
try:
token = request.GET['token']
except:
return render(request,'error.html')
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
try:
voter = Person.objects.get(email__iexact=form.cleaned_data['email'],token__exact=token)
return HttpResponseRedirect('/vote/')
except Person.DoesNotExist:
form.add_error('email','Invalid email')
else:
form = LoginForm()
return render(request,'login.html', context = {'form':form})
And now I can pass voter into next form using request, session, whatever :D

The set_password() method isn't encrypting the password in a custom Django user model

I am saving these details in a custom user model stored in MySQL, but the password is not getting encrypted; it is being saved in plain text.
def regauth(request):
if request.method == "POST":
form = UserAuth(data=request.POST)
# user_form = UserAuth(data=request.POST)
if form.is_valid():
try:
messages.info(request, 'inside try')
user = form.save()
user.set_password(form.password)
user.save()
return redirect('login_url')
except:
messages.info(request, 'inside exception')
return render(request, 'registration/registration.html', {'form': form})
else:
user_form = UserAuth()
return render(request, 'registration/registration.html', {'form': user_form})
Forms.py
class UserAuth(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = RegAuth
fields = "__all__"
How can I make sure the set_password() method gets called properly to encrypt the password?
Try this:
Saving with commit=False gets you a model object, then you can add your extra data and save it.
...
if form.is_valid():
user = form.save(commit=False) # <---
user.set_password(form.cleaned_data.get('password')) # <---
user.save()
...

Django 1.5 - Login

After creating a UserProfile model. I started to create login but I'm stuck because of get_user() error.
EXCEPTION
AttributeError: 'LoginForm' object has no attribute 'get_user'
Here are my codes:
UPDATE
class LoginView(FormView):
form_class = LoginForm
redirect_field_name = REDIRECT_FIELD_NAME
template_name = 'login.html'
success_url = '/'
def form_valid(self, form):
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(self.request, user)
return HttpResponseRedirect(self.get_success_url())
else:
return self.form_invalid()
def form_invalid(self):
return HttpResponseRedirect(reverse('accounts:login'))
def get_success_url(self):
if self.success_url:
redirect_to = self.success_url
else:
redirect_to = self.request.REQUEST.get(self.redirect_field_name, '')
netloc = urlparse.urlparse(redirect_to)[1]
if not redirect_to:
redirect_to = settings.LOGIN_REDIRECT_URL
elif netloc and netloc != self.request.get_host():
redirect_to = settings.LOGIN_REDIRECT_URL
return redirect_to
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid()
How to fix this? Any help would be appreciated. I'm really new on Django 1.5. Need help.
[update]
In the original code, the author is doing the authenticate stuff inside a form method called get_user. You are doing it outside the form already, so just replace form.get_user()with user.
I use a login view that is not class based, and I don't even care into using a Django form instance, but it should be easy to adapt:
def signin(request):
if request.method == 'POST':
user = authenticate(
email=request.POST.get('username', '').lower().strip(),
password= request.POST.get('password', ''),
)
if user is None:
messages.error(request, u'Invalid credentials')
else:
if user.is_active:
login(request, user)
return HttpResponseRedirect(request.GET.get('next', '/'))
else:
messages.error(request, u'User is not active.')
return render_to_response('login.html', locals(),
context_instance=RequestContext(request))
[old answer]
Define a get_user method for your form.
Untested (but should get you in the right path):
def get_user(self):
from django.contrib.auth import authenticate
return authenticate(
email=self.cleaned_data.get('username', '').lower().strip(),
password=self.cleaned_data.get('password', ''),
)