pytest-django RuntimeError : Database access not allowed, - django

I'm testing my django application using pytest / pytest-django.
my urls.py file contains
from django.urls import include, path
from . import views
urlpatterns = [
path('', include('django.contrib.auth.urls')),
path('users/', views.users, name='users'),
path('add-user/', views.add_new_user, name='add_new_user'),
]
in my tests.py file, I have
import pytest
from django import urls
def test_users_url_resolves_to_users_view(client):
url = urls.reverse('users')
resp = client.get(url)
assert resp.status_code == 200
I get RuntimeError: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it. when i run this.

The error message says you should do either
#pytest.mark.django_db
def test_users_url_resolves_to_users_view(client):
url = urls.reverse('users')
resp = client.get(url)
assert resp.status_code == 200
or
def test_users_url_resolves_to_users_view(client, django_db):
url = urls.reverse('users')
resp = client.get(url)
assert resp.status_code == 200

Related

Django NoReverseMatch at http://127.0.0.1:8000/boards/1/new/

This is my site urls:
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('',include('boards.urls'))
]
And this is my app urls:
urlpatterns = [
path('',views.home,name='home'),
path('boards/<int:pk>',views.board_topic,name='board_topic'),
path('boards/<int:pk>/new/',views.new,name='new_topic')
]
This is the Views for app:
from django.shortcuts import render,get_object_or_404
from django.http import HttpResponse,Http404
from .models import Board
# Create your views here.
def home(request):
board = Board.objects.all()
return render(request,'home.html',{
'board':board,
})
def board_topic(request,pk):
# try:
# board = Board.objects.get(pk=pk)
# except:
# raise Http404
board = get_object_or_404(Board,pk=pk)
return render(request,'topics.html',{
'board':board
})
def new(request,pk):
boards = get_object_or_404(Board, pk=pk)
return render(request, 'new_topic.html', {
'board' : boards
})
when I try to go to http://127.0.0.1:8000/boards/1/new/ then this error occurs:
enter image description here
please help me.
Here's how I was able to get rid of my error
In my app's url:
urlpatterns = [
path('',views.home,name='home'),
path('boards/<int:pk>',views.board_topic,name='board_topic'),
path('boards/<int:pk>/new/',views.new,name='new_topic')
]
In the second path I was using name= 'board_topic'
and in my templates file i was using url as href = ' url "board.pk board_topics" '
so that was why i was getting that error .
THANK YOU TO EVERYONE WHO RESPONDED

I don't understand django's 404 display

I want to move to my 404 page when accessing a URL that is not set.
We are trying to implement it in multiple applications.
I tried a few, but I can't.
Where is the best way to write code?
#setting
DEBUG = False
ALLOWED_HOSTS = ['127.0.0.1']
#project url.py
from django.conf import settings
from django.urls import re_path
from django.views.static import serve
# ... the rest of your URLconf goes here ...
if settings.DEBUG:
urlpatterns += [
re_path(r'^media/(?P<path>.*)$', serve, {
'document_root': settings.MEDIA_ROOT,
}),
]
handler404 = 'person.views.handler404'
handler500 = 'person.views.handler500'
#application view.py
def handler404(request):
response = render_to_response('404.html', {},
context_instance=RequestContext(request))
response.status_code = 404
return response
def handler500(request):
response = render_to_response('500.html', {},
context_instance=RequestContext(request))
response.status_code = 500
return response
Don't use render_to_response, it's obsolete. Use render instead.
def handler404(request):
response = render(request, '404.html', status_code=404)
If your tutorial or book is telling you to write this code, then it's out of date, and you should look for a different resource to learn Django.
In your case, the handlers are not doing anything different to the regular handler. Therefore you should unset handler404 and handler500. The default handlers will use your custom 404.html and 500.html templates as long as they are in the templates directory.

Django: Why does this test fail?

