Skip to content

Commit

Permalink
Merge pull request #51 from yceruto/fix_issue_50
Browse files Browse the repository at this point in the history
Fix unexpected keyword argument 'request' when using ajax decorator and 404 exception
  • Loading branch information
yceruto authored Feb 7, 2019
2 parents 50eb130 + 9f64eda commit d779762
Show file tree
Hide file tree
Showing 21 changed files with 347 additions and 26 deletions.
7 changes: 4 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ matrix:
sudo: true

env:
- DJANGO_VERSION=2.0.8
- DJANGO_VERSION=2.*

install:
- pip install django~=$DJANGO_VERSION
- pip install django==$DJANGO_VERSION
- python setup.py install

script:
- python tests/manage.py test example
- python tests/ajaxmiddleware/manage.py test app
- python tests/ajaxdecorator/manage.py test app
4 changes: 2 additions & 2 deletions django_ajax/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ def inner(request, *args, **kwargs):
if request.is_ajax():
# return json response
try:
return render_to_json(func(request, *args, **kwargs), **ajax_kwargs)
return render_to_json(func(request, *args, **kwargs), request, **ajax_kwargs)
except Exception as exception:
return render_to_json(exception, **{'request': request})
return render_to_json(exception, request)
else:
# return standard response
return func(request, *args, **kwargs)
Expand Down
4 changes: 2 additions & 2 deletions django_ajax/encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class LazyJSONEncoder(LazyJSONEncoderMixin, json.JSONEncoder):
pass


def serialize_to_json(data, *args, **kwargs):
def serialize_to_json(data, **kwargs):
"""
A wrapper for simplejson.dumps with defaults as:
Expand All @@ -65,4 +65,4 @@ def serialize_to_json(data, *args, **kwargs):
"""
kwargs['cls'] = kwargs.get('cls', LazyJSONEncoder)

return json.dumps(data, *args, **kwargs)
return json.dumps(data, **kwargs)
4 changes: 2 additions & 2 deletions django_ajax/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class JSONResponse(HttpResponse):
Return a JSON serialized HTTP response
"""

def __init__(self, data, *args, **kwargs):
def __init__(self, data, **kwargs):
"""
This returns a object that we send as json content using
utils.serialize_to_json, that is a wrapper to json.dumps
Expand All @@ -26,6 +26,6 @@ def __init__(self, data, *args, **kwargs):
kwargs['sort_keys'] = settings.DEBUG

super(JSONResponse, self).__init__(
content=serialize_to_json(data, *args, **kwargs),
content=serialize_to_json(data, **kwargs),
content_type='application/json'
)
6 changes: 3 additions & 3 deletions django_ajax/shortcuts.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
}


def render_to_json(response, *args, **kwargs):
def render_to_json(response, request=None, **kwargs):
"""
Creates the main structure and returns the JSON response.
"""
Expand All @@ -87,7 +87,7 @@ def render_to_json(response, *args, **kwargs):
status_code = 404
elif issubclass(type(response), Exception):
status_code = 500
logger.exception(str(response), extra={'request': kwargs.pop('request', None)})
logger.exception(str(response), extra={'request': request})

if settings.DEBUG:
import sys
Expand All @@ -106,5 +106,5 @@ def render_to_json(response, *args, **kwargs):
'content': response
}

return JSONResponse(data, *args, **kwargs)
return JSONResponse(data, **kwargs)

File renamed without changes.
Empty file.
File renamed without changes.
File renamed without changes.
39 changes: 39 additions & 0 deletions tests/ajaxdecorator/app/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from django.contrib.auth.decorators import login_required
from django.views.generic import TemplateView
from django.shortcuts import render
from django.http import Http404

from django_ajax.decorators import ajax
from django_ajax.mixin import AJAXMixin


@ajax
def foo_view(request):
return {'foo': True}


@ajax
@login_required
def login_required_view(request):
# if the request.user is anonymous then this view not proceed
return {'user_id': request.user.id}


@ajax
def render_view(request):
return render(request, 'hello.html')


class SimpleView(AJAXMixin, TemplateView):
template_name = 'hello.html'


@ajax
def exception_view(request):
a = 23 / 0 # this line throws an exception
return a


@ajax
def raise_exception_view(request):
raise Http404
File renamed without changes.
172 changes: 172 additions & 0 deletions tests/ajaxdecorator/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
from __future__ import absolute_import

import os
import sys

sys.path.insert(0, '../')

ROOT_DIR = os.path.dirname(__file__)

DEBUG = True
TEMPLATE_DEBUG = DEBUG

ADMINS = (
('Yonel Ceruto', '[email protected]'),
)

MANAGERS = ADMINS

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(ROOT_DIR, 'data.sqlite3'),
}
}

# A boolean that specifies if datetimes will be timezone-aware by default or
# not. If this is set to True, Django will use timezone-aware datetimes
# internally. Otherwise, Django will use naive datetimes in local time.
USE_TZ = True

# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'UTC'

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'

SITE_ID = 1

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True

# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale
USE_L10N = True

# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = ''

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
MEDIA_URL = ''

# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = ''

# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'

# URL prefix for admin static files -- CSS, JavaScript and images.
# Make sure to use a trailing slash.
# Examples: "http://foo.com/static/admin/", "/static/admin/".
ADMIN_MEDIA_PREFIX = '/static/admin/'

# Make this unique, and don't share it with anybody.
SECRET_KEY = '(l*w&8lg1co#vw#3$1#i^!!!tvhiw061%@jm*_-#_o@jv-y^#d'

MIDDLEWARE = (
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'urls'

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(ROOT_DIR, 'app/templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

INSTALLED_APPS = (
'app',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
)

AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]

# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': [],
'class': 'django.utils.log.AdminEmailHandler'
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
}

# Only run Jenkins report generation on these apps.
PROJECT_APPS = ('app',)

# Which Jenkins reports/tasks to run.
JENKINS_TASKS = ('django_jenkins.tasks.run_pylint',
'django_jenkins.tasks.run_pep8',
'django_jenkins.tasks.run_pyflakes',
'django_jenkins.tasks.with_coverage',
'django_jenkins.tasks.django_tests',)

# The test runner for the Jenkins command.
JENKINS_TEST_RUNNER = 'django_jenkins.runner.CITestSuiteRunner'

# django-ajax specific settings
MAX_PER_PAGE = 20
2 changes: 1 addition & 1 deletion tests/urls.py → tests/ajaxdecorator/urls.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from __future__ import absolute_import
from example import views
from app import views
import django

try:
Expand Down
Empty file.
Empty file.
1 change: 1 addition & 0 deletions tests/ajaxmiddleware/app/templates/hello.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<html>Hello</html>
74 changes: 74 additions & 0 deletions tests/ajaxmiddleware/app/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from __future__ import unicode_literals
from datetime import datetime
from django.test import TestCase
from django.utils import six
from django_ajax.encoder import LazyJSONEncoder
import json


class LazyJSONEncoderMixinTestCase(TestCase):
def test_default_date(self):
data = {'datetime': datetime.today()}
self.assertEqual('{"datetime": "' + data['datetime'].isoformat() + '"}', json.dumps(data, cls=LazyJSONEncoder))


class BaseTestCase(TestCase):
def post(self, uri, data=None):
response = resp = self.client.get(uri, data, HTTP_X_REQUESTED_WITH='XMLHttpRequest')

self.assertEquals(200, resp.status_code)
self.assertEquals('application/json', response['Content-Type'])
if isinstance(response.content, six.text_type):
return response, json.loads(response.content)
else:
return response, json.loads(response.content.decode('utf-8'))


class FooTestCase(BaseTestCase):
def test_json_response(self):
resp, data = self.post('/ajax/foo')

self.assertEqual('OK', data['statusText'])
self.assertEqual({'foo': True}, data['content'])


class LoginRequiredTestCase(BaseTestCase):
def test_json_response(self):
resp, data = self.post('/ajax/login-required')

self.assertEquals(302, data['status'])
self.assertEqual('FOUND', data['statusText'])


class RenderTestCase(BaseTestCase):
def test_json_response(self):
resp, data = self.post('/ajax/render')

self.assertEquals(200, data['status'])
self.assertEqual('OK', data['statusText'])
self.assertEqual('<html>Hello</html>', data['content'].strip())


class RenderClassBasedViewTestCase(BaseTestCase):
def test_json_response(self):
resp, data = self.post('/ajax/render-class-based-view')

self.assertEquals(200, data['status'])
self.assertEqual('OK', data['statusText'])
self.assertEqual('<html>Hello</html>', data['content'].strip())


class ExceptionTestCase(BaseTestCase):
def test_json_response(self):
resp, data = self.post('/ajax/exception')

# self.assertEquals(200, data['status'])
self.assertEqual('INTERNAL SERVER ERROR', data['statusText'])


class RaiseExceptionTestCase(BaseTestCase):
def test_json_response(self):
resp, data = self.post('/ajax/raise-exception')

# self.assertEquals(200, data['status'])
self.assertEqual('NOT FOUND', data['statusText'])
Loading

0 comments on commit d779762

Please sign in to comment.