Index: django/contrib/flatpages/views.py
===================================================================
--- django/contrib/flatpages/views.py	(revision 6894)
+++ django/contrib/flatpages/views.py	(working copy)
@@ -1,9 +1,9 @@
 from django.contrib.flatpages.models import FlatPage
 from django.template import loader, RequestContext
-from django.shortcuts import get_object_or_404
-from django.http import HttpResponse
+from django.http import HttpResponse, Http404
 from django.conf import settings
 from django.core.xheaders import populate_xheaders
+from django.core.urlresolvers import get_resolver
 from django.utils.safestring import mark_safe
 
 DEFAULT_TEMPLATE = 'flatpages/default.html'
@@ -21,7 +21,16 @@
     """
     if not url.startswith('/'):
         url = "/" + url
-    f = get_object_or_404(FlatPage, url__exact=url, sites__id__exact=settings.SITE_ID)
+    try:
+        f = FlatPage.objects.get(url=url, sites__id=settings.SITE_ID)
+    except FlatPage.DoesNotExist:
+        if url.endswith('/') or not settings.APPEND_SLASH:
+            raise Http404
+        # No matching flat page was found, but url didn't end in a slash and
+        # APPEND_SLASH is on. Append a slash to the url and try to resolve that. 
+        resolver = get_resolver(getattr(request, 'urlconf', None))
+        func, args, kwargs = resolver.resolve('%s/' % url)
+        return func(request, *args, **kwargs)
     # If registration is required for accessing this page, and the user isn't
     # logged in, redirect to the login page.
     if f.registration_required and not request.user.is_authenticated():
Index: django/contrib/flatpages/tests.py
===================================================================
--- django/contrib/flatpages/tests.py	(revision 0)
+++ django/contrib/flatpages/tests.py	(revision 0)
@@ -0,0 +1,112 @@
+"""
+Set up flat pages
+>>> from django.contrib.flatpages.models import FlatPage
+>>> from django.contrib.sites.models import Site
+>>> site = Site.objects.get(pk=1)
+>>> f = FlatPage.objects.create(url='/contact/', title='Contact Us',
+...     content='Contact us at...', enable_comments=False)
+>>> f.sites.add(site)
+>>> f = FlatPage.objects.create(url='/custom/test', title='Custom flatpage',
+...     content='similar to custom view', enable_comments=False,
+...     template_name='custom_flatpage_template.htm')
+>>> f.sites.add(site)
+
+Set up the resolver
+>>> from django.core.urlresolvers import get_resolver, RegexURLResolver
+>>> resolver = RegexURLResolver('^/', 'django.contrib.flatpages.tests')
+>>> from django.http import HttpRequest
+>>> fake_request = HttpRequest()
+>>> fake_request.urlconf = 'django.contrib.flatpages.tests'
+>>> def render(path):
+...     func, args, kwargs = resolver.resolve(path)
+...     return func(fake_request, *args, **kwargs).content
+
+Turn off APPEND_SLASH
+>>> from django.conf import settings
+>>> original_append_slash = settings.APPEND_SLASH
+>>> settings.APPEND_SLASH = False
+
+Use test templates
+>>> from django.contrib.flatpages.tests import TestTemplateLoader
+>>> test_template_loader = TestTemplateLoader()
+
+Test a flat page
+>>> print render('/contact/')
+flatpage: Contact Us -- Contact us at...
+
+Flat pages can specify a custom template_name rather than using the default
+'flatpages/default.html'.
+>>> print render('/custom/test')
+custom flatpage: Custom flatpage -- similar to custom view
+
+If a flat page is not found, Http404 is raised.
+>>> print render('/nonexistant/')
+Traceback (most recent call last):
+  ...
+Http404
+>>> print render('/contact')
+Traceback (most recent call last):
+  ...
+Http404
+
+Turn on APPEND_SLASH
+>>> settings.APPEND_SLASH = True
+
+If a path is requested without a slash and it is caught by the flatpage view,
+if no matching flat page is found (and APPEND_SLASH is True), a slash will be
+added and then resolved again.
+>>> print render('/contact')
+flatpage: Contact Us -- Contact us at...
+>>> print render('/custom/test')
+custom flatpage: Custom flatpage -- similar to custom view
+
+We resolve again rather than just checking for another flat page because there
+may be another view which should catch the path with appended slash.
+>>> print render('/custom/notflatpage')
+notflatpage
+
+Revert APPEND_SLASH and test templates
+>>> settings.APPEND_SLASH = original_append_slash
+>>> test_template_loader.revert()
+"""
+
+from django.conf.urls.defaults import *
+from django.http import HttpResponse
+from django.contrib.flatpages.views import flatpage
+from django.template import loader, TemplateDoesNotExist
+
+def custom_view(request, echo):
+    return HttpResponse(echo)
+
+urlpatterns = patterns('',
+    # A non-flatpage view
+    url('^custom/(?P<echo>\w+)/$', custom_view),
+    # Fall back to using flat pages
+    url('(.*)', flatpage),
+)
+
+class TestTemplateLoader:
+    def __init__(self):
+        self.register(test_template_loader)
+    def register(self, *args):
+        if not hasattr(self, 'old_template_loaders'):
+            old_template_loaders = loader.template_source_loaders
+        loader.template_source_loaders = args
+    def revert(self):
+        if hasattr(self, 'old_template_loaders'):
+            loader.template_source_loaders = self.old_template_loaders
+
+templates = {
+    'flatpages/default.html':
+        'flatpage: {{ flatpage.title }} -- {{ flatpage.content }}',
+    'custom_flatpage_template.htm':
+        'custom flatpage: {{ flatpage.title }} -- {{ flatpage.content }}',
+}
+
+def test_template_loader(template_name, template_dirs=None):
+    "A custom template loader that loads the unit-test templates."
+    try:
+        return (templates[template_name], "test:%s" % template_name)
+    except KeyError:
+        raise TemplateDoesNotExist, template_name
+