I an new to Django and to Test Driven Devolopment as well.
After working through the tutorials in the 1.11 official documentation
I am starting my first app: wos_2017_2
This test fails and I cannot figure out why:
import unittest
from django.test import TestCase
from django.test import Client
from .models import *
from .views import *
class SimpleTest(unittest.TestCase):
def test_index(self):
client = Client()
response = client.get('/')
self.assertEqual(response.status_code, 200)
FAIL: test_index (wos_2017_2.tests.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/js/django/wos/wos_2017_2/tests.py", line 16, in test_index
self.assertEqual(response.status_code, 200)
AssertionError: 404 != 200
This link in the browser works without a problem:
http://localhost:8000/wos_2017_2/
In the shell (run from the project root):
>>> from django.test import Client
>>> client = Client()
>>> response = client.get('/')
>>> response = client.get('wos_2017_2/index')
Not Found: /wos_2017_2index
>>> response = client.get('wos_2017_2/')
Not Found: /wos_2017_2
>>> response = client.get('/wos_2017_2/')
>>> response = client.get('/wos_2017_2/index/')
Not Found: /wos_2017_2/index/
>>> response = client.get('/wos_2017_2/')
>>> response.status_code
200
in wos_2017_1.urls.py:
from . import views
from django.conf.urls import url
urlpatterns = [
url(r'^$', views.index, name='index'),
]
client.get('/') is failing because you haven't defined a URL pattern for ^$ in your root url config (the one in the same directory as your settings.py).
You have included your urls with:
url(r'^wos_2017_2/', include('wos_2017_2.urls')),
and in that urls you have
url(r'^$', views.index, name='index'),
Therefore in your test you should use response = client.get('/wos_2017_2/')

sitemaps.xml not working in google app engine or local google sdk but it does work running in django 1.9.7 server

In the following image on the left side is the google server and on the right side is the django server:
The google server does not show any logs about it, at first sight, the xml is rendered by the server but it doesn't show the links of the sitemap,
sitemap.py
from django.contrib.sitemaps import Sitemap
from django.core.urlresolvers import reverse
from datetime import datetime
class BasicSitemap(Sitemap):
def __init__(self, names):
self.names = names
def items(self):
return self.names
def changefreq(self, obj):
return 'weekly'
def lastmod(self, obj):
return datetime.now()
def location(self, obj):
return reverse(obj)
urls.py
from django.conf.urls import url, include
from django.contrib import admin
from django.views.generic import TemplateView
from django.shortcuts import render_to_response
from django.template import RequestContext
from sitemap import BasicSitemap
from django.contrib.sitemaps.views import sitemap
sitemaps = {
'pages': BasicSitemap(['about', 'home', 'team', 'contacto', 'courses', 'services'])
}
urlpatterns = [
url(r'^', include('apps.home.urls')),
url(r'^', include('apps.about.urls')),
url(r'^', include('apps.contact.urls')),
url(r'^', include('apps.services.urls')),
url(r'^', include('apps.team.urls')),
url(r'^', include('apps.client.urls')),
url(r'^', include('apps.course.urls')),
url(r'^admin/', admin.site.urls),
url('^robots.txt', TemplateView.as_view(template_name='robots.txt', content_type='text/plain')),
url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap')
]
def handler404(request):
response = render_to_response('404.html', {},
context_instance=RequestContext(request))
response.status_code = 404
return response
def handler500(request):
response = render_to_response('500.html', {},
context_instance=RequestContext(request))
response.status_code = 500
return response
Things I've done:
run the aplication in different os (linux windows)
tried different django versions < 1.9.7
The weird thing about this is that I had a prev version of this site wich was deployed at January this year and it doesn't have that problem, I used logic, but this new app engine seems to work differently.
Any ideas?? a link to the sitemap page

How to test 500.html error page in django development env?

I am using Django for a project and is already in production.
In the production environment 500.html is rendered whenever a server error occurs.
How do I test the rendering of 500.html in dev environment? Or how do I render 500.html in dev, if I turn-off debug I still get the errors and not 500.html
background: I include some page elements based on a page and some are missing when 500.html is called and want to debug it in dev environment.
I prefer not to turn DEBUG off. Instead I put the following snippet in the urls.py:
if settings.DEBUG:
urlpatterns += patterns('',
(r'^500/$', 'your_custom_view_if_you_wrote_one'),
(r'^404/$', 'django.views.generic.simple.direct_to_template', {'template': '404.html'}),
)
In the snippet above, the error page uses a custom view, you can easily replace it with Django's direct_to_template view though.
Now you can test 500 and 404 pages by calling their urls: http://example.com/500 and http://example.com/404
In Django 1.6 django.views.generic.simple.direct_to_template does not exists anymore, these are my settings for special views:
# urls.py
from django.views.generic import TemplateView
from django.views.defaults import page_not_found, server_error
urlpatterns += [
url(r'^400/$', TemplateView.as_view(template_name='400.html')),
url(r'^403/$', TemplateView.as_view(template_name='403.html')),
url(r'^404/$', page_not_found),
url(r'^500/$', server_error),
]
And if you want to use the default Django 500 view instead of your custom view:
if settings.DEBUG:
urlpatterns += patterns('',
(r'^500/$', 'django.views.defaults.server_error'),
(r'^404/$', 'django.views.generic.simple.direct_to_template', {'template': '404.html'}),
)
Continuing shanyu's answer, in Django 1.3+ use:
if settings.DEBUG:
urlpatterns += patterns('',
(r'^500/$', 'django.views.defaults.server_error'),
(r'^404/$', 'django.views.defaults.page_not_found'),
)
For Django > 3.0, just set the raise_request_exception value to False.
from django.test import TestCase
class ViewTestClass(TestCase):
def test_error_page(self):
self.client.raise_request_exception = False
response = self.client.get(reverse('error-page'))
self.assertEqual(response.status_code, 500)
self.assertTrue(
'some text from the custom 500 page'
in response.content.decode('utf8'))
Documentation: https://docs.djangoproject.com/en/3.2/topics/testing/tools/
NOTE: if the error page raises an exception, that will show up as an ERROR in the test log. You can turn the test logging up to CRITICAL by default to suppress that error.
Are both debug settings false?
settings.DEBUG = False
settings.TEMPLATE_DEBUG = False
How i do and test custom error handlers
Define custom View based on TemplateView
# views.py
from django.views.generic import TemplateView
class ErrorHandler(TemplateView):
""" Render error template """
error_code = 404
template_name = 'index/error.html'
def dispatch(self, request, *args, **kwargs):
""" For error on any methods return just GET """
return self.get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['error_code'] = self.error_code
return context
def render_to_response(self, context, **response_kwargs):
""" Return correct status code """
response_kwargs = response_kwargs or {}
response_kwargs.update(status=self.error_code)
return super().render_to_response(context, **response_kwargs)
Tell django to use custom error handlers
# urls.py
from index.views import ErrorHandler
# error handing handlers - fly binding
for code in (400, 403, 404, 500):
vars()['handler{}'.format(code)] = ErrorHandler.as_view(error_code=code)
Testcase for custom error handlers
# tests.py
from unittest import mock
from django.test import TestCase
from django.core.exceptions import SuspiciousOperation, PermissionDenied
from django.http import Http404
from index import views
class ErrorHandlersTestCase(TestCase):
""" Check is correct error handlers work """
def raise_(exception):
def wrapped(*args, **kwargs):
raise exception('Test exception')
return wrapped
def test_index_page(self):
""" Should check is 200 on index page """
response = self.client.get('/')
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'index/index.html')
#mock.patch('index.views.IndexView.get', raise_(Http404))
def test_404_page(self):
""" Should check is 404 page correct """
response = self.client.get('/')
self.assertEqual(response.status_code, 404)
self.assertTemplateUsed(response, 'index/error.html')
self.assertIn('404 Page not found', response.content.decode('utf-8'))
#mock.patch('index.views.IndexView.get', views.ErrorHandler.as_view(error_code=500))
def test_500_page(self):
""" Should check is 500 page correct """
response = self.client.get('/')
self.assertEqual(response.status_code, 500)
self.assertTemplateUsed(response, 'index/error.html')
self.assertIn('500 Server Error', response.content.decode('utf-8'))
#mock.patch('index.views.IndexView.get', raise_(SuspiciousOperation))
def test_400_page(self):
""" Should check is 400 page correct """
response = self.client.get('/')
self.assertEqual(response.status_code, 400)
self.assertTemplateUsed(response, 'index/error.html')
self.assertIn('400 Bad request', response.content.decode('utf-8'))
#mock.patch('index.views.IndexView.get', raise_(PermissionDenied))
def test_403_page(self):
""" Should check is 403 page correct """
response = self.client.get('/')
self.assertEqual(response.status_code, 403)
self.assertTemplateUsed(response, 'index/error.html')
self.assertIn('403 Permission Denied', response.content.decode('utf-8'))
urls.py
handler500 = 'project.apps.core.views.handler500'
handler404 = 'project.apps.core.views.handler404'
views.py
from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponseServerError, HttpResponseNotFound
def handler500(request, template_name='500.html'):
t = get_template(template_name)
ctx = Context({})
return HttpResponseServerError(t.render(ctx))
def handler404(request, template_name='404.html'):
t = get_template(template_name)
ctx = Context({})
return HttpResponseNotFound(t.render(ctx))
tests.py
from django.test import TestCase
from django.test.client import RequestFactory
from project import urls
from ..views import handler404, handler500
class TestErrorPages(TestCase):
def test_error_handlers(self):
self.assertTrue(urls.handler404.endswith('.handler404'))
self.assertTrue(urls.handler500.endswith('.handler500'))
factory = RequestFactory()
request = factory.get('/')
response = handler404(request)
self.assertEqual(response.status_code, 404)
self.assertIn('404 Not Found!!', unicode(response))
response = handler500(request)
self.assertEqual(response.status_code, 500)
self.assertIn('500 Internal Server Error', unicode(response))
Update for Django > 1.6 and without getting
page_not_found() missing 1 required positional argument: 'exception'
Inspired by this answer:
# urls.py
from django.views.defaults import page_not_found, server_error, permission_denied, bad_request
[...]
if settings.DEBUG:
# This allows the error pages to be debugged during development, just visit
# these url in browser to see how these error pages look like.
urlpatterns += [
path('400/', bad_request, kwargs={'exception': Exception('Bad Request!')}),
path('403/', permission_denied, kwargs={'exception': Exception('Permission Denied')}),
path('404/', page_not_found, kwargs={'exception': Exception('Page not Found')}),
path('500/', server_error),
You can simply define the handler404 and handler500 for errors in your main views.py file as detailed in this answer:
https://stackoverflow.com/a/18009660/1913888
This will return the error that you desire when Django routes to that handler. No custom URL configuration is needed to route to a different URL name.
In Django versions < 3.0, you should do as follows:
client.py
from django.core.signals import got_request_exception
from django.template import TemplateDoesNotExist
from django.test import signals
from django.test.client import Client as DjangoClient, store_rendered_templates
from django.urls import resolve
from django.utils import six
from django.utils.functional import SimpleLazyObject, curry
class Client(DjangoClient):
"""Test client that does not raise Exceptions if requested."""
def __init__(self,
enforce_csrf_checks=False,
raise_request_exception=True, **defaults):
super(Client, self).__init__(enforce_csrf_checks=enforce_csrf_checks,
**defaults)
self.raise_request_exception = raise_request_exception
def request(self, **request):
"""
The master request method. Composes the environment dictionary
and passes to the handler, returning the result of the handler.
Assumes defaults for the query environment, which can be overridden
using the arguments to the request.
"""
environ = self._base_environ(**request)
# Curry a data dictionary into an instance of the template renderer
# callback function.
data = {}
on_template_render = curry(store_rendered_templates, data)
signal_uid = "template-render-%s" % id(request)
signals.template_rendered.connect(on_template_render,
dispatch_uid=signal_uid)
# Capture exceptions created by the handler.
exception_uid = "request-exception-%s" % id(request)
got_request_exception.connect(self.store_exc_info,
dispatch_uid=exception_uid)
try:
try:
response = self.handler(environ)
except TemplateDoesNotExist as e:
# If the view raises an exception, Django will attempt to show
# the 500.html template. If that template is not available,
# we should ignore the error in favor of re-raising the
# underlying exception that caused the 500 error. Any other
# template found to be missing during view error handling
# should be reported as-is.
if e.args != ('500.html',):
raise
# Look for a signalled exception, clear the current context
# exception data, then re-raise the signalled exception.
# Also make sure that the signalled exception is cleared from
# the local cache!
response.exc_info = self.exc_info # Patch exception handling
if self.exc_info:
exc_info = self.exc_info
self.exc_info = None
if self.raise_request_exception: # Patch exception handling
six.reraise(*exc_info)
# Save the client and request that stimulated the response.
response.client = self
response.request = request
# Add any rendered template detail to the response.
response.templates = data.get("templates", [])
response.context = data.get("context")
response.json = curry(self._parse_json, response)
# Attach the ResolverMatch instance to the response
response.resolver_match = SimpleLazyObject(
lambda: resolve(request['PATH_INFO'])
)
# Flatten a single context. Not really necessary anymore thanks to
# the __getattr__ flattening in ContextList, but has some edge-case
# backwards-compatibility implications.
if response.context and len(response.context) == 1:
response.context = response.context[0]
# Update persistent cookie data.
if response.cookies:
self.cookies.update(response.cookies)
return response
finally:
signals.template_rendered.disconnect(dispatch_uid=signal_uid)
got_request_exception.disconnect(dispatch_uid=exception_uid)
tests.py
from unittest import mock
from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse
from django.test import TestCase, override_settings
from .client import Client # Important, we use our own Client here!
class TestErrors(TestCase):
"""Test errors."""
#classmethod
def setUpClass(cls):
super(TestErrors, cls).setUpClass()
cls.username = 'admin'
cls.email = 'admin#localhost'
cls.password = 'test1234test1234'
cls.not_found_url = '/i-do-not-exist/'
cls.internal_server_error_url = reverse('password_reset')
def setUp(self):
super(TestErrors, self).setUp()
User = get_user_model()
User.objects.create_user(
self.username,
self.email,
self.password,
is_staff=True,
is_active=True
)
self.client = Client(raise_request_exception=False)
# Mock in order to trigger Exception and resulting Internal server error
#mock.patch('django.contrib.auth.views.PasswordResetView.form_class', None)
#override_settings(DEBUG=False)
def test_errors(self):
self.client.login(username=self.username, password=self.password)
with self.subTest("Not found (404)"):
response = self.client.get(self.not_found_url, follow=True)
self.assertNotIn('^admin/', str(response.content))
with self.subTest("Internal server error (500)"):
response = self.client.get(self.internal_server_error_url,
follow=True)
self.assertNotIn('TypeError', str(response.content))
Starting from Django 3.0 you could skip the custom Client definition and just use the code from tests.py.