how to test a url with POST-arguments? - python

please help to write the test.
to address:
/edit_records/38/
uses the view edit_records().
Here's a test for it:
def test_edit_records(self):
resolver = resolve('/edit_records/38/')
self.assertEqual(resolver.func, edit_records)
And for an address:
/edit_records/38/
POST={
q:1,
w:2
}
view should be used my_records()
here's a non-working test for it:
def test_edit_records_POST(self):
resolver = resolve('/edit_records/38/', {q:1, w:2})
self.assertEqual(resolver.func, my_records)
here's an view, if you want to:
def edit_records(request, id_record):
entry = Diary.get_entry(id_record=id_record, user_id=request.user.pk)
form = addMessageForm(instance=entry)
if request.method == 'POST':
form = addMessageForm(request.POST, request.FILES, instance=entry)
if form.is_valid():
form.save()
return HttpResponseRedirect('/my_records/')
t = loader.get_template('page_edit_records.html')
c = RequestContext(request, {
'form': form,
})
return HttpResponse(t.render(c))

I'm not quite sure why you're doing all that stuff with resolver. That's not really relevant to a unit test; you don't ever call the view itself, so you're not testing any of its actual functionality, the only thing you're testing here is Django's URL resolver.
Instead, you should use the functionality provided by the test client to actually call your views:
def test_edit_records(self):
response = self.client.get('/edit_records/38/')
self.assertContains(response, 'some data you expect to see in the response')
And you can do the same with the POST:
def test_edit_records_POST(self):
response = self.client.POST('/edit_records/38/', {q:1, w:2})
self.assertTrue(something_about_the_response)

Related

How to move some code from post method to a separate method in Django views

I have a class that take some info from a form, make some changes to it. And than saves it into database
At the moment all the logic is in the post method. And I want to make the code more structured and I want to put some part of it to a separate method. Is it possible? If so, how can I do it?
here is my code:
class AddSiteView(View):
form_class = AddSiteForm
template_name = 'home.html'
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, { 'form': form })
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
site_instanse = form.save()
url = request.POST.get('url', '')
if url.endswith('/'):
url = url + "robots.txt"
else:
url = url + "/robots.txt"
robot_link = Robot(
site = site_instanse,
link = url,
)
robot_link.save()
pk = Robot.objects.get(site=site_instanse)
return redirect('checks:robots', pk.id)
return render(request, self.template_name, { 'form': form })
I want to make 2 changes to it:
The 1st thing I want to do is to move this part of code to a separate method
if url.endswith('/'):
url = url + "robots.txt"
else:
url = url + "/robots.txt"
And the 2nd thing I want to do is to move this part of code also in a separate method
robot_link = Robot(
site = site_instanse,
link = url,
)
robot_link.save()
pk = Robot.objects.get(site=site_instanse)
return redirect('checks:robots', pk.id)
The reason is that I will be adding more functions here. And I don't want to have it all in post method. If it is possible, please, help me. I've already tried several ways of solving this problem, but they didn't work
Thank you
There is nothing special about Django preventing you from using plain python functions. So, if you know how to define methods and functions, you should take the same approach. For example, the first part can be the function
def get_robots_url(url):
if url.endswith('/'):
url = url + "robots.txt"
else:
url = url + "/robots.txt"
return url
Then you call the extracted function in the same place
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
site_instance = form.save()
url = request.POST.get('url', '')
url = get_robots_url(url)
....
You can also define a function inside the class - a method, to group the code. For the 2nd part:
class AddSiteView(View):
...
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
site_instanse = form.save()
url = request.POST.get('url', '')
url = get_robots_url(url)
return self.create_robot(site_instanse, url)
return render(request, self.template_name, { 'form': form })
def create_robot(self, site_instance, url):
robot_link = Robot(
site = site_instanse,
link = url,
)
robot_link.save()
pk = Robot.objects.get(site=site_instance)
return redirect('checks:robots', pk.id)

how to write get and post test methods for views in django?

I'm new to Django's testing and trying to write test functions for views, but I don't get the whole test view thing, I've seen a lot of examples but it seems to be to difficult, I need an example on something I wrote to get the idea.
here's a function I want to test its post and get:
def ForgetPasswordRegistry(self, request):
forgetpassword = True
if request.method == 'GET':
if 'UserID' in request.session:
forgetpassword = False
return request, forgetpassword
elif request.method == 'POST':
email = request.POST['email']
if self.IsUserExist(email):
forget = models.ForgetPasswordRegistry()
forget.UserID = self.GetUser(email)
forget.Access = 1
session = random.randint(999999999999999, 9999999999999999999999999999999999)
forget.Session = str(session)
link = 'http://127.0.0.1:8000/home/resetpassword/' + forget.Session
self.SendEmail('Reset-Password', link, [forget.UserID.Email])
forget.save()
FeedBack = ' Check Your Mail You Got A Recovery Mail'
AlertType = 'alert-success'
return request, AlertType, None, FeedBack, None, None
else:
AlertType = 'alert-danger'
ModalFeedBack = 'This Email Dose Not Exist'
EmailErrors = 'This Email Dose Not Exist'
return request, AlertType, forgetpassword, None, EmailErrors, ModalFeedBack
Don't let the concept of views confuse you!! Essentially there is a python function that you need to exercise certain conditionals of.
It looks like there are 4 main branches:
GET not in session
GET in session
POST exists
POST does not exist
so there should probably be at least 4 different tests. I'll post the first one because it is pretty straightforward:
def ForgetPasswordRegistry(self, request):
forgetpassword = True
if request.method == 'GET':
if 'UserID' in request.session:
forgetpassword = False
return request, forgetpassword
def test_forget_get_user_id_in_session(self):
request = Mock(session={'UserID': 'here'}, method='GET')
# instantiate your view class
yourview = YourView()
sefl.assertEqual(yourview.ForgetPasswordRegistry(request), (request, False))
The post user exists branch is a little more complicated because there are more things that the test needs to account for, and potentially provide stub implementations for:
SendEmail
GetUser
models.ForgetPasswordRegistry()
Use Django's test client: https://docs.djangoproject.com/en/stable/topics/testing/tools/#the-test-client
Example:
from django.test import Client, TestCase
class ViewTestCase(TestCase):
def test_post_creation(self):
c = Client() # instantiate the Django test client
response = c.get('/forgetpassword/')
self.assertEqual(response.status, 200)

How to pass a value to a form for unittest?

I want to write test for my code and pass a value to a form how can i do that? I have two form in my code and this value should pass just to one of them.
my unittest:
def test_user_has_project(self):
resp = self.client.post('/register/', NEW_USER)
self.assertRedirects(resp, '/register/confirm/')
confirmation_code = self.client.session['confirm_code']
resp = self.client.post('/register/confirm/',
{'confirm_code':confirmation_code})
but this code pass confirmation code to both forms.
my views:
if request.method == 'POST':
form = forms.RegistrationConfirmForm(request.POST)
if (form.is_valid() and
form.cleaned_data['confirm_code'] == request.session['confirm_code']):
# Register the user in the backend
form = forms.RegistrationForm(request.session['registering_user'])
sorry. I'm a beginner in both coding and asking question!

Filter only if the value is defined in Django

I have the following view:
def process(request):
if request.method == 'POST':
data = request.POST
results = Specs.objects.filter(screenGroup = data['screen_user'], storage = data['storage_user'], mSystem = data['system_user'] )
context = {'results' : results}
return render(request, 'process.html', context)
When the user inputs the three values it filters correctly, but when it just inputs one or two (or nothing), then it filters passing the value None. Is there any way to ignore the filter if it's not set?
Thanks!
EDIT:
The following code is working, but it's obviously a very unefficient way:
def process(request):
if request.method == 'POST':
data = request.POST
if(data['screen_user'] != None):
results = Specs.objects.filter(screenGroup = data['screen_user'])
elif (data['storage_user'] != None):
results = Specs.objects.filter(storage = data['storage_user'])
else:
results = Specs.objects.all()
#plus all the other options...
context = {'results' : results}
return render(request, 'process.html', context)
You can build the filter beforehand:
def process(request):
if request.method == 'POST':
data = request.POST
spec_filter = {}
for attribute in ['screenGroup', 'storage', 'mSystem']:
if attribute in data and data[attribute]:
spec_filter[attribute] = data[attribute]
results = Specs.objects.filter(**spec_filter)
context = {'results' : results}
return render(request, 'process.html', context)
NB: To use this verbatim you would have to change the names of the variables being passed in the request.POST to match those in the Specs model. I did this just to illustrate, but you can easily use the same principle with your variable names. In that case you'll have to be a bit more verbose.
It's called validating your form.. There are two ways of doing this:
create a django form and use myform.is_valid(). You can read about it in the docs
validate it yourself with a few 'if' statements (either on server side or with javascript before sending the ajax call)

Commit a variable to the next function

I just simple want to pass the emailadress from def send_username to the second def username_is_send. How do I do it? How can I pass the variable to the next def?
#csrf_protect
def send_username(request, template_name='auth/user/registration/send_username_form.html',
email_template_name='auth/user/registration/send_username_email.html',
send_username_form=SendUsernameForm, post_reset_redirect=None):
if post_reset_redirect is None:
post_reset_redirect = reverse('auth.user.registration.views.username_is_send')
if request.method == "POST":
form = send_username_form(request.POST)
if form.is_valid():
opts = {}
opts['use_https'] = request.is_secure()
opts['email_template_name'] = email_template_name
opts['request'] = request
form.send_mail_now(**opts)
return HttpResponseRedirect(post_reset_redirect)
else:
form = send_username_form()
return render_to_response(template_name, {
'form': form,},
context_instance=RequestContext(request))
def username_is_send(request, template_name='tmp/username.html'):
return render_to_response(template_name, context_instance=RequestContext(request))
Thanks!
Craphunter
You need to store the state somehow in order to pass parameters through a redirect. Multiple possibilities:
Store the mail address in the session, then read in the session variable again in the username_is_send view.
Use a GET parameter to pass the mail address.
And it's "pass", not "path". And the "def" is called (view) function.

Categories

Resources