Merge branch 'master' into lookups_3

This commit is contained in:
Anssi Kääriäinen 2014-01-11 13:21:01 +02:00
commit 90e7004ec1
378 changed files with 6075 additions and 4298 deletions

View File

@ -15,7 +15,8 @@ Extensive contribution guidelines are available in the repository at
https://docs.djangoproject.com/en/dev/internals/contributing/
**Warning: pull requests are ignored!** `File a ticket`__ to suggest changes.
**Warning: non-trivial pull requests (anything more than fixing a typo) without
Trac tickets will be closed!** `Please file a ticket`__ to suggest changes.
__ https://code.djangoproject.com/newticket

View File

@ -2,8 +2,8 @@ Django is a high-level Python Web framework that encourages rapid development
and clean, pragmatic design. Thanks for checking it out.
All documentation is in the "docs" directory and online at
http://docs.djangoproject.com/en/dev/. If you're just getting started, here's
how we recommend you read the docs:
https://docs.djangoproject.com/en/stable/. If you're just getting started,
here's how we recommend you read the docs:
* First, read docs/intro/install.txt for instructions on installing Django.
@ -19,11 +19,9 @@ how we recommend you read the docs:
* See docs/README for instructions on building an HTML version of the docs.
Docs are updated rigorously. If you find any problems in the docs, or think they
should be clarified in any way, please take 30 seconds to fill out a ticket
here:
http://code.djangoproject.com/newticket
Docs are updated rigorously. If you find any problems in the docs, or think
they should be clarified in any way, please take 30 seconds to fill out a
ticket here: https://code.djangoproject.com/newticket
To get more help:
@ -31,11 +29,11 @@ To get more help:
there. Read the archives at http://django-irc-logs.com/.
* Join the django-users mailing list, or read the archives, at
http://groups.google.com/group/django-users.
https://groups.google.com/group/django-users.
To contribute to Django:
* Check out http://www.djangoproject.com/community/ for information about
* Check out https://www.djangoproject.com/community/ for information about
getting involved.
To run Django's test suite:

View File

@ -6,3 +6,16 @@ def get_version(*args, **kwargs):
# Only import if it's actually called.
from django.utils.version import get_version
return get_version(*args, **kwargs)
def setup():
"""
Configure the settings (this happens as a side effect of accessing the
first setting), configure logging and populate the app registry.
"""
from django.apps import apps
from django.conf import settings
from django.utils.log import configure_logging
configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
apps.populate(settings.INSTALLED_APPS)

2
django/apps/__init__.py Normal file
View File

@ -0,0 +1,2 @@
from .base import AppConfig # NOQA
from .registry import apps # NOQA

165
django/apps/base.py Normal file
View File

@ -0,0 +1,165 @@
from importlib import import_module
from django.core.exceptions import ImproperlyConfigured
from django.utils.module_loading import module_has_submodule
from django.utils._os import upath
MODELS_MODULE_NAME = 'models'
class AppConfig(object):
"""
Class representing a Django application and its configuration.
"""
def __init__(self, app_name, app_module):
# Full Python path to the application eg. 'django.contrib.admin'.
self.name = app_name
# Root module for the application eg. <module 'django.contrib.admin'
# from 'django/contrib/admin/__init__.pyc'>.
self.module = app_module
# The following attributes could be defined at the class level in a
# subclass, hence the test-and-set pattern.
# Last component of the Python path to the application eg. 'admin'.
# This value must be unique across a Django project.
if not hasattr(self, 'label'):
self.label = app_name.rpartition(".")[2]
# Human-readable name for the application eg. "Admin".
if not hasattr(self, 'verbose_name'):
self.verbose_name = self.label.title()
# Filesystem path to the application directory eg.
# u'/usr/lib/python2.7/dist-packages/django/contrib/admin'. May be
# None if the application isn't a bona fide package eg. if it's an
# egg. Otherwise it's a unicode on Python 2 and a str on Python 3.
if not hasattr(self, 'path'):
try:
self.path = upath(app_module.__path__[0])
except AttributeError:
self.path = None
# Module containing models eg. <module 'django.contrib.admin.models'
# from 'django/contrib/admin/models.pyc'>. Set by import_models().
# None if the application doesn't have a models module.
self.models_module = None
# Mapping of lower case model names to model classes. Initally set to
# None to prevent accidental access before import_models() runs.
self.models = None
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, self.label)
@classmethod
def create(cls, entry):
"""
Factory that creates an app config from an entry in INSTALLED_APPS.
"""
try:
# If import_module succeeds, entry is a path to an app module.
# Otherwise, entry is a path to an app config class or an error.
module = import_module(entry)
except ImportError:
# Avoid django.utils.module_loading.import_by_path because it
# masks errors -- it reraises ImportError as ImproperlyConfigured.
mod_path, _, cls_name = entry.rpartition('.')
# Raise the original exception when entry cannot be a path to an
# app config class.
if not mod_path:
raise
mod = import_module(mod_path)
try:
cls = getattr(mod, cls_name)
except AttributeError:
# Emulate the error that "from <mod_path> import <cls_name>"
# would raise when <mod_path> exists but not <cls_name>, with
# more context (Python just says "cannot import name ...").
raise ImportError(
"cannot import name '%s' from '%s'" % (cls_name, mod_path))
# Check for obvious errors. (This check prevents duck typing, but
# it could be removed if it became a problem in practice.)
if not issubclass(cls, AppConfig):
raise ImproperlyConfigured(
"'%s' isn't a subclass of AppConfig." % entry)
# Obtain app name here rather than in AppClass.__init__ to keep
# all error checking for entries in INSTALLED_APPS in one place.
try:
app_name = cls.name
except AttributeError:
raise ImproperlyConfigured(
"'%s' must supply a name attribute." % entry)
# Ensure app_names points to a valid module.
app_module = import_module(app_name)
# Entry is a path to an app config class.
return cls(app_name, app_module)
else:
# Entry is a path to an app module.
return cls(entry, module)
def get_model(self, model_name):
"""
Returns the model with the given case-insensitive model_name.
Raises LookupError if no model exists with this name.
"""
if self.models is None:
raise LookupError(
"App '%s' doesn't have any models." % self.label)
try:
return self.models[model_name.lower()]
except KeyError:
raise LookupError(
"App '%s' doesn't have a '%s' model." % (self.label, model_name))
def get_models(self, include_auto_created=False,
include_deferred=False, include_swapped=False):
"""
Returns an iterable of models.
By default, the following models aren't included:
- auto-created models for many-to-many relations without
an explicit intermediate table,
- models created to satisfy deferred attribute queries,
- models that have been swapped out.
Set the corresponding keyword argument to True to include such models.
Keyword arguments aren't documented; they're a private API.
"""
for model in self.models.values():
if model._deferred and not include_deferred:
continue
if model._meta.auto_created and not include_auto_created:
continue
if model._meta.swapped and not include_swapped:
continue
yield model
def import_models(self, all_models):
# Dictionary of models for this app, primarily maintained in the
# 'all_models' attribute of the Apps this AppConfig is attached to.
# Injected as a parameter because it gets populated when models are
# imported, which might happen before populate() imports models.
self.models = all_models
if module_has_submodule(self.module, MODELS_MODULE_NAME):
models_module_name = '%s.%s' % (self.name, MODELS_MODULE_NAME)
self.models_module = import_module(models_module_name)
def ready(self):
"""
Override this method in subclasses to run code when Django starts.
"""

413
django/apps/registry.py Normal file
View File

@ -0,0 +1,413 @@
from collections import Counter, defaultdict, OrderedDict
import os
import sys
import warnings
from django.core.exceptions import ImproperlyConfigured
from django.utils import lru_cache
from django.utils.module_loading import import_lock
from django.utils._os import upath
from .base import AppConfig
class Apps(object):
"""
A registry that stores the configuration of installed applications.
It also keeps track of models eg. to provide reverse-relations.
"""
def __init__(self, installed_apps=()):
# installed_apps is set to None when creating the master registry
# because it cannot be populated at that point. Other registries must
# provide a list of installed apps and are populated immediately.
if installed_apps is None and hasattr(sys.modules[__name__], 'apps'):
raise RuntimeError("You must supply an installed_apps argument.")
# Mapping of app labels => model names => model classes. Every time a
# model is imported, ModelBase.__new__ calls apps.register_model which
# creates an entry in all_models. All imported models are registered,
# regardless of whether they're defined in an installed application
# and whether the registry has been populated. Since it isn't possible
# to reimport a module safely (it could reexecute initialization code)
# all_models is never overridden or reset.
self.all_models = defaultdict(OrderedDict)
# Mapping of labels to AppConfig instances for installed apps.
self.app_configs = OrderedDict()
# Stack of app_configs. Used to store the current state in
# set_available_apps and set_installed_apps.
self.stored_app_configs = []
# Whether the registry is populated.
self.ready = False
# Pending lookups for lazy relations.
self._pending_lookups = {}
# Populate apps and models, unless it's the master registry.
if installed_apps is not None:
self.populate(installed_apps)
def populate(self, installed_apps=None):
"""
Loads application configurations and models.
This method imports each application module and then each model module.
It is thread safe and idempotent, but not reentrant.
"""
if self.ready:
return
# Since populate() may be a side effect of imports, and since it will
# itself import modules, an ABBA deadlock between threads would be
# possible if we didn't take the import lock. See #18251.
with import_lock():
if self.ready:
return
# app_config should be pristine, otherwise the code below won't
# guarantee that the order matches the order in INSTALLED_APPS.
if self.app_configs:
raise RuntimeError("populate() isn't reentrant")
# Load app configs and app modules.
for entry in installed_apps:
if isinstance(entry, AppConfig):
app_config = entry
else:
app_config = AppConfig.create(entry)
if app_config.label in self.app_configs:
raise ImproperlyConfigured(
"Application labels aren't unique, "
"duplicates: %s" % app_config.label)
self.app_configs[app_config.label] = app_config
# Check for duplicate app names.
counts = Counter(
app_config.name for app_config in self.app_configs.values())
duplicates = [
name for name, count in counts.most_common() if count > 1]
if duplicates:
raise ImproperlyConfigured(
"Application names aren't unique, "
"duplicates: %s" % ", ".join(duplicates))
# Load models.
for app_config in self.app_configs.values():
all_models = self.all_models[app_config.label]
app_config.import_models(all_models)
self.clear_cache()
self.ready = True
for app_config in self.get_app_configs():
app_config.ready()
def check_ready(self):
"""
Raises an exception if the registry isn't ready.
"""
if not self.ready:
raise RuntimeError("App registry isn't ready yet.")
def get_app_configs(self):
"""
Imports applications and returns an iterable of app configs.
"""
self.check_ready()
return self.app_configs.values()
def get_app_config(self, app_label):
"""
Imports applications and returns an app config for the given label.
Raises LookupError if no application exists with this label.
"""
self.check_ready()
try:
return self.app_configs[app_label]
except KeyError:
raise LookupError("No installed app with label '%s'." % app_label)
# This method is performance-critical at least for Django's test suite.
@lru_cache.lru_cache(maxsize=None)
def get_models(self, app_mod=None, include_auto_created=False,
include_deferred=False, include_swapped=False):
"""
Returns a list of all installed models.
By default, the following models aren't included:
- auto-created models for many-to-many relations without
an explicit intermediate table,
- models created to satisfy deferred attribute queries,
- models that have been swapped out.
Set the corresponding keyword argument to True to include such models.
"""
self.check_ready()
if app_mod:
warnings.warn(
"The app_mod argument of get_models is deprecated.",
PendingDeprecationWarning, stacklevel=2)
app_label = app_mod.__name__.split('.')[-2]
try:
return list(self.get_app_config(app_label).get_models(
include_auto_created, include_deferred, include_swapped))
except LookupError:
return []
result = []
for app_config in self.app_configs.values():
result.extend(list(app_config.get_models(
include_auto_created, include_deferred, include_swapped)))
return result
def get_model(self, app_label, model_name):
"""
Returns the model matching the given app_label and model_name.
model_name is case-insensitive.
Raises LookupError if no application exists with this label, or no
model exists with this name in the application.
"""
self.check_ready()
return self.get_app_config(app_label).get_model(model_name.lower())
def register_model(self, app_label, model):
# Since this method is called when models are imported, it cannot
# perform imports because of the risk of import loops. It mustn't
# call get_app_config().
model_name = model._meta.model_name
app_models = self.all_models[app_label]
if model_name in app_models:
raise RuntimeError(
"Conflicting '%s' models in application '%s': %s and %s." %
(model_name, app_label, app_models[model_name], model))
app_models[model_name] = model
self.clear_cache()
def is_installed(self, app_name):
"""
Checks whether an application with this name exists in the registry.
app_name is the full name of the app eg. 'django.contrib.admin'.
It's safe to call this method at import time, even while the registry
is being populated. It returns False for apps that aren't loaded yet.
"""
app_config = self.app_configs.get(app_name.rpartition(".")[2])
return app_config is not None and app_config.name == app_name
def get_containing_app_config(self, object_name):
"""
Look for an app config containing a given object.
object_name is the dotted Python path to the object.
Returns the app config for the inner application in case of nesting.
Returns None if the object isn't in any registered app config.
It's safe to call this method at import time, even while the registry
is being populated.
"""
candidates = []
for app_config in self.app_configs.values():
if object_name.startswith(app_config.name):
subpath = object_name[len(app_config.name):]
if subpath == '' or subpath[0] == '.':
candidates.append(app_config)
if candidates:
return sorted(candidates, key=lambda ac: -len(ac.name))[0]
def get_registered_model(self, app_label, model_name):
"""
Similar to get_model(), but doesn't require that an app exists with
the given app_label.
It's safe to call this method at import time, even while the registry
is being populated.
"""
model = self.all_models[app_label].get(model_name.lower())
if model is None:
raise LookupError(
"Model '%s.%s' not registered." % (app_label, model_name))
return model
def set_available_apps(self, available):
"""
Restricts the set of installed apps used by get_app_config[s].
available must be an iterable of application names.
set_available_apps() must be balanced with unset_available_apps().
Primarily used for performance optimization in TransactionTestCase.
This method is safe is the sense that it doesn't trigger any imports.
"""
available = set(available)
installed = set(app_config.name for app_config in self.get_app_configs())
if not available.issubset(installed):
raise ValueError("Available apps isn't a subset of installed "
"apps, extra apps: %s" % ", ".join(available - installed))
self.stored_app_configs.append(self.app_configs)
self.app_configs = OrderedDict(
(label, app_config)
for label, app_config in self.app_configs.items()
if app_config.name in available)
self.clear_cache()
def unset_available_apps(self):
"""
Cancels a previous call to set_available_apps().
"""
self.app_configs = self.stored_app_configs.pop()
self.clear_cache()
def set_installed_apps(self, installed):
"""
Enables a different set of installed apps for get_app_config[s].
installed must be an iterable in the same format as INSTALLED_APPS.
set_installed_apps() must be balanced with unset_installed_apps(),
even if it exits with an exception.
Primarily used as a receiver of the setting_changed signal in tests.
This method may trigger new imports, which may add new models to the
registry of all imported models. They will stay in the registry even
after unset_installed_apps(). Since it isn't possible to replay
imports safely (eg. that could lead to registering listeners twice),
models are registered when they're imported and never removed.
"""
self.check_ready()
self.stored_app_configs.append(self.app_configs)
self.app_configs = OrderedDict()
self.ready = False
self.clear_cache()
self.populate(installed)
def unset_installed_apps(self):
"""
Cancels a previous call to set_installed_apps().
"""
self.app_configs = self.stored_app_configs.pop()
self.ready = True
self.clear_cache()
def clear_cache(self):
"""
Clears all internal caches, for methods that alter the app registry.
This is mostly used in tests.
"""
self.get_models.cache_clear()
### DEPRECATED METHODS GO BELOW THIS LINE ###
def load_app(self, app_name):
"""
Loads the app with the provided fully qualified name, and returns the
model module.
"""
warnings.warn(
"load_app(app_name) is deprecated.",
PendingDeprecationWarning, stacklevel=2)
app_config = AppConfig.create(app_name)
app_config.import_models(self.all_models[app_config.label])
self.app_configs[app_config.label] = app_config
self.clear_cache()
return app_config.models_module
def app_cache_ready(self):
warnings.warn(
"app_cache_ready() is deprecated in favor of the ready property.",
PendingDeprecationWarning, stacklevel=2)
return self.ready
def get_app(self, app_label):
"""
Returns the module containing the models for the given app_label.
"""
warnings.warn(
"get_app_config(app_label).models_module supersedes get_app(app_label).",
PendingDeprecationWarning, stacklevel=2)
try:
models_module = self.get_app_config(app_label).models_module
except LookupError as exc:
# Change the exception type for backwards compatibility.
raise ImproperlyConfigured(*exc.args)
if models_module is None:
raise ImproperlyConfigured(
"App '%s' doesn't have a models module." % app_label)
return models_module
def get_apps(self):
"""
Returns a list of all installed modules that contain models.
"""
warnings.warn(
"[a.models_module for a in get_app_configs()] supersedes get_apps().",
PendingDeprecationWarning, stacklevel=2)
app_configs = self.get_app_configs()
return [app_config.models_module for app_config in app_configs
if app_config.models_module is not None]
def _get_app_package(self, app):
return '.'.join(app.__name__.split('.')[:-1])
def get_app_package(self, app_label):
warnings.warn(
"get_app_config(label).name supersedes get_app_package(label).",
PendingDeprecationWarning, stacklevel=2)
return self._get_app_package(self.get_app(app_label))
def _get_app_path(self, app):
if hasattr(app, '__path__'): # models/__init__.py package
app_path = app.__path__[0]
else: # models.py module
app_path = app.__file__
return os.path.dirname(upath(app_path))
def get_app_path(self, app_label):
warnings.warn(
"get_app_config(label).path supersedes get_app_path(label).",
PendingDeprecationWarning, stacklevel=2)
return self._get_app_path(self.get_app(app_label))
def get_app_paths(self):
"""
Returns a list of paths to all installed apps.
Useful for discovering files at conventional locations inside apps
(static files, templates, etc.)
"""
warnings.warn(
"[a.path for a in get_app_configs()] supersedes get_app_paths().",
PendingDeprecationWarning, stacklevel=2)
self.check_ready()
app_paths = []
for app in self.get_apps():
app_paths.append(self._get_app_path(app))
return app_paths
def register_models(self, app_label, *models):
"""
Register a set of models as belonging to an app.
"""
warnings.warn(
"register_models(app_label, *models) is deprecated.",
PendingDeprecationWarning, stacklevel=2)
for model in models:
self.register_model(app_label, model)
apps = Apps(installed_apps=None)

View File

@ -7,16 +7,12 @@ a list of all possible variables.
"""
import importlib
import logging
import os
import sys
import time # Needed for Windows
import warnings
from django.conf import global_settings
from django.core.exceptions import ImproperlyConfigured
from django.utils.functional import LazyObject, empty
from django.utils.module_loading import import_by_path
from django.utils import six
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
@ -44,34 +40,12 @@ class LazySettings(LazyObject):
% (desc, ENVIRONMENT_VARIABLE))
self._wrapped = Settings(settings_module)
self._configure_logging()
def __getattr__(self, name):
if self._wrapped is empty:
self._setup(name)
return getattr(self._wrapped, name)
def _configure_logging(self):
"""
Setup logging from LOGGING_CONFIG and LOGGING settings.
"""
if not sys.warnoptions:
# Route warnings through python logging
logging.captureWarnings(True)
# Allow DeprecationWarnings through the warnings filters
warnings.simplefilter("default", DeprecationWarning)
if self.LOGGING_CONFIG:
from django.utils.log import DEFAULT_LOGGING
# First find the logging configuration function ...
logging_config_func = import_by_path(self.LOGGING_CONFIG)
logging_config_func(DEFAULT_LOGGING)
# ... then invoke it with the logging settings
if self.LOGGING:
logging_config_func(self.LOGGING)
def configure(self, default_settings=global_settings, **options):
"""
Called to manually configure the settings. The 'default_settings'
@ -84,7 +58,6 @@ class LazySettings(LazyObject):
for name, value in options.items():
setattr(holder, name, value)
self._wrapped = holder
self._configure_logging()
@property
def configured(self):
@ -104,11 +77,6 @@ class BaseSettings(object):
elif name == "ALLOWED_INCLUDE_ROOTS" and isinstance(value, six.string_types):
raise ValueError("The ALLOWED_INCLUDE_ROOTS setting must be set "
"to a tuple, not a string.")
elif name == "INSTALLED_APPS":
value = list(value) # force evaluation of generators on Python 3
if len(value) != len(set(value)):
raise ImproperlyConfigured("The INSTALLED_APPS setting must contain unique values.")
object.__setattr__(self, name, value)

View File

@ -290,7 +290,7 @@ MEDIA_URL = ''
# Absolute path to the directory static files should be collected to.
# Example: "/var/www/example.com/static/"
STATIC_ROOT = ''
STATIC_ROOT = None
# URL that handles the static files served from STATIC_ROOT.
# Example: "http://example.com/static/", "http://static.example.com/"

View File

@ -71,7 +71,6 @@ def delete_selected(modeladmin, request, queryset):
"perms_lacking": perms_needed,
"protected": protected,
"opts": opts,
"app_label": app_label,
'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
}

View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class AdminConfig(AppConfig):
name = 'django.contrib.admin'
verbose_name = _("administration")

View File

@ -46,9 +46,12 @@ from django.views.decorators.csrf import csrf_protect
IS_POPUP_VAR = '_popup'
TO_FIELD_VAR = '_to_field'
HORIZONTAL, VERTICAL = 1, 2
# returns the <ul> class for a given radio_admin field
get_ul_class = lambda x: 'radiolist%s' % (' inline' if x == HORIZONTAL else '')
def get_ul_class(radio_style):
return 'radiolist' if radio_style == VERTICAL else 'radiolist inline'
class IncorrectLookupParameters(Exception):
@ -1308,7 +1311,6 @@ class ModelAdmin(BaseModelAdmin):
media=media,
inline_admin_formsets=inline_admin_formsets,
errors=helpers.AdminErrorList(form, formsets),
app_label=opts.app_label,
preserved_filters=self.get_preserved_filters(request),
)
context.update(extra_context or {})
@ -1532,7 +1534,6 @@ class ModelAdmin(BaseModelAdmin):
media=media,
has_add_permission=self.has_add_permission(request),
opts=cl.opts,
app_label=app_label,
action_form=action_form,
actions_on_top=self.actions_on_top,
actions_on_bottom=self.actions_on_bottom,
@ -1627,7 +1628,6 @@ class ModelAdmin(BaseModelAdmin):
action_list=action_list,
module_name=capfirst(force_text(opts.verbose_name_plural)),
object=obj,
app_label=app_label,
opts=opts,
preserved_filters=self.get_preserved_filters(request),
)

View File

@ -6,6 +6,7 @@ from django.contrib.auth import logout as auth_logout, REDIRECT_FIELD_NAME
from django.contrib.contenttypes import views as contenttype_views
from django.views.decorators.csrf import csrf_protect
from django.db.models.base import ModelBase
from django.apps import apps
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from django.core.urlresolvers import reverse, NoReverseMatch
from django.template.response import TemplateResponse
@ -156,20 +157,16 @@ class AdminSite(object):
"""
Check that all things needed to run the admin have been correctly installed.
The default implementation checks that LogEntry, ContentType and the
auth context processor are installed.
The default implementation checks that admin and contenttypes apps are
installed, as well as the auth context processor.
"""
from django.contrib.admin.models import LogEntry
from django.contrib.contenttypes.models import ContentType
if not LogEntry._meta.installed:
if not apps.is_installed('django.contrib.admin'):
raise ImproperlyConfigured("Put 'django.contrib.admin' in your "
"INSTALLED_APPS setting in order to use the admin application.")
if not ContentType._meta.installed:
if not apps.is_installed('django.contrib.contenttypes'):
raise ImproperlyConfigured("Put 'django.contrib.contenttypes' in "
"your INSTALLED_APPS setting in order to use the admin application.")
if not ('django.contrib.auth.context_processors.auth' in settings.TEMPLATE_CONTEXT_PROCESSORS or
'django.core.context_processors.auth' in settings.TEMPLATE_CONTEXT_PROCESSORS):
if 'django.contrib.auth.context_processors.auth' not in settings.TEMPLATE_CONTEXT_PROCESSORS:
raise ImproperlyConfigured("Put 'django.contrib.auth.context_processors.auth' "
"in your TEMPLATE_CONTEXT_PROCESSORS setting in order to use the admin application.")
@ -383,7 +380,7 @@ class AdminSite(object):
app_dict[app_label]['models'].append(model_dict)
else:
app_dict[app_label] = {
'name': app_label.title(),
'name': apps.get_app_config(app_label).verbose_name,
'app_label': app_label,
'app_url': reverse('admin:app_list', kwargs={'app_label': app_label}, current_app=self.name),
'has_module_perms': has_module_perms,
@ -392,7 +389,7 @@ class AdminSite(object):
# Sort the apps alphabetically.
app_list = list(six.itervalues(app_dict))
app_list.sort(key=lambda x: x['name'])
app_list.sort(key=lambda x: x['name'].lower())
# Sort the models alphabetically within each app.
for app in app_list:
@ -410,6 +407,7 @@ class AdminSite(object):
def app_index(self, request, app_label, extra_context=None):
user = request.user
app_name = apps.get_app_config(app_label).verbose_name
has_module_perms = user.has_module_perms(app_label)
if not has_module_perms:
raise PermissionDenied
@ -444,7 +442,7 @@ class AdminSite(object):
# something to display, add in the necessary meta
# information.
app_dict = {
'name': app_label.title(),
'name': app_name,
'app_label': app_label,
'app_url': '',
'has_module_perms': has_module_perms,
@ -455,7 +453,7 @@ class AdminSite(object):
# Sort the models alphabetically within each app.
app_dict['models'].sort(key=lambda x: x['name'])
context = dict(self.each_context(),
title=_('%s administration') % capfirst(app_label),
title=_('%(app)s administration') % {'app': app_name},
app_list=[app_dict],
app_label=app_label,
)

View File

@ -6,12 +6,12 @@
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
{% endblock %}
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />{% endblock %}
{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %}
{% block bodyclass %}{{ opts.app_label }}-{{ opts.model_name }} change-form{% endblock %}
{% if not is_popup %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_label|capfirst|escape }}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'change' original.pk|admin_urlquote %}">{{ original|truncatewords:"18" }}</a>
&rsaquo; {% trans 'Change password' %}

View File

@ -10,13 +10,13 @@
{% block coltype %}colM{% endblock %}
{% block bodyclass %}app-{{ opts.app_label }} model-{{ opts.object_name.lower }} change-form{% endblock %}
{% block bodyclass %}app-{{ opts.app_label }} model-{{ opts.model_name }} change-form{% endblock %}
{% if not is_popup %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ app_label|capfirst|escape }}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
&rsaquo; {% if has_change_permission %}<a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %}
&rsaquo; {% if add %}{% trans 'Add' %} {{ opts.verbose_name }}{% else %}{{ original|truncatewords:"18" }}{% endif %}
</div>

View File

@ -32,13 +32,13 @@
{% endif %}{% endif %}
{% endblock %}
{% block bodyclass %}app-{{ opts.app_label }} model-{{ opts.object_name.lower }} change-list{% endblock %}
{% block bodyclass %}app-{{ opts.app_label }} model-{{ opts.model_name }} change-list{% endblock %}
{% if not is_popup %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=cl.opts.app_label %}">{{ app_label|capfirst|escape }}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=cl.opts.app_label %}">{{ cl.opts.app_config.verbose_name }}</a>
&rsaquo; {{ cl.opts.verbose_name_plural|capfirst }}
</div>
{% endblock %}

View File

@ -1,12 +1,12 @@
{% extends "admin/base_site.html" %}
{% load i18n admin_urls %}
{% block bodyclass %}app-{{ opts.app_label }} model-{{ opts.object_name.lower }} delete-confirmation{% endblock %}
{% block bodyclass %}app-{{ opts.app_label }} model-{{ opts.model_name }} delete-confirmation{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ app_label|capfirst }}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst|escape }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'change' object.pk|admin_urlquote %}">{{ object|truncatewords:"18" }}</a>
&rsaquo; {% trans 'Delete' %}

View File

@ -1,12 +1,12 @@
{% extends "admin/base_site.html" %}
{% load i18n l10n admin_urls %}
{% block bodyclass %}app-{{ opts.app_label }} model-{{ opts.object_name.lower }} delete-confirmation delete-selected-confirmation{% endblock %}
{% block bodyclass %}app-{{ opts.app_label }} model-{{ opts.model_name }} delete-confirmation delete-selected-confirmation{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=app_label %}">{{ app_label|capfirst|escape }}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
&rsaquo; {% trans 'Delete multiple objects' %}
</div>

View File

@ -4,7 +4,7 @@
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=app_label %}">{{ app_label|capfirst|escape }}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}">{{ module_name }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'change' object.pk|admin_urlquote %}">{{ object|truncatewords:"18" }}</a>
&rsaquo; {% trans 'History' %}

View File

@ -333,7 +333,7 @@ def date_hierarchy(cl):
month_lookup = cl.params.get(month_field)
day_lookup = cl.params.get(day_field)
link = lambda d: cl.get_query_string(d, [field_generic])
link = lambda filters: cl.get_query_string(filters, [field_generic])
if not (year_lookup or month_lookup or day_lookup):
# select appropriate start level

View File

@ -1,9 +1,9 @@
from django.conf import settings
from django.apps import apps
from django.template import Library
register = Library()
if 'django.contrib.staticfiles' in settings.INSTALLED_APPS:
if apps.is_installed('django.contrib.staticfiles'):
from django.contrib.staticfiles.templatetags.staticfiles import static
else:
from django.templatetags.static import static

View File

@ -32,7 +32,6 @@ class AdminSeleniumWebDriverTestCase(StaticLiveServerCase):
@classmethod
def _tearDownClassInternal(cls):
if hasattr(cls, 'selenium'):
cls.selenium.refresh() # see ticket #21227
cls.selenium.quit()
super(AdminSeleniumWebDriverTestCase, cls)._tearDownClassInternal()
@ -51,8 +50,40 @@ class AdminSeleniumWebDriverTestCase(StaticLiveServerCase):
Helper function that blocks until the element with the given tag name
is found on the page.
"""
self.wait_for(tag_name, timeout)
def wait_for(self, css_selector, timeout=10):
"""
Helper function that blocks until an css selector is found on the page.
"""
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec
self.wait_until(
lambda driver: driver.find_element_by_tag_name(tag_name),
ec.presence_of_element_located((By.CSS_SELECTOR, css_selector)),
timeout
)
def wait_for_text(self, css_selector, text, timeout=10):
"""
Helper function that blocks until the text is found in the css selector.
"""
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec
self.wait_until(
ec.text_to_be_present_in_element(
(By.CSS_SELECTOR, css_selector), text),
timeout
)
def wait_for_value(self, css_selector, text, timeout=10):
"""
Helper function that blocks until the value is found in the css selector.
"""
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec
self.wait_until(
ec.text_to_be_present_in_element_value(
(By.CSS_SELECTOR, css_selector), text),
timeout
)

View File

@ -1,4 +1,3 @@
from django.core.apps import app_cache
from django.core.exceptions import ImproperlyConfigured
from django.db import models
from django.db.models.fields import FieldDoesNotExist
@ -15,10 +14,6 @@ __all__ = ['BaseValidator', 'InlineValidator']
class BaseValidator(object):
def __init__(self):
# Before we can introspect models, they need the app cache to be fully
# loaded so that inter-relations are set up correctly.
app_cache.populate()
def validate(self, cls, model):
for m in dir(self):

View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class AdminDocsConfig(AppConfig):
name = 'django.contrib.admindocs'
verbose_name = _("administrative documentation")

View File

@ -27,7 +27,7 @@
<table class="xfull">
{% for model in group.list %}
<tr>
<th><a href="{% url 'django-admindocs-models-detail' app_label=model.app_label model_name=model.object_name.lower %}">{{ model.object_name }}</a></th>
<th><a href="{% url 'django-admindocs-models-detail' app_label=model.app_label model_name=model.model_name %}">{{ model.object_name }}</a></th>
</tr>
{% endfor %}
</table>

View File

@ -5,10 +5,10 @@ import re
import warnings
from django import template
from django.apps import apps
from django.conf import settings
from django.contrib import admin
from django.contrib.admin.views.decorators import staff_member_required
from django.core.apps import app_cache
from django.db import models
from django.core.exceptions import ViewDoesNotExist
from django.http import Http404
@ -174,7 +174,7 @@ class ModelIndexView(BaseAdminDocsView):
template_name = 'admin_doc/model_index.html'
def get_context_data(self, **kwargs):
m_list = [m._meta for m in app_cache.get_models()]
m_list = [m._meta for m in apps.get_models()]
kwargs.update({'models': m_list})
return super(ModelIndexView, self).get_context_data(**kwargs)
@ -185,11 +185,12 @@ class ModelDetailView(BaseAdminDocsView):
def get_context_data(self, **kwargs):
# Get the model class.
try:
app_cache.get_app_config(self.kwargs['app_label'])
apps.get_app_config(self.kwargs['app_label'])
except LookupError:
raise Http404(_("App %(app_label)r not found") % self.kwargs)
model = app_cache.get_model(self.kwargs['app_label'], self.kwargs['model_name'])
if model is None:
try:
model = apps.get_model(self.kwargs['app_label'], self.kwargs['model_name'])
except LookupError:
raise Http404(_("Model %(model_name)r not found in app %(app_label)r") % self.kwargs)
opts = model._meta

View File

@ -123,14 +123,15 @@ def get_user_model():
"""
Returns the User model that is active in this project.
"""
from django.core.apps import app_cache
from django.apps import apps
try:
app_label, model_name = settings.AUTH_USER_MODEL.split('.')
except ValueError:
raise ImproperlyConfigured("AUTH_USER_MODEL must be of the form 'app_label.model_name'")
user_model = app_cache.get_model(app_label, model_name)
if user_model is None:
try:
user_model = apps.get_model(app_label, model_name)
except LookupError:
raise ImproperlyConfigured("AUTH_USER_MODEL refers to model '%s' that has not been installed" % settings.AUTH_USER_MODEL)
return user_model

View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class AuthConfig(AppConfig):
name = 'django.contrib.auth'
verbose_name = _("authentication and authorization")

View File

@ -21,7 +21,11 @@ from django.contrib.sites.models import get_current_site
UNMASKED_DIGITS_TO_SHOW = 6
mask_password = lambda p: "%s%s" % (p[:UNMASKED_DIGITS_TO_SHOW], "*" * max(len(p) - UNMASKED_DIGITS_TO_SHOW, 0))
def mask_password(password):
shown = password[:UNMASKED_DIGITS_TO_SHOW]
masked = "*" * max(len(password) - UNMASKED_DIGITS_TO_SHOW, 0)
return shown + masked
class ReadOnlyPasswordHashWidget(forms.Widget):

View File

@ -6,9 +6,9 @@ from __future__ import unicode_literals
import getpass
import unicodedata
from django.apps import apps
from django.contrib.auth import (models as auth_app, get_permission_codename,
get_user_model)
from django.core.apps import app_cache, UnavailableApp
from django.core import exceptions
from django.core.management.base import CommandError
from django.db import DEFAULT_DB_ALIAS, router
@ -60,25 +60,26 @@ def _check_permission_clashing(custom, builtin, ctype):
pool.add(codename)
def create_permissions(app, created_models, verbosity, db=DEFAULT_DB_ALIAS, **kwargs):
try:
app_cache.get_model('auth', 'Permission')
except UnavailableApp:
def create_permissions(app_config, verbosity=2, interactive=True, db=DEFAULT_DB_ALIAS, **kwargs):
if not app_config.models_module:
return
if not router.allow_migrate(db, auth_app.Permission):
try:
Permission = apps.get_model('auth', 'Permission')
except LookupError:
return
if not router.allow_migrate(db, Permission):
return
from django.contrib.contenttypes.models import ContentType
app_models = app_cache.get_models(app)
# This will hold the permissions we're looking for as
# (content_type, (codename, name))
searched_perms = list()
# The codenames and ctypes that should exist.
ctypes = set()
for klass in app_models:
for klass in app_config.get_models():
# Force looking up the content types in the current database
# before creating foreign keys to them.
ctype = ContentType.objects.db_manager(db).get_for_model(klass)
@ -89,20 +90,20 @@ def create_permissions(app, created_models, verbosity, db=DEFAULT_DB_ALIAS, **kw
# Find all the Permissions that have a content_type for a model we're
# looking for. We don't need to check for codenames since we already have
# a list of the ones we're going to create.
all_perms = set(auth_app.Permission.objects.using(db).filter(
all_perms = set(Permission.objects.using(db).filter(
content_type__in=ctypes,
).values_list(
"content_type", "codename"
))
perms = [
auth_app.Permission(codename=codename, name=name, content_type=ctype)
Permission(codename=codename, name=name, content_type=ctype)
for ctype, (codename, name) in searched_perms
if (ctype.pk, codename) not in all_perms
]
# Validate the permissions before bulk_creation to avoid cryptic
# database error when the verbose_name is longer than 50 characters
permission_name_max_length = auth_app.Permission._meta.get_field('name').max_length
permission_name_max_length = Permission._meta.get_field('name').max_length
verbose_name_max_length = permission_name_max_length - 11 # len('Can change ') prefix
for perm in perms:
if len(perm.name) > permission_name_max_length:
@ -112,23 +113,24 @@ def create_permissions(app, created_models, verbosity, db=DEFAULT_DB_ALIAS, **kw
verbose_name_max_length,
)
)
auth_app.Permission.objects.using(db).bulk_create(perms)
Permission.objects.using(db).bulk_create(perms)
if verbosity >= 2:
for perm in perms:
print("Adding permission '%s'" % perm)
def create_superuser(app, created_models, verbosity, db, **kwargs):
def create_superuser(app_config, verbosity=2, interactive=True, db=DEFAULT_DB_ALIAS, **kwargs):
try:
app_cache.get_model('auth', 'Permission')
UserModel = get_user_model()
except UnavailableApp:
apps.get_model('auth', 'Permission')
except LookupError:
return
UserModel = get_user_model()
from django.core.management import call_command
if UserModel in created_models and kwargs.get('interactive', True):
msg = ("\nYou just installed Django's auth system, which means you "
if not UserModel.objects.exists() and interactive:
msg = ("\nYou have installed Django's auth system, and "
"don't have any superusers defined.\nWould you like to create one "
"now? (yes/no): ")
confirm = input(msg)
@ -202,7 +204,9 @@ def get_default_username(check_db=True):
return ''
return default_username
signals.post_migrate.connect(create_permissions,
dispatch_uid="django.contrib.auth.management.create_permissions")
signals.post_migrate.connect(create_superuser,
sender=auth_app, dispatch_uid="django.contrib.auth.management.create_superuser")
sender=apps.get_app_config('auth'),
dispatch_uid="django.contrib.auth.management.create_superuser")

View File

@ -1,3 +1,5 @@
from __future__ import unicode_literals
import getpass
from optparse import make_option

View File

@ -10,8 +10,7 @@ from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from django.contrib.auth import authenticate, get_user
from django.http import HttpRequest
from django.test import TestCase
from django.test.utils import override_settings
from django.test import TestCase, override_settings
from django.contrib.auth.hashers import MD5PasswordHasher

View File

@ -3,6 +3,7 @@ from __future__ import unicode_literals
import locale
from django.apps import apps
from django.contrib.auth import get_user_model
from django.contrib.auth.management.commands import createsuperuser
from django.contrib.auth.models import User, AnonymousUser
@ -11,9 +12,8 @@ from django.contrib.auth.tests.utils import skipIfCustomUser
from django.core.exceptions import ImproperlyConfigured
from django.core.management import call_command
from django.dispatch import receiver
from django.test import TestCase
from django.test import TestCase, override_settings
from django.test.signals import setting_changed
from django.test.utils import override_settings
from django.utils import translation
from django.utils.encoding import force_str
from django.utils.six import binary_type, PY2, StringIO
@ -26,6 +26,7 @@ def user_model_swapped(**kwargs):
# Reset User manager
setattr(User, 'objects', User._default_manager)
ensure_default_manager(User)
apps.clear_cache()
def mock_inputs(inputs):

View File

@ -7,8 +7,7 @@ from django.contrib.auth.models import User, Permission
from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.context_processors import PermWrapper, PermLookupDict
from django.db.models import Q
from django.test import TestCase
from django.test.utils import override_settings
from django.test import TestCase, override_settings
from django.utils._os import upath

View File

@ -12,8 +12,7 @@ from django.contrib.auth.forms import (UserCreationForm, AuthenticationForm,
from django.contrib.auth.tests.utils import skipIfCustomUser
from django.core import mail
from django.forms.fields import Field, CharField
from django.test import TestCase
from django.test.utils import override_settings
from django.test import TestCase, override_settings
from django.utils.encoding import force_text
from django.utils._os import upath
from django.utils import translation

View File

@ -5,7 +5,7 @@ from django.contrib.auth.models import User, Group
from django.contrib.auth.tests.custom_user import CustomUser
from django.contrib.auth.tests.utils import skipIfCustomUser
from django.test import TransactionTestCase
from django.test.utils import override_settings
from django.test import override_settings
# This must be a TransactionTestCase because the WSGI auth handler performs

View File

@ -1,6 +1,7 @@
from __future__ import unicode_literals
from datetime import date
from django.apps import apps
from django.contrib.auth import models, management
from django.contrib.auth.management import create_permissions
from django.contrib.auth.management.commands import changepassword
@ -8,13 +9,11 @@ from django.contrib.auth.models import User
from django.contrib.auth.tests.custom_user import CustomUser
from django.contrib.auth.tests.utils import skipIfCustomUser
from django.contrib.contenttypes.models import ContentType
from django.core.apps import app_cache
from django.core import exceptions
from django.core.management import call_command
from django.core.management.base import CommandError
from django.core.management.validation import get_validation_errors
from django.test import TestCase
from django.test.utils import override_settings
from django.test import TestCase, override_settings
from django.utils import six
from django.utils.six import StringIO
@ -83,6 +82,19 @@ class ChangepasswordManagementCommandTestCase(TestCase):
with self.assertRaises(CommandError):
command.execute("joe", stdout=self.stdout, stderr=self.stderr)
def test_that_changepassword_command_works_with_nonascii_output(self):
"""
#21627 -- Executing the changepassword management command should allow
non-ASCII characters from the User object representation.
"""
# 'Julia' with accented 'u':
models.User.objects.create_user(username='J\xfalia', password='qwerty')
command = changepassword.Command()
command._get_pass = lambda *args: 'not qwerty'
command.execute("J\xfalia", stdout=self.stdout)
@skipIfCustomUser
class CreatesuperuserManagementCommandTestCase(TestCase):
@ -184,21 +196,21 @@ class CustomUserModelValidationTestCase(TestCase):
def test_required_fields_is_list(self):
"REQUIRED_FIELDS should be a list."
new_io = StringIO()
get_validation_errors(new_io, app_cache.get_app_config('auth').models_module)
get_validation_errors(new_io, apps.get_app_config('auth'))
self.assertIn("The REQUIRED_FIELDS must be a list or tuple.", new_io.getvalue())
@override_settings(AUTH_USER_MODEL='auth.CustomUserBadRequiredFields')
def test_username_not_in_required_fields(self):
"USERNAME_FIELD should not appear in REQUIRED_FIELDS."
new_io = StringIO()
get_validation_errors(new_io, app_cache.get_app_config('auth').models_module)
get_validation_errors(new_io, apps.get_app_config('auth'))
self.assertIn("The field named as the USERNAME_FIELD should not be included in REQUIRED_FIELDS on a swappable User model.", new_io.getvalue())
@override_settings(AUTH_USER_MODEL='auth.CustomUserNonUniqueUsername')
def test_username_non_unique(self):
"A non-unique USERNAME_FIELD should raise a model validation error."
new_io = StringIO()
get_validation_errors(new_io, app_cache.get_app_config('auth').models_module)
get_validation_errors(new_io, apps.get_app_config('auth'))
self.assertIn("The USERNAME_FIELD must be unique. Add unique=True to the field parameters.", new_io.getvalue())
@ -220,13 +232,15 @@ class PermissionTestCase(TestCase):
Test that we show proper error message if we are trying to create
duplicate permissions.
"""
auth_app_config = apps.get_app_config('auth')
# check duplicated default permission
models.Permission._meta.permissions = [
('change_permission', 'Can edit permission (duplicate)')]
six.assertRaisesRegex(self, CommandError,
"The permission codename 'change_permission' clashes with a "
"builtin permission for model 'auth.Permission'.",
create_permissions, models, [], verbosity=0)
create_permissions, auth_app_config, verbosity=0)
# check duplicated custom permissions
models.Permission._meta.permissions = [
@ -237,21 +251,23 @@ class PermissionTestCase(TestCase):
six.assertRaisesRegex(self, CommandError,
"The permission codename 'my_custom_permission' is duplicated for model "
"'auth.Permission'.",
create_permissions, models, [], verbosity=0)
create_permissions, auth_app_config, verbosity=0)
# should not raise anything
models.Permission._meta.permissions = [
('my_custom_permission', 'Some permission'),
('other_one', 'Some other permission'),
]
create_permissions(models, [], verbosity=0)
create_permissions(auth_app_config, verbosity=0)
def test_default_permissions(self):
auth_app_config = apps.get_app_config('auth')
permission_content_type = ContentType.objects.get_by_natural_key('auth', 'permission')
models.Permission._meta.permissions = [
('my_custom_permission', 'Some permission'),
]
create_permissions(models, [], verbosity=0)
create_permissions(auth_app_config, verbosity=0)
# add/change/delete permission by default + custom permission
self.assertEqual(models.Permission.objects.filter(
@ -260,7 +276,7 @@ class PermissionTestCase(TestCase):
models.Permission.objects.filter(content_type=permission_content_type).delete()
models.Permission._meta.default_permissions = []
create_permissions(models, [], verbosity=0)
create_permissions(auth_app_config, verbosity=0)
# custom permission only since default permissions is empty
self.assertEqual(models.Permission.objects.filter(
@ -268,10 +284,12 @@ class PermissionTestCase(TestCase):
).count(), 1)
def test_verbose_name_length(self):
auth_app_config = apps.get_app_config('auth')
permission_content_type = ContentType.objects.get_by_natural_key('auth', 'permission')
models.Permission.objects.filter(content_type=permission_content_type).delete()
models.Permission._meta.verbose_name = "some ridiculously long verbose name that is out of control"
six.assertRaisesRegex(self, exceptions.ValidationError,
"The verbose_name of permission is longer than 39 characters",
create_permissions, models, [], verbosity=0)
create_permissions, auth_app_config, verbosity=0)

View File

@ -3,8 +3,7 @@ from django.contrib.auth.models import AbstractUser, Group, User, UserManager
from django.contrib.auth.tests.utils import skipIfCustomUser
from django.core import mail
from django.db.models.signals import post_save
from django.test import TestCase
from django.test.utils import override_settings
from django.test import TestCase, override_settings
@skipIfCustomUser

View File

@ -3,7 +3,7 @@ from django.contrib.auth.models import User
from django.contrib.auth.tests.utils import skipIfCustomUser
from django.test import TestCase
from django.test.client import RequestFactory
from django.test.utils import override_settings
from django.test import override_settings
@skipIfCustomUser

View File

@ -7,7 +7,7 @@ from django.contrib.auth.views import (
password_reset_complete, password_change, password_change_done,
)
from django.test import RequestFactory, TestCase
from django.test.utils import override_settings
from django.test import override_settings
from django.utils.encoding import force_bytes, force_text
from django.utils.http import urlsafe_base64_encode

View File

@ -14,8 +14,8 @@ from django.utils.encoding import force_text
from django.utils.http import urlquote
from django.utils.six.moves.urllib.parse import urlparse, ParseResult
from django.utils._os import upath
from django.test import TestCase
from django.test.utils import override_settings, patch_logger
from django.test import TestCase, override_settings
from django.test.utils import patch_logger
from django.middleware.csrf import CsrfViewMiddleware
from django.contrib.sessions.middleware import SessionMiddleware

View File

@ -1,5 +1,6 @@
from importlib import import_module
import warnings
from django.apps import apps
from django.conf import settings
from django.core import urlresolvers
from django.core.exceptions import ImproperlyConfigured
@ -14,20 +15,12 @@ def get_comment_app():
"""
Get the comment app (i.e. "django.contrib.comments") as defined in the settings
"""
# Make sure the app's in INSTALLED_APPS
comments_app = get_comment_app_name()
if comments_app not in settings.INSTALLED_APPS:
raise ImproperlyConfigured("The COMMENTS_APP (%r) "\
"must be in INSTALLED_APPS" % settings.COMMENTS_APP)
# Try to import the package
try:
package = import_module(comments_app)
except ImportError as e:
raise ImproperlyConfigured("The COMMENTS_APP setting refers to "\
"a non-existing package. (%s)" % e)
return package
app_config = apps.get_app_config(get_comment_app_name().rpartition(".")[2])
except LookupError:
raise ImproperlyConfigured("The COMMENTS_APP (%r) "
"must be in INSTALLED_APPS" % settings.COMMENTS_APP)
return app_config.module
def get_comment_app_name():
"""

View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class CommentsConfig(AppConfig):
name = 'django.contrib.comments'
verbose_name = _("comments")

View File

@ -1,9 +1,9 @@
from django import http
from django.apps import apps
from django.conf import settings
from django.contrib import comments
from django.contrib.comments import signals
from django.contrib.comments.views.utils import next_redirect, confirmation_view
from django.core.apps import app_cache
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models
from django.shortcuts import render_to_response
@ -49,12 +49,12 @@ def post_comment(request, next=None, using=None):
if ctype is None or object_pk is None:
return CommentPostBadRequest("Missing content_type or object_pk field.")
try:
model = app_cache.get_model(*ctype.split(".", 1))
model = apps.get_model(*ctype.split(".", 1))
target = model._default_manager.using(using).get(pk=object_pk)
except TypeError:
return CommentPostBadRequest(
"Invalid content_type value: %r" % escape(ctype))
except AttributeError:
except LookupError:
return CommentPostBadRequest(
"The given content-type %r does not resolve to a valid model." % \
escape(ctype))

View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class ContentTypesConfig(AppConfig):
name = 'django.contrib.contenttypes'
verbose_name = _("content types")

View File

@ -1,5 +1,4 @@
from django.contrib.contenttypes.models import ContentType
from django.core.apps import app_cache, UnavailableApp
from django.apps import apps
from django.db import DEFAULT_DB_ALIAS, router
from django.db.models import signals
from django.utils.encoding import smart_text
@ -7,29 +6,32 @@ from django.utils import six
from django.utils.six.moves import input
def update_contenttypes(app, created_models, verbosity=2, db=DEFAULT_DB_ALIAS, **kwargs):
def update_contenttypes(app_config, verbosity=2, interactive=True, db=DEFAULT_DB_ALIAS, **kwargs):
"""
Creates content types for models in the given app, removing any model
entries that no longer have a matching model class.
"""
if not app_config.models_module:
return
try:
app_cache.get_model('contenttypes', 'ContentType')
except UnavailableApp:
ContentType = apps.get_model('contenttypes', 'ContentType')
except LookupError:
return
if not router.allow_migrate(db, ContentType):
return
ContentType.objects.clear_cache()
app_models = app_cache.get_models(app)
if not app_models:
return
# They all have the same app_label, get the first one.
app_label = app_models[0]._meta.app_label
app_label = app_config.label
app_models = dict(
(model._meta.model_name, model)
for model in app_models
)
for model in app_config.get_models())
if not app_models:
return
# Get all the content types
content_types = dict(
@ -85,11 +87,13 @@ If you're unsure, answer 'no'.
print("Stale content types remain.")
def update_all_contenttypes(verbosity=2, **kwargs):
for app_config in app_cache.get_app_configs(only_with_models_module=True):
update_contenttypes(app_config.models_module, None, verbosity, **kwargs)
def update_all_contenttypes(**kwargs):
for app_config in apps.get_app_configs():
update_contenttypes(app_config, **kwargs)
signals.post_migrate.connect(update_contenttypes)
if __name__ == "__main__":
update_all_contenttypes()

View File

@ -1,4 +1,4 @@
from django.core.apps import app_cache
from django.apps import apps
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_text, force_text
@ -157,8 +157,10 @@ class ContentType(models.Model):
def model_class(self):
"Returns the Python model class for this type of content."
return app_cache.get_model(self.app_label, self.model,
only_installed=False)
try:
return apps.get_model(self.app_label, self.model)
except LookupError:
return None
def get_object_for_this_type(self, **kwargs):
"""

View File

@ -1,12 +1,11 @@
from __future__ import unicode_literals
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.views import shortcut
from django.contrib.sites.models import Site, get_current_site
from django.contrib.sites.models import get_current_site
from django.db import models
from django.http import HttpRequest, Http404
from django.test import TestCase
from django.test.utils import override_settings
from django.test import TestCase, override_settings
from django.utils.http import urlquote
from django.utils import six
from django.utils.encoding import python_2_unicode_compatible
@ -54,11 +53,9 @@ class FooWithBrokenAbsoluteUrl(FooWithoutUrl):
class ContentTypesTests(TestCase):
def setUp(self):
self._old_installed = Site._meta.app_config.installed
ContentType.objects.clear_cache()
def tearDown(self):
Site._meta.app_config.installed = self._old_installed
ContentType.objects.clear_cache()
def test_lookup_cache(self):
@ -223,15 +220,15 @@ class ContentTypesTests(TestCase):
user_ct = ContentType.objects.get_for_model(FooWithUrl)
obj = FooWithUrl.objects.create(name="john")
Site._meta.app_config.installed = True
response = shortcut(request, user_ct.id, obj.id)
self.assertEqual("http://%s/users/john/" % get_current_site(request).domain,
response._headers.get("location")[1])
with self.modify_settings(INSTALLED_APPS={'append': 'django.contrib.sites'}):
response = shortcut(request, user_ct.id, obj.id)
self.assertEqual("http://%s/users/john/" % get_current_site(request).domain,
response._headers.get("location")[1])
Site._meta.app_config.installed = False
response = shortcut(request, user_ct.id, obj.id)
self.assertEqual("http://Example.com/users/john/",
response._headers.get("location")[1])
with self.modify_settings(INSTALLED_APPS={'remove': 'django.contrib.sites'}):
response = shortcut(request, user_ct.id, obj.id)
self.assertEqual("http://Example.com/users/john/",
response._headers.get("location")[1])
def test_shortcut_view_without_get_absolute_url(self):
"""

View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class FlatPagesConfig(AppConfig):
name = 'django.contrib.flatpages'
verbose_name = _("flat pages")

View File

@ -2,7 +2,7 @@ import os
from django.contrib.auth.models import User
from django.contrib.auth.tests.utils import skipIfCustomUser
from django.test import TestCase, Client
from django.test.utils import override_settings
from django.test import override_settings
@override_settings(

View File

@ -3,8 +3,7 @@ from __future__ import unicode_literals
from django.conf import settings
from django.contrib.flatpages.forms import FlatpageForm
from django.contrib.flatpages.models import FlatPage
from django.test import TestCase
from django.test.utils import override_settings
from django.test import TestCase, override_settings
from django.utils import translation

View File

@ -3,8 +3,7 @@ from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth.tests.utils import skipIfCustomUser
from django.contrib.flatpages.models import FlatPage
from django.test import TestCase
from django.test.utils import override_settings
from django.test import TestCase, override_settings
@override_settings(

View File

@ -2,8 +2,7 @@ import os
from django.contrib.auth.models import AnonymousUser, User
from django.contrib.auth.tests.utils import skipIfCustomUser
from django.template import Template, Context, TemplateSyntaxError
from django.test import TestCase
from django.test.utils import override_settings
from django.test import TestCase, override_settings
@override_settings(

View File

@ -3,8 +3,7 @@ from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth.tests.utils import skipIfCustomUser
from django.contrib.flatpages.models import FlatPage
from django.test import TestCase
from django.test.utils import override_settings
from django.test import TestCase, override_settings
@override_settings(

View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class FormToolsConfig(AppConfig):
name = 'django.contrib.formtools'
verbose_name = _("form tools")

View File

@ -8,8 +8,7 @@ import warnings
from django import http
from django.contrib.formtools import preview, utils
from django.test import TestCase
from django.test.utils import override_settings
from django.test import TestCase, override_settings
from django.utils._os import upath
from django.contrib.formtools.tests.forms import (

View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class GISConfig(AppConfig):
name = 'django.contrib.gis'
verbose_name = _("GIS")

View File

@ -89,7 +89,7 @@ class PostGISCreation(DatabaseCreation):
self.connection.close()
self.connection.settings_dict["NAME"] = test_database_name
cursor = self.connection.cursor()
cursor.execute("CREATE EXTENSION postgis")
cursor.execute("CREATE EXTENSION IF NOT EXISTS postgis")
cursor.connection.commit()
return test_database_name

View File

@ -6,9 +6,9 @@ for more details:
__all__ = ['HAS_GEOS']
try:
from .libgeos import geos_version, geos_version_info, GEOS_PREPARE # NOQA: flake8 detects only the last __all__
from .libgeos import geos_version, geos_version_info # NOQA: flake8 detects only the last __all__
HAS_GEOS = True
__all__ += ['geos_version', 'geos_version_info', 'GEOS_PREPARE']
__all__ += ['geos_version', 'geos_version_info']
except ImportError:
HAS_GEOS = False

View File

@ -3,9 +3,8 @@
GeometryCollection, MultiPoint, MultiLineString, and MultiPolygon
"""
from ctypes import c_int, c_uint, byref
from django.contrib.gis.geos.error import GEOSException
from django.contrib.gis.geos.geometry import GEOSGeometry
from django.contrib.gis.geos.libgeos import get_pointer_arr, GEOS_PREPARE
from django.contrib.gis.geos.libgeos import get_pointer_arr
from django.contrib.gis.geos.linestring import LineString, LinearRing
from django.contrib.gis.geos.point import Point
from django.contrib.gis.geos.polygon import Polygon
@ -119,10 +118,7 @@ class MultiPolygon(GeometryCollection):
@property
def cascaded_union(self):
"Returns a cascaded union of this MultiPolygon."
if GEOS_PREPARE:
return GEOSGeometry(capi.geos_cascaded_union(self.ptr), self.srid)
else:
raise GEOSException('The cascaded union operation requires GEOS 3.1+.')
return GEOSGeometry(capi.geos_cascaded_union(self.ptr), self.srid)
# Setting the allowed types here since GeometryCollection is defined before
# its subclasses.

View File

@ -17,7 +17,7 @@ from django.contrib.gis.gdal.error import SRSException
from django.contrib.gis.geos.base import GEOSBase, gdal
from django.contrib.gis.geos.coordseq import GEOSCoordSeq
from django.contrib.gis.geos.error import GEOSException, GEOSIndexError
from django.contrib.gis.geos.libgeos import GEOM_PTR, GEOS_PREPARE
from django.contrib.gis.geos.libgeos import GEOM_PTR
# All other functions in this module come from the ctypes
# prototypes module -- which handles all interaction with
@ -289,8 +289,6 @@ class GEOSGeometry(GEOSBase, ListMixin):
"""
Returns a string containing the reason for any invalidity.
"""
if not GEOS_PREPARE:
raise GEOSException('Upgrade GEOS to 3.1 to get validity reason.')
return capi.geos_isvalidreason(self.ptr).decode()
#### Binary predicates. ####
@ -411,9 +409,6 @@ class GEOSGeometry(GEOSBase, ListMixin):
extension of the WKB specification that includes SRID value that are
a part of this geometry.
"""
if self.hasz and not GEOS_PREPARE:
# See: http://trac.osgeo.org/geos/ticket/216
raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D HEXEWKB.')
return ewkb_w(3 if self.hasz else 2).write_hex(self)
@property
@ -443,9 +438,6 @@ class GEOSGeometry(GEOSBase, ListMixin):
This is an extension of the WKB specification that includes any SRID
value that are a part of this geometry.
"""
if self.hasz and not GEOS_PREPARE:
# See: http://trac.osgeo.org/geos/ticket/216
raise GEOSException('Upgrade GEOS to 3.1 to get valid 3D EWKB.')
return ewkb_w(3 if self.hasz else 2).write(self)
@property
@ -460,10 +452,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
Returns a PreparedGeometry corresponding to this geometry -- it is
optimized for the contains, intersects, and covers operations.
"""
if GEOS_PREPARE:
return PreparedGeometry(self)
else:
raise GEOSException('GEOS 3.1+ required for prepared geometry support.')
return PreparedGeometry(self)
#### GDAL-specific output routines ####
@property
@ -707,16 +696,14 @@ from django.contrib.gis.geos.linestring import LineString, LinearRing
from django.contrib.gis.geos.point import Point
from django.contrib.gis.geos.polygon import Polygon
from django.contrib.gis.geos.collections import GeometryCollection, MultiPoint, MultiLineString, MultiPolygon
GEOS_CLASSES = {0: Point,
1: LineString,
2: LinearRing,
3: Polygon,
4: MultiPoint,
5: MultiLineString,
6: MultiPolygon,
7: GeometryCollection,
}
# If supported, import the PreparedGeometry class.
if GEOS_PREPARE:
from django.contrib.gis.geos.prepared import PreparedGeometry
from django.contrib.gis.geos.prepared import PreparedGeometry
GEOS_CLASSES = {
0: Point,
1: LineString,
2: LinearRing,
3: Polygon,
4: MultiPoint,
5: MultiLineString,
6: MultiPolygon,
7: GeometryCollection,
}

View File

@ -155,22 +155,10 @@ GEOS_MINOR_VERSION = int(_verinfo['minor'])
GEOS_SUBMINOR_VERSION = int(_verinfo['subminor'])
del _verinfo
GEOS_VERSION = (GEOS_MAJOR_VERSION, GEOS_MINOR_VERSION, GEOS_SUBMINOR_VERSION)
GEOS_PREPARE = GEOS_VERSION >= (3, 1, 0)
if GEOS_PREPARE:
# Here we set up the prototypes for the initGEOS_r and finishGEOS_r
# routines. These functions aren't actually called until they are
# attached to a GEOS context handle -- this actually occurs in
# geos/prototypes/threadsafe.py.
lgeos.initGEOS_r.restype = CONTEXT_PTR
lgeos.finishGEOS_r.argtypes = [CONTEXT_PTR]
else:
# When thread-safety isn't available, the initGEOS routine must be called
# first. This function takes the notice and error functions, defined
# as Python callbacks above, as parameters. Here is the C code that is
# wrapped:
# extern void GEOS_DLL initGEOS(GEOSMessageHandler notice_function, GEOSMessageHandler error_function);
lgeos.initGEOS(notice_h, error_h)
# Calling finishGEOS() upon exit of the interpreter.
import atexit
atexit.register(lgeos.finishGEOS)
# Here we set up the prototypes for the initGEOS_r and finishGEOS_r
# routines. These functions aren't actually called until they are
# attached to a GEOS context handle -- this actually occurs in
# geos/prototypes/threadsafe.py.
lgeos.initGEOS_r.restype = CONTEXT_PTR
lgeos.finishGEOS_r.argtypes = [CONTEXT_PTR]

View File

@ -1,6 +1,8 @@
from django.contrib.gis.geos.base import GEOSBase
from django.contrib.gis.geos.geometry import GEOSGeometry
from django.contrib.gis.geos.prototypes import prepared as capi
from .base import GEOSBase
from .error import GEOSException
from .geometry import GEOSGeometry
from .libgeos import geos_version_info
from .prototypes import prepared as capi
class PreparedGeometry(GEOSBase):
@ -12,6 +14,10 @@ class PreparedGeometry(GEOSBase):
ptr_type = capi.PREPGEOM_PTR
def __init__(self, geom):
# Keeping a reference to the original geometry object to prevent it
# from being garbage collected which could then crash the prepared one
# See #21662
self._base_geom = geom
if not isinstance(geom, GEOSGeometry):
raise TypeError
self.ptr = capi.geos_prepare(geom.ptr)
@ -31,3 +37,30 @@ class PreparedGeometry(GEOSBase):
def intersects(self, other):
return capi.prepared_intersects(self.ptr, other.ptr)
# Added in GEOS 3.3:
def crosses(self, other):
if geos_version_info()['version'] < '3.3.0':
raise GEOSException("crosses on prepared geometries requires GEOS >= 3.3.0")
return capi.prepared_crosses(self.ptr, other.ptr)
def disjoint(self, other):
if geos_version_info()['version'] < '3.3.0':
raise GEOSException("disjoint on prepared geometries requires GEOS >= 3.3.0")
return capi.prepared_disjoint(self.ptr, other.ptr)
def overlaps(self, other):
if geos_version_info()['version'] < '3.3.0':
raise GEOSException("overlaps on prepared geometries requires GEOS >= 3.3.0")
return capi.prepared_overlaps(self.ptr, other.ptr)
def touches(self, other):
if geos_version_info()['version'] < '3.3.0':
raise GEOSException("touches on prepared geometries requires GEOS >= 3.3.0")
return capi.prepared_touches(self.ptr, other.ptr)
def within(self, other):
if geos_version_info()['version'] < '3.3.0':
raise GEOSException("within on prepared geometries requires GEOS >= 3.3.0")
return capi.prepared_within(self.ptr, other.ptr)

View File

@ -3,13 +3,13 @@
ones that return the area, distance, and length.
"""
from ctypes import c_int, c_double, POINTER
from django.contrib.gis.geos.libgeos import GEOM_PTR, GEOS_PREPARE
from django.contrib.gis.geos.libgeos import GEOM_PTR
from django.contrib.gis.geos.prototypes.errcheck import check_dbl, check_string
from django.contrib.gis.geos.prototypes.geom import geos_char_p
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
from django.utils.six.moves import xrange
__all__ = ['geos_area', 'geos_distance', 'geos_length']
__all__ = ['geos_area', 'geos_distance', 'geos_length', 'geos_isvalidreason']
### ctypes generator function ###
@ -31,11 +31,7 @@ def dbl_from_geom(func, num_geom=1):
geos_area = dbl_from_geom(GEOSFunc('GEOSArea'))
geos_distance = dbl_from_geom(GEOSFunc('GEOSDistance'), num_geom=2)
geos_length = dbl_from_geom(GEOSFunc('GEOSLength'))
# Validity reason; only in GEOS 3.1+
if GEOS_PREPARE:
geos_isvalidreason = GEOSFunc('GEOSisValidReason')
geos_isvalidreason.argtypes = [GEOM_PTR]
geos_isvalidreason.restype = geos_char_p
geos_isvalidreason.errcheck = check_string
__all__.append('geos_isvalidreason')
geos_isvalidreason = GEOSFunc('GEOSisValidReason')
geos_isvalidreason.argtypes = [GEOM_PTR]
geos_isvalidreason.restype = geos_char_p
geos_isvalidreason.errcheck = check_string

View File

@ -1,5 +1,5 @@
from ctypes import c_char
from django.contrib.gis.geos.libgeos import GEOM_PTR, PREPGEOM_PTR
from django.contrib.gis.geos.libgeos import GEOM_PTR, PREPGEOM_PTR, geos_version_info
from django.contrib.gis.geos.prototypes.errcheck import check_predicate
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
@ -24,3 +24,10 @@ prepared_contains = prepared_predicate(GEOSFunc('GEOSPreparedContains'))
prepared_contains_properly = prepared_predicate(GEOSFunc('GEOSPreparedContainsProperly'))
prepared_covers = prepared_predicate(GEOSFunc('GEOSPreparedCovers'))
prepared_intersects = prepared_predicate(GEOSFunc('GEOSPreparedIntersects'))
if geos_version_info()['version'] > '3.3.0':
prepared_crosses = prepared_predicate(GEOSFunc('GEOSPreparedCrosses'))
prepared_disjoint = prepared_predicate(GEOSFunc('GEOSPreparedDisjoint'))
prepared_overlaps = prepared_predicate(GEOSFunc('GEOSPreparedOverlaps'))
prepared_touches = prepared_predicate(GEOSFunc('GEOSPreparedTouches'))
prepared_within = prepared_predicate(GEOSFunc('GEOSPreparedWithin'))

View File

@ -2,13 +2,14 @@
This module houses the GEOS ctypes prototype functions for the
topological operations on geometries.
"""
__all__ = ['geos_boundary', 'geos_buffer', 'geos_centroid', 'geos_convexhull',
'geos_difference', 'geos_envelope', 'geos_intersection',
'geos_linemerge', 'geos_pointonsurface', 'geos_preservesimplify',
'geos_simplify', 'geos_symdifference', 'geos_union', 'geos_relate']
__all__ = ['geos_boundary', 'geos_buffer', 'geos_cascaded_union',
'geos_centroid', 'geos_convexhull', 'geos_difference',
'geos_envelope', 'geos_intersection', 'geos_linemerge',
'geos_pointonsurface', 'geos_preservesimplify', 'geos_simplify',
'geos_symdifference', 'geos_union', 'geos_relate']
from ctypes import c_double, c_int
from django.contrib.gis.geos.libgeos import geos_version_info, GEOM_PTR, GEOS_PREPARE
from django.contrib.gis.geos.libgeos import geos_version_info, GEOM_PTR
from django.contrib.gis.geos.prototypes.errcheck import check_geom, check_minus_one, check_string
from django.contrib.gis.geos.prototypes.geom import geos_char_p
from django.contrib.gis.geos.prototypes.threadsafe import GEOSFunc
@ -39,19 +40,16 @@ geos_simplify = topology(GEOSFunc('GEOSSimplify'), c_double)
geos_symdifference = topology(GEOSFunc('GEOSSymDifference'), GEOM_PTR)
geos_union = topology(GEOSFunc('GEOSUnion'), GEOM_PTR)
geos_cascaded_union = GEOSFunc('GEOSUnionCascaded')
geos_cascaded_union.argtypes = [GEOM_PTR]
geos_cascaded_union.restype = GEOM_PTR
# GEOSRelate returns a string, not a geometry.
geos_relate = GEOSFunc('GEOSRelate')
geos_relate.argtypes = [GEOM_PTR, GEOM_PTR]
geos_relate.restype = geos_char_p
geos_relate.errcheck = check_string
# Routines only in GEOS 3.1+
if GEOS_PREPARE:
geos_cascaded_union = GEOSFunc('GEOSUnionCascaded')
geos_cascaded_union.argtypes = [GEOM_PTR]
geos_cascaded_union.restype = GEOM_PTR
__all__.append('geos_cascaded_union')
# Linear referencing routines
info = geos_version_info()
if info['version'] >= '3.2.0':

View File

@ -22,8 +22,7 @@ from .. import HAS_GEOS
if HAS_GEOS:
from .. import (GEOSException, GEOSIndexError, GEOSGeometry,
GeometryCollection, Point, MultiPoint, Polygon, MultiPolygon, LinearRing,
LineString, MultiLineString, fromfile, fromstr, geos_version_info,
GEOS_PREPARE)
LineString, MultiLineString, fromfile, fromstr, geos_version_info)
from ..base import gdal, numpy, GEOSBase
@ -121,20 +120,12 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
# a bug in versions prior to 3.1 that puts the X coordinate in
# place of Z; an exception should be raised on those versions.
self.assertEqual(hexewkb_2d, pnt_2d.hexewkb)
if GEOS_PREPARE:
self.assertEqual(hexewkb_3d, pnt_3d.hexewkb)
self.assertEqual(True, GEOSGeometry(hexewkb_3d).hasz)
else:
with self.assertRaises(GEOSException):
pnt_3d.hexewkb
self.assertEqual(hexewkb_3d, pnt_3d.hexewkb)
self.assertEqual(True, GEOSGeometry(hexewkb_3d).hasz)
# Same for EWKB.
self.assertEqual(memoryview(a2b_hex(hexewkb_2d)), pnt_2d.ewkb)
if GEOS_PREPARE:
self.assertEqual(memoryview(a2b_hex(hexewkb_3d)), pnt_3d.ewkb)
else:
with self.assertRaises(GEOSException):
pnt_3d.ewkb
self.assertEqual(memoryview(a2b_hex(hexewkb_3d)), pnt_3d.ewkb)
# Redundant sanity check.
self.assertEqual(4326, GEOSGeometry(hexewkb_2d).srid)
@ -869,10 +860,9 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
self.assertIsInstance(g1.ogr, gdal.OGRGeometry)
self.assertIsNone(g1.srs)
if GEOS_PREPARE:
g1_3d = fromstr('POINT(5 23 8)')
self.assertIsInstance(g1_3d.ogr, gdal.OGRGeometry)
self.assertEqual(g1_3d.ogr.z, 8)
g1_3d = fromstr('POINT(5 23 8)')
self.assertIsInstance(g1_3d.ogr, gdal.OGRGeometry)
self.assertEqual(g1_3d.ogr.z, 8)
g2 = fromstr('LINESTRING(0 0, 5 5, 23 23)', srid=4326)
self.assertIsInstance(g2.ogr, gdal.OGRGeometry)
@ -918,10 +908,7 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
def test_transform_3d(self):
p3d = GEOSGeometry('POINT (5 23 100)', 4326)
p3d.transform(2774)
if GEOS_PREPARE:
self.assertEqual(p3d.z, 100)
else:
self.assertIsNone(p3d.z)
self.assertEqual(p3d.z, 100)
@skipUnless(HAS_GDAL, "GDAL is required.")
def test_transform_noop(self):
@ -1030,7 +1017,6 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
if not no_srid:
self.assertEqual(geom.srid, tmpg.srid)
@skipUnless(HAS_GEOS and GEOS_PREPARE, "geos >= 3.1.0 is required")
def test_prepared(self):
"Testing PreparedGeometry support."
# Creating a simple multipolygon and getting a prepared version.
@ -1046,6 +1032,20 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
self.assertEqual(mpoly.intersects(pnt), prep.intersects(pnt))
self.assertEqual(c, prep.covers(pnt))
if geos_version_info()['version'] > '3.3.0':
self.assertTrue(prep.crosses(fromstr('LINESTRING(1 1, 15 15)')))
self.assertTrue(prep.disjoint(Point(-5, -5)))
poly = Polygon(((-1, -1), (1, 1), (1, 0), (-1, -1)))
self.assertTrue(prep.overlaps(poly))
poly = Polygon(((-5, 0), (-5, 5), (0, 5), (-5, 0)))
self.assertTrue(prep.touches(poly))
poly = Polygon(((-1, -1), (-1, 11), (11, 11), (11, -1), (-1, -1)))
self.assertTrue(prep.within(poly))
# Original geometry deletion should not crash the prepared one (#21662)
del mpoly
self.assertTrue(prep.covers(Point(5, 5)))
def test_line_merge(self):
"Testing line merge support"
ref_geoms = (fromstr('LINESTRING(1 1, 1 1, 3 3)'),
@ -1057,7 +1057,6 @@ class GEOSTest(unittest.TestCase, TestDataMixin):
for geom, merged in zip(ref_geoms, ref_merged):
self.assertEqual(merged, geom.merged)
@skipUnless(HAS_GEOS and GEOS_PREPARE, "geos >= 3.1.0 is required")
def test_valid_reason(self):
"Testing IsValidReason support"

View File

@ -1,4 +1,6 @@
import inspect
from optparse import make_option
from django.contrib.gis import gdal
from django.core.management.base import LabelCommand, CommandError
@ -83,27 +85,21 @@ class Command(LabelCommand):
if not gdal.HAS_GDAL:
raise CommandError('GDAL is required to inspect geospatial data sources.')
# Removing options with `None` values.
options = dict((k, v) for k, v in options.items() if not v is None)
# Getting the OGR DataSource from the string parameter.
try:
ds = gdal.DataSource(data_source)
except gdal.OGRException as msg:
raise CommandError(msg)
# Whether the user wants to generate the LayerMapping dictionary as well.
show_mapping = options.pop('mapping', False)
# Getting rid of settings that `_ogrinspect` doesn't like.
options.pop('verbosity', False)
options.pop('settings', False)
# Returning the output of ogrinspect with the given arguments
# and options.
from django.contrib.gis.utils.ogrinspect import _ogrinspect, mapping
output = [s for s in _ogrinspect(ds, model_name, **options)]
if show_mapping:
# Filter options to params accepted by `_ogrinspect`
ogr_options = dict((k, v) for k, v in options.items()
if k in inspect.getargspec(_ogrinspect).args and v is not None)
output = [s for s in _ogrinspect(ds, model_name, **ogr_options)]
if options['mapping']:
# Constructing the keyword arguments for `mapping`, and
# calling it on the data source.
kwargs = {'geom_name': options['geom_name'],

View File

@ -1,4 +1,4 @@
from django.core.apps import app_cache
from django.apps import apps
from django.core import urlresolvers
from django.contrib.sitemaps import Sitemap
from django.contrib.gis.db.models.fields import GeometryField
@ -26,7 +26,7 @@ class KMLSitemap(Sitemap):
"""
kml_sources = []
if sources is None:
sources = app_cache.get_models()
sources = apps.get_models()
for source in sources:
if isinstance(source, models.base.ModelBase):
for field in source._meta.fields:

View File

@ -2,7 +2,7 @@ from __future__ import unicode_literals
import warnings
from django.core.apps import app_cache
from django.apps import apps
from django.http import HttpResponse, Http404
from django.template import loader
from django.contrib.sites.models import get_current_site
@ -81,8 +81,9 @@ def kml(request, label, model, field_name=None, compress=False, using=DEFAULT_DB
must be that of a geographic field.
"""
placemarks = []
klass = app_cache.get_model(label, model)
if not klass:
try:
klass = apps.get_model(label, model)
except LookupError:
raise Http404('You must supply a valid app label and module name. Got "%s.%s"' % (label, model))
if field_name:

View File

@ -3,77 +3,49 @@ from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible
class SouthTexasCity(models.Model):
class NamedModel(models.Model):
name = models.CharField(max_length=30)
objects = models.GeoManager()
class Meta:
abstract = True
app_label = 'distapp'
def __str__(self):
return self.name
class SouthTexasCity(NamedModel):
"City model on projected coordinate system for South Texas."
name = models.CharField(max_length=30)
point = models.PointField(srid=32140)
objects = models.GeoManager()
def __str__(self):
return self.name
@python_2_unicode_compatible
class SouthTexasCityFt(models.Model):
class SouthTexasCityFt(NamedModel):
"Same City model as above, but U.S. survey feet are the units."
name = models.CharField(max_length=30)
point = models.PointField(srid=2278)
objects = models.GeoManager()
def __str__(self):
return self.name
@python_2_unicode_compatible
class AustraliaCity(models.Model):
class AustraliaCity(NamedModel):
"City model for Australia, using WGS84."
name = models.CharField(max_length=30)
point = models.PointField()
objects = models.GeoManager()
def __str__(self):
return self.name
@python_2_unicode_compatible
class CensusZipcode(models.Model):
class CensusZipcode(NamedModel):
"Model for a few South Texas ZIP codes (in original Census NAD83)."
name = models.CharField(max_length=5)
poly = models.PolygonField(srid=4269)
objects = models.GeoManager()
def __str__(self):
return self.name
@python_2_unicode_compatible
class SouthTexasZipcode(models.Model):
class SouthTexasZipcode(NamedModel):
"Model for a few South Texas ZIP codes."
name = models.CharField(max_length=5)
poly = models.PolygonField(srid=32140, null=True)
objects = models.GeoManager()
def __str__(self):
return self.name
@python_2_unicode_compatible
class Interstate(models.Model):
class Interstate(NamedModel):
"Geodetic model for U.S. Interstates."
name = models.CharField(max_length=10)
path = models.LineStringField()
objects = models.GeoManager()
def __str__(self):
return self.name
@python_2_unicode_compatible
class SouthTexasInterstate(models.Model):
class SouthTexasInterstate(NamedModel):
"Projected model for South Texas Interstates."
name = models.CharField(max_length=10)
path = models.LineStringField(srid=32140)
objects = models.GeoManager()
def __str__(self):
return self.name

View File

@ -3,85 +3,63 @@ from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible
class City3D(models.Model):
class NamedModel(models.Model):
name = models.CharField(max_length=30)
point = models.PointField(dim=3)
objects = models.GeoManager()
class Meta:
abstract = True
app_label = 'geo3d'
def __str__(self):
return self.name
@python_2_unicode_compatible
class Interstate2D(models.Model):
name = models.CharField(max_length=30)
class City3D(NamedModel):
point = models.PointField(dim=3)
class Interstate2D(NamedModel):
line = models.LineStringField(srid=4269)
objects = models.GeoManager()
def __str__(self):
return self.name
@python_2_unicode_compatible
class Interstate3D(models.Model):
name = models.CharField(max_length=30)
class Interstate3D(NamedModel):
line = models.LineStringField(dim=3, srid=4269)
objects = models.GeoManager()
def __str__(self):
return self.name
@python_2_unicode_compatible
class InterstateProj2D(models.Model):
name = models.CharField(max_length=30)
class InterstateProj2D(NamedModel):
line = models.LineStringField(srid=32140)
objects = models.GeoManager()
def __str__(self):
return self.name
@python_2_unicode_compatible
class InterstateProj3D(models.Model):
name = models.CharField(max_length=30)
class InterstateProj3D(NamedModel):
line = models.LineStringField(dim=3, srid=32140)
objects = models.GeoManager()
def __str__(self):
return self.name
@python_2_unicode_compatible
class Polygon2D(models.Model):
name = models.CharField(max_length=30)
class Polygon2D(NamedModel):
poly = models.PolygonField(srid=32140)
objects = models.GeoManager()
def __str__(self):
return self.name
@python_2_unicode_compatible
class Polygon3D(models.Model):
name = models.CharField(max_length=30)
class Polygon3D(NamedModel):
poly = models.PolygonField(dim=3, srid=32140)
class SimpleModel(models.Model):
objects = models.GeoManager()
def __str__(self):
return self.name
class Meta:
abstract = True
app_label = 'geo3d'
class Point2D(models.Model):
class Point2D(SimpleModel):
point = models.PointField()
objects = models.GeoManager()
class Point3D(models.Model):
class Point3D(SimpleModel):
point = models.PointField(dim=3)
objects = models.GeoManager()
class MultiPoint3D(models.Model):
class MultiPoint3D(SimpleModel):
mpoint = models.MultiPointField(dim=3)
objects = models.GeoManager()

View File

@ -7,8 +7,12 @@ from django.utils.encoding import python_2_unicode_compatible
class City(models.Model):
name = models.CharField(max_length=30)
point = models.PointField()
objects = models.GeoManager()
class Meta:
app_label = 'geoadmin'
def __str__(self):
return self.name

View File

@ -4,8 +4,7 @@ from unittest import skipUnless
from django.contrib.gis.geos import HAS_GEOS
from django.contrib.gis.tests.utils import HAS_SPATIAL_DB
from django.test import TestCase
from django.test.utils import override_settings
from django.test import TestCase, override_settings
if HAS_GEOS and HAS_SPATIAL_DB:
from django.contrib.gis import admin

View File

@ -7,66 +7,66 @@ null_flag = not mysql
@python_2_unicode_compatible
class Country(models.Model):
class NamedModel(models.Model):
name = models.CharField(max_length=30)
objects = models.GeoManager()
class Meta:
abstract = True
app_label = 'geoapp'
def __str__(self):
return self.name
class Country(NamedModel):
mpoly = models.MultiPolygonField() # SRID, by default, is 4326
objects = models.GeoManager()
def __str__(self):
return self.name
@python_2_unicode_compatible
class City(models.Model):
name = models.CharField(max_length=30)
class City(NamedModel):
point = models.PointField()
objects = models.GeoManager()
def __str__(self):
return self.name
# This is an inherited model from City
class PennsylvaniaCity(City):
county = models.CharField(max_length=30)
founded = models.DateTimeField(null=True)
objects = models.GeoManager() # TODO: This should be implicitly inherited.
# TODO: This should be implicitly inherited.
objects = models.GeoManager()
class Meta:
app_label = 'geoapp'
@python_2_unicode_compatible
class State(models.Model):
name = models.CharField(max_length=30)
class State(NamedModel):
poly = models.PolygonField(null=null_flag) # Allowing NULL geometries here.
objects = models.GeoManager()
def __str__(self):
return self.name
@python_2_unicode_compatible
class Track(models.Model):
name = models.CharField(max_length=30)
class Track(NamedModel):
line = models.LineStringField()
objects = models.GeoManager()
def __str__(self):
return self.name
class Truth(models.Model):
val = models.BooleanField(default=False)
objects = models.GeoManager()
if not spatialite:
@python_2_unicode_compatible
class Feature(models.Model):
name = models.CharField(max_length=20)
geom = models.GeometryField()
objects = models.GeoManager()
class Meta:
app_label = 'geoapp'
def __str__(self):
return self.name
if not spatialite:
class Feature(NamedModel):
geom = models.GeometryField()
class MinusOneSRID(models.Model):
geom = models.PointField(srid=-1) # Minus one SRID.
objects = models.GeoManager()
class Meta:
app_label = 'geoapp'

View File

@ -7,12 +7,13 @@ from django.conf import settings
from django.contrib.sites.models import Site
from django.contrib.gis.geos import HAS_GEOS
from django.contrib.gis.tests.utils import HAS_SPATIAL_DB
from django.test import TestCase
from django.test import TestCase, modify_settings
if HAS_GEOS:
from .models import City
@modify_settings(INSTALLED_APPS={'append': 'django.contrib.sites'})
@skipUnless(HAS_GEOS and HAS_SPATIAL_DB, "Geos and spatial db are required.")
class GeoFeedTest(TestCase):
@ -20,11 +21,6 @@ class GeoFeedTest(TestCase):
def setUp(self):
Site(id=settings.SITE_ID, domain="example.com", name="example.com").save()
self._old_installed = Site._meta.app_config.installed
Site._meta.app_config.installed = True
def tearDown(self):
Site._meta.app_config.installed = self._old_installed
def assertChildNodes(self, elem, expected):
"Taken from syndication/tests.py."

View File

@ -10,7 +10,7 @@ from django.conf import settings
from django.contrib.gis.geos import HAS_GEOS
from django.contrib.gis.tests.utils import HAS_SPATIAL_DB
from django.contrib.sites.models import Site
from django.test import TestCase
from django.test import TestCase, modify_settings
from django.test.utils import IgnoreDeprecationWarningsMixin
from django.utils._os import upath
@ -18,6 +18,7 @@ if HAS_GEOS:
from .models import City, Country
@modify_settings(INSTALLED_APPS={'append': 'django.contrib.sites'})
@skipUnless(HAS_GEOS and HAS_SPATIAL_DB, "Geos and spatial db are required.")
class GeoSitemapTest(IgnoreDeprecationWarningsMixin, TestCase):
@ -26,12 +27,6 @@ class GeoSitemapTest(IgnoreDeprecationWarningsMixin, TestCase):
def setUp(self):
super(GeoSitemapTest, self).setUp()
Site(id=settings.SITE_ID, domain="example.com", name="example.com").save()
self._old_installed = Site._meta.app_config.installed
Site._meta.app_config.installed = True
def tearDown(self):
Site._meta.app_config.installed = self._old_installed
super(GeoSitemapTest, self).tearDown()
def assertChildNodes(self, elem, expected):
"Taken from syndication/tests.py."

View File

@ -3,31 +3,31 @@ from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible
class City(models.Model):
class NamedModel(models.Model):
name = models.CharField(max_length=30)
point = models.PointField(geography=True)
objects = models.GeoManager()
class Meta:
abstract = True
app_label = 'geogapp'
def __str__(self):
return self.name
@python_2_unicode_compatible
class Zipcode(models.Model):
class City(NamedModel):
point = models.PointField(geography=True)
class Zipcode(NamedModel):
code = models.CharField(max_length=10)
poly = models.PolygonField(geography=True)
objects = models.GeoManager()
def __str__(self):
return self.code
@python_2_unicode_compatible
class County(models.Model):
name = models.CharField(max_length=25)
class County(NamedModel):
state = models.CharField(max_length=20)
mpoly = models.MultiPolygonField(geography=True)
objects = models.GeoManager()
def __str__(self):
return ' County, '.join([self.name, self.state])

View File

@ -2,6 +2,7 @@ from django.contrib.gis.db import models
class AllOGRFields(models.Model):
f_decimal = models.FloatField()
f_float = models.FloatField()
f_int = models.IntegerField()
@ -13,3 +14,6 @@ class AllOGRFields(models.Model):
point = models.PointField()
objects = models.GeoManager()
class Meta:
app_label = 'inspectapp'

View File

@ -115,6 +115,13 @@ class OGRInspectTest(TestCase):
' objects = models.GeoManager()'
))
def test_management_command(self):
shp_file = os.path.join(TEST_DATA, 'cities', 'cities.shp')
out = StringIO()
call_command('ogrinspect', shp_file, 'City', stdout=out)
output = out.getvalue()
self.assertIn('class City(models.Model):', output)
def get_ogr_db_string():
"""

View File

@ -1,61 +1,75 @@
from django.contrib.gis.db import models
from django.utils.encoding import python_2_unicode_compatible
class State(models.Model):
name = models.CharField(max_length=20)
@python_2_unicode_compatible
class NamedModel(models.Model):
name = models.CharField(max_length=25)
objects = models.GeoManager()
class Meta:
abstract = True
app_label = 'layermap'
class County(models.Model):
name = models.CharField(max_length=25)
def __str__(self):
return self.name
class State(NamedModel):
pass
class County(NamedModel):
state = models.ForeignKey(State)
mpoly = models.MultiPolygonField(srid=4269) # Multipolygon in NAD83
objects = models.GeoManager()
class CountyFeat(models.Model):
name = models.CharField(max_length=25)
class CountyFeat(NamedModel):
poly = models.PolygonField(srid=4269)
objects = models.GeoManager()
class City(models.Model):
name = models.CharField(max_length=25)
class City(NamedModel):
name_txt = models.TextField(default='')
population = models.IntegerField()
density = models.DecimalField(max_digits=7, decimal_places=1)
dt = models.DateField()
point = models.PointField()
objects = models.GeoManager()
class Interstate(models.Model):
name = models.CharField(max_length=20)
class Interstate(NamedModel):
length = models.DecimalField(max_digits=6, decimal_places=2)
path = models.LineStringField()
objects = models.GeoManager()
# Same as `City` above, but for testing model inheritance.
class CityBase(models.Model):
name = models.CharField(max_length=25)
class CityBase(NamedModel):
population = models.IntegerField()
density = models.DecimalField(max_digits=7, decimal_places=1)
point = models.PointField()
objects = models.GeoManager()
class ICity1(CityBase):
dt = models.DateField()
class Meta(CityBase.Meta):
pass
class ICity2(ICity1):
dt_time = models.DateTimeField(auto_now=True)
class Meta(ICity1.Meta):
pass
class Invalid(models.Model):
point = models.PointField()
class Meta:
app_label = 'layermap'
# Mapping dictionaries for the models above.
co_mapping = {'name': 'Name',
'state': {'name': 'State'}, # ForeignKey's use another mapping dictionary for the _related_ Model (State in this case).

View File

@ -2,21 +2,28 @@ from django.contrib.gis.db import models
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible
class Location(models.Model):
point = models.PointField()
class SimpleModel(models.Model):
objects = models.GeoManager()
class Meta:
abstract = True
app_label = 'relatedapp'
@python_2_unicode_compatible
class Location(SimpleModel):
point = models.PointField()
def __str__(self):
return self.point.wkt
@python_2_unicode_compatible
class City(models.Model):
class City(SimpleModel):
name = models.CharField(max_length=50)
state = models.CharField(max_length=2)
location = models.ForeignKey(Location)
objects = models.GeoManager()
def __str__(self):
return self.name
@ -24,17 +31,20 @@ class City(models.Model):
class AugmentedLocation(Location):
extra_text = models.TextField(blank=True)
objects = models.GeoManager()
class Meta:
app_label = 'relatedapp'
class DirectoryEntry(models.Model):
class DirectoryEntry(SimpleModel):
listing_text = models.CharField(max_length=50)
location = models.ForeignKey(AugmentedLocation)
objects = models.GeoManager()
@python_2_unicode_compatible
class Parcel(models.Model):
class Parcel(SimpleModel):
name = models.CharField(max_length=30)
city = models.ForeignKey(City)
center1 = models.PointField()
@ -42,26 +52,22 @@ class Parcel(models.Model):
center2 = models.PointField(srid=2276, db_column='mycenter')
border1 = models.PolygonField()
border2 = models.PolygonField(srid=2276)
objects = models.GeoManager()
def __str__(self):
return self.name
# These use the GeoManager but do not have any geographic fields.
class Author(models.Model):
class Author(SimpleModel):
name = models.CharField(max_length=100)
dob = models.DateField()
objects = models.GeoManager()
class Article(models.Model):
class Article(SimpleModel):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author, unique=True)
objects = models.GeoManager()
class Book(models.Model):
class Book(SimpleModel):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author, related_name='books', null=True)
objects = models.GeoManager()

View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class HumanizeConfig(AppConfig):
name = 'django.contrib.humanize'
verbose_name = _("humanize")

View File

@ -11,8 +11,8 @@ except ImportError:
from django.conf import settings
from django.contrib.humanize.templatetags import humanize
from django.template import Template, Context, defaultfilters
from django.test import TestCase
from django.test.utils import override_settings, TransRealMixin
from django.test import TestCase, override_settings
from django.test.utils import TransRealMixin
from django.utils.html import escape
from django.utils.timezone import utc, get_fixed_timezone
from django.utils import translation

View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class MessagesConfig(AppConfig):
name = 'django.contrib.messages'
verbose_name = _("messages")

View File

@ -1,8 +1,12 @@
from django.conf import settings
from django.utils.module_loading import import_by_path as get_storage
from django.utils.module_loading import import_by_path
# Callable with the same interface as the storage classes i.e. accepts a
# 'request' object. It is wrapped in a lambda to stop 'settings' being used at
# the module level
default_storage = lambda request: get_storage(settings.MESSAGE_STORAGE)(request)
def default_storage(request):
"""
Callable with the same interface as the storage classes.
This isn't just default_storage = import_by_path(settings.MESSAGE_STORAGE)
to avoid accessing the settings at the module level.
"""
return import_by_path(settings.MESSAGE_STORAGE)(request)

View File

@ -1,20 +1,21 @@
from unittest import skipIf
from unittest import skipUnless
from django import http
from django.conf import settings, global_settings
from django.apps import apps
from django.conf import global_settings
from django.contrib.messages import constants, utils, get_level, set_level
from django.contrib.messages.api import MessageFailure
from django.contrib.messages.constants import DEFAULT_LEVELS
from django.contrib.messages.storage import default_storage, base
from django.contrib.messages.storage.base import Message
from django.core.urlresolvers import reverse
from django.test.utils import override_settings
from django.test import modify_settings, override_settings
from django.utils.translation import ugettext_lazy
def skipUnlessAuthIsInstalled(func):
return skipIf(
'django.contrib.auth' not in settings.INSTALLED_APPS,
return skipUnless(
apps.is_installed('django.contrib.auth'),
"django.contrib.auth isn't installed")(func)
@ -218,16 +219,12 @@ class BaseTests(object):
for msg in data['messages']:
self.assertContains(response, msg)
@override_settings(
INSTALLED_APPS=filter(
lambda app: app != 'django.contrib.messages', settings.INSTALLED_APPS),
MIDDLEWARE_CLASSES=filter(
lambda m: 'MessageMiddleware' not in m, settings.MIDDLEWARE_CLASSES),
TEMPLATE_CONTEXT_PROCESSORS=filter(
lambda p: 'context_processors.messages' not in p,
settings.TEMPLATE_CONTEXT_PROCESSORS),
MESSAGE_LEVEL=constants.DEBUG
@modify_settings(
INSTALLED_APPS={'remove': 'django.contrib.messages'},
MIDDLEWARE_CLASSES={'remove': 'django.contrib.messages.middleware.MessageMiddleware'},
TEMPLATE_CONTEXT_PROCESSORS={'remove': 'django.contrib.messages.context_processors.messages'},
)
@override_settings(MESSAGE_LEVEL=constants.DEBUG)
def test_middleware_disabled(self):
"""
Tests that, when the middleware is disabled, an exception is raised
@ -243,15 +240,10 @@ class BaseTests(object):
self.assertRaises(MessageFailure, self.client.post, add_url,
data, follow=True)
@override_settings(
INSTALLED_APPS=filter(
lambda app: app != 'django.contrib.messages', settings.INSTALLED_APPS),
MIDDLEWARE_CLASSES=filter(
lambda m: 'MessageMiddleware' not in m, settings.MIDDLEWARE_CLASSES),
TEMPLATE_CONTEXT_PROCESSORS=filter(
lambda p: 'context_processors.messages' not in p,
settings.TEMPLATE_CONTEXT_PROCESSORS),
MESSAGE_LEVEL=constants.DEBUG
@modify_settings(
INSTALLED_APPS={'remove': 'django.contrib.messages'},
MIDDLEWARE_CLASSES={'remove': 'django.contrib.messages.middleware.MessageMiddleware'},
TEMPLATE_CONTEXT_PROCESSORS={'remove': 'django.contrib.messages.context_processors.messages'},
)
def test_middleware_disabled_fail_silently(self):
"""

View File

@ -5,8 +5,7 @@ from django.contrib.messages.tests.base import BaseTests
from django.contrib.messages.storage.cookie import (CookieStorage,
MessageEncoder, MessageDecoder)
from django.contrib.messages.storage.base import Message
from django.test import TestCase
from django.test.utils import override_settings
from django.test import TestCase, override_settings
from django.utils.safestring import SafeData, mark_safe

View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class RedirectsConfig(AppConfig):
name = 'django.contrib.redirects'
verbose_name = _("redirects")

View File

@ -1,5 +1,6 @@
from __future__ import unicode_literals
from django.apps import apps
from django.conf import settings
from django.contrib.redirects.models import Redirect
from django.contrib.sites.models import get_current_site
@ -14,7 +15,7 @@ class RedirectFallbackMiddleware(object):
response_redirect_class = http.HttpResponsePermanentRedirect
def __init__(self):
if 'django.contrib.sites' not in settings.INSTALLED_APPS:
if not apps.is_installed('django.contrib.sites'):
raise ImproperlyConfigured(
"You cannot use RedirectFallbackMiddleware when "
"django.contrib.sites is not installed."

View File

@ -2,20 +2,16 @@ from django import http
from django.conf import settings
from django.contrib.sites.models import Site
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase
from django.test.utils import override_settings
from django.test import TestCase, modify_settings, override_settings
from django.utils import six
from .middleware import RedirectFallbackMiddleware
from .models import Redirect
@override_settings(
APPEND_SLASH=False,
MIDDLEWARE_CLASSES=list(settings.MIDDLEWARE_CLASSES) +
['django.contrib.redirects.middleware.RedirectFallbackMiddleware'],
SITE_ID=1,
)
@modify_settings(MIDDLEWARE_CLASSES={'append':
'django.contrib.redirects.middleware.RedirectFallbackMiddleware'})
@override_settings(APPEND_SLASH=False, SITE_ID=1)
class RedirectTests(TestCase):
def setUp(self):
@ -56,9 +52,7 @@ class RedirectTests(TestCase):
response = self.client.get('/initial')
self.assertEqual(response.status_code, 410)
@override_settings(
INSTALLED_APPS=[app for app in settings.INSTALLED_APPS
if app != 'django.contrib.sites'])
@modify_settings(INSTALLED_APPS={'remove': 'django.contrib.sites'})
def test_sites_not_installed(self):
with self.assertRaises(ImproperlyConfigured):
RedirectFallbackMiddleware()
@ -70,11 +64,9 @@ class OverriddenRedirectFallbackMiddleware(RedirectFallbackMiddleware):
response_redirect_class = http.HttpResponseRedirect
@override_settings(
MIDDLEWARE_CLASSES=list(settings.MIDDLEWARE_CLASSES) +
['django.contrib.redirects.tests.OverriddenRedirectFallbackMiddleware'],
SITE_ID=1,
)
@modify_settings(MIDDLEWARE_CLASSES={'append':
'django.contrib.redirects.tests.OverriddenRedirectFallbackMiddleware'})
@override_settings(SITE_ID=1)
class OverriddenRedirectMiddlewareTests(TestCase):
def setUp(self):

View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class SessionsConfig(AppConfig):
name = 'django.contrib.sessions'
verbose_name = _("sessions")

View File

@ -20,8 +20,8 @@ from django.core.cache.backends.base import InvalidCacheBackendError
from django.core import management
from django.core.exceptions import ImproperlyConfigured
from django.http import HttpResponse
from django.test import TestCase, RequestFactory
from django.test.utils import override_settings, patch_logger
from django.test import TestCase, RequestFactory, override_settings
from django.test.utils import patch_logger
from django.utils import six
from django.utils import timezone

View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class SiteMapsConfig(AppConfig):
name = 'django.contrib.sitemaps'
verbose_name = _("site maps")

View File

@ -0,0 +1,22 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-01-04 23:05+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: apps.py:8
msgid "site maps"
msgstr ""

View File

@ -25,10 +25,6 @@ class SitemapTestsBase(TestCase):
def setUp(self):
self.base_url = '%s://%s' % (self.protocol, self.domain)
self._old_installed = Site._meta.app_config.installed
cache.clear()
# Create an object for sitemap content.
TestModel.objects.create(name='Test Object')
def tearDown(self):
Site._meta.app_config.installed = self._old_installed

View File

@ -2,6 +2,7 @@ from __future__ import unicode_literals
from unittest import skipUnless
from django.apps import apps
from django.conf import settings
from .base import SitemapTestsBase
@ -9,7 +10,7 @@ from .base import SitemapTestsBase
class FlatpagesSitemapTests(SitemapTestsBase):
@skipUnless("django.contrib.flatpages" in settings.INSTALLED_APPS,
@skipUnless(apps.is_installed('django.contrib.flatpages'),
"django.contrib.flatpages app not installed.")
def test_flatpage_sitemap(self):
"Basic FlatPage sitemap test"

View File

@ -1,6 +1,6 @@
from __future__ import unicode_literals
from django.test.utils import override_settings
from django.test import override_settings
from .base import TestModel, SitemapTestsBase

View File

@ -4,11 +4,12 @@ import os
from datetime import date
from unittest import skipUnless
from django.apps import apps
from django.conf import settings
from django.contrib.sitemaps import Sitemap, GenericSitemap
from django.contrib.sites.models import Site
from django.core.exceptions import ImproperlyConfigured
from django.test.utils import override_settings
from django.test import modify_settings, override_settings
from django.utils.formats import localize
from django.utils._os import upath
from django.utils.translation import activate, deactivate
@ -105,11 +106,10 @@ class HTTPSitemapTests(SitemapTestsBase):
self.assertContains(response, '<lastmod>%s</lastmod>' % date.today())
deactivate()
@modify_settings(INSTALLED_APPS={'remove': 'django.contrib.sites'})
def test_requestsite_sitemap(self):
# Make sure hitting the flatpages sitemap without the sites framework
# installed doesn't raise an exception.
# Reset by SitemapTestsBase.tearDown().
Site._meta.app_config.installed = False
response = self.client.get('/simple/sitemap.xml')
expected_content = """<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
@ -118,7 +118,7 @@ class HTTPSitemapTests(SitemapTestsBase):
""" % date.today()
self.assertXMLEqual(response.content.decode('utf-8'), expected_content)
@skipUnless("django.contrib.sites" in settings.INSTALLED_APPS,
@skipUnless(apps.is_installed('django.contrib.sites'),
"django.contrib.sites app not installed.")
def test_sitemap_get_urls_no_site_1(self):
"""
@ -128,14 +128,13 @@ class HTTPSitemapTests(SitemapTestsBase):
Site.objects.all().delete()
self.assertRaises(ImproperlyConfigured, Sitemap().get_urls)
@modify_settings(INSTALLED_APPS={'remove': 'django.contrib.sites'})
def test_sitemap_get_urls_no_site_2(self):
"""
Check we get ImproperlyConfigured when we don't pass a site object to
Sitemap.get_urls if Site objects exists, but the sites framework is not
actually installed.
"""
# Reset by SitemapTestsBase.tearDown().
Site._meta.app_config.installed = False
self.assertRaises(ImproperlyConfigured, Sitemap().get_urls)
def test_sitemap_item(self):

View File

@ -2,7 +2,7 @@ from __future__ import unicode_literals
from datetime import date
from django.test.utils import override_settings
from django.test import override_settings
from .base import SitemapTestsBase

View File

@ -0,0 +1,8 @@
from django.apps import AppConfig
from django.utils.translation import ugettext_lazy as _
class SitesConfig(AppConfig):
name = 'django.contrib.sites'
verbose_name = _("sites")

Some files were not shown because too many files have changed in this diff Show More