From 4cfd3203a67cd6e1fccccab5c85da5551814d2ee Mon Sep 17 00:00:00 2001 From: Christopher Long Date: Mon, 14 Aug 2006 18:52:03 +0000 Subject: [per-object-permissions] Merged to revision 3582 git-svn-id: http://code.djangoproject.com/svn/django/branches/per-object-permissions@3583 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/core/management.py | 60 ++++++++++++++++++++++++++++------------- django/core/serializers/json.py | 6 ++--- django/core/servers/basehttp.py | 4 --- django/core/urlresolvers.py | 60 ++++++++++++++++++++++++++--------------- 4 files changed, 84 insertions(+), 46 deletions(-) (limited to 'django/core') diff --git a/django/core/management.py b/django/core/management.py index 14182cbdff..a469c72901 100644 --- a/django/core/management.py +++ b/django/core/management.py @@ -94,12 +94,15 @@ def get_sql_create(app): "Edit your settings file and change DATABASE_ENGINE to something like 'postgresql' or 'mysql'.\n")) sys.exit(1) - # Get installed models, so we generate REFERENCES right + # Get installed models, so we generate REFERENCES right. + # We trim models from the current app so that the sqlreset command does not + # generate invalid SQL (leaving models out of known_models is harmless, so + # we can be conservative). + app_models = models.get_models(app) final_output = [] - known_models = set(_get_installed_models(_get_table_list())) + known_models = set([model for model in _get_installed_models(_get_table_list()) if model not in app_models]) pending_references = {} - app_models = models.get_models(app) for model in app_models: output, references = _get_sql_model_create(model, known_models) @@ -118,10 +121,13 @@ def get_sql_create(app): # but don't exist physically not_installed_models = set(pending_references.keys()) if not_installed_models: - final_output.append('-- The following references should be added but depend on non-existant tables:') + alter_sql = [] for model in not_installed_models: - final_output.extend(['-- ' + sql for sql in + alter_sql.extend(['-- ' + sql for sql in _get_sql_for_pending_references(model, pending_references)]) + if alter_sql: + final_output.append('-- The following references should be added but depend on non-existent tables:') + final_output.extend(alter_sql) return final_output get_sql_create.help_doc = "Prints the CREATE TABLE SQL statements for the given app name(s)." @@ -192,7 +198,6 @@ def _get_sql_for_pending_references(model, pending_references): data_types = get_creation_module().DATA_TYPES final_output = [] - reference_names = {} if backend.supports_constraints: opts = model._meta if model in pending_references: @@ -202,12 +207,9 @@ def _get_sql_for_pending_references(model, pending_references): r_col = f.column table = opts.db_table col = opts.get_field(f.rel.field_name).column - r_name = '%s_referencing_%s_%s' % (r_col, table, col) - if r_name in reference_names: - reference_names[r_name] += 1 - r_name += '_%s' % reference_names[r_name] - else: - reference_names[r_name] = 0 + # For MySQL, r_name must be unique in the first 64 characters. + # So we are careful with character usage here. + r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table)))) final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \ (backend.quote_name(r_table), r_name, backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col))) @@ -299,7 +301,7 @@ def get_sql_delete(app): (style.SQL_KEYWORD('ALTER TABLE'), style.SQL_TABLE(backend.quote_name(table)), style.SQL_KEYWORD(backend.get_drop_foreignkey_sql()), - style.SQL_FIELD(backend.quote_name("%s_referencing_%s_%s" % (col, r_table, r_col))))) + style.SQL_FIELD(backend.quote_name('%s_refs_%s_%x' % (col, r_col, abs(hash((table, r_table)))))))) del references_to_delete[model] # Output DROP TABLE statements for many-to-many tables. @@ -696,9 +698,7 @@ def inspectdb(): introspection_module = get_introspection_module() - def table2model(table_name): - object_name = table_name.title().replace('_', '') - return object_name.endswith('s') and object_name[:-1] or object_name + table2model = lambda table_name: table_name.title().replace('_', '') cursor = connection.cursor() yield "# This is an auto-generated Django model module." @@ -727,6 +727,10 @@ def inspectdb(): comment_notes = [] # Holds Field notes, to be displayed in a Python comment. extra_params = {} # Holds Field parameters such as 'db_column'. + if ' ' in att_name: + extra_params['db_column'] = att_name + att_name = att_name.replace(' ', '') + comment_notes.append('Field renamed to remove spaces.') if keyword.iskeyword(att_name): extra_params['db_column'] = att_name att_name += '_field' @@ -957,6 +961,12 @@ def get_validation_errors(outfile, app=None): f = opts.get_field(fn) except models.FieldDoesNotExist: e.add(opts, '"admin.list_filter" refers to %r, which isn\'t a field.' % fn) + # date_hierarchy + if opts.admin.date_hierarchy: + try: + f = opts.get_field(opts.admin.date_hierarchy) + except models.FieldDoesNotExist: + e.add(opts, '"admin.date_hierarchy" refers to %r, which isn\'t a field.' % opts.admin.date_hierarchy) # Check ordering attribute. if opts.ordering: @@ -1132,7 +1142,14 @@ def dbshell(): dbshell.args = "" def runfcgi(args): - """Run this project as a FastCGI application. requires flup.""" + "Runs this project as a FastCGI application. Requires flup." + from django.conf import settings + from django.utils import translation + # Activate the current language, because it won't get activated later. + try: + translation.activate(settings.LANGUAGE_CODE) + except AttributeError: + pass from django.core.servers.fastcgi import runfastcgi runfastcgi(args) runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]' @@ -1289,7 +1306,11 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None): if action not in NO_SQL_TRANSACTION: print style.SQL_KEYWORD("COMMIT;") -def execute_manager(settings_mod, argv=None): +def setup_environ(settings_mod): + """ + Configure the runtime environment. This can also be used by external + scripts wanting to set up a similar environment to manage.py. + """ # Add this project to sys.path so that it's importable in the conventional # way. For example, if this file (manage.py) lives in a directory # "myproject", this code would add "/path/to/myproject" to sys.path. @@ -1301,7 +1322,10 @@ def execute_manager(settings_mod, argv=None): # Set DJANGO_SETTINGS_MODULE appropriately. os.environ['DJANGO_SETTINGS_MODULE'] = '%s.settings' % project_name + return project_directory +def execute_manager(settings_mod, argv=None): + project_directory = setup_environ(settings_mod) action_mapping = DEFAULT_ACTION_MAPPING.copy() # Remove the "startproject" command from the action_mapping, because that's diff --git a/django/core/serializers/json.py b/django/core/serializers/json.py index dd6513db57..a8b4259099 100644 --- a/django/core/serializers/json.py +++ b/django/core/serializers/json.py @@ -41,11 +41,11 @@ class DateTimeAwareJSONEncoder(simplejson.JSONEncoder): TIME_FORMAT = "%H:%M:%S" def default(self, o): - if isinstance(o, datetime.date): + if isinstance(o, datetime.datetime): + return o.strftime("%s %s" % (self.DATE_FORMAT, self.TIME_FORMAT)) + elif isinstance(o, datetime.date): return o.strftime(self.DATE_FORMAT) elif isinstance(o, datetime.time): return o.strftime(self.TIME_FORMAT) - elif isinstance(o, datetime.datetime): - return o.strftime("%s %s" % (self.DATE_FORMAT, self.TIME_FORMAT)) else: return super(self, DateTimeAwareJSONEncoder).default(o) \ No newline at end of file diff --git a/django/core/servers/basehttp.py b/django/core/servers/basehttp.py index 7ce5706c23..4bd0e50e53 100644 --- a/django/core/servers/basehttp.py +++ b/django/core/servers/basehttp.py @@ -547,10 +547,6 @@ class WSGIRequestHandler(BaseHTTPRequestHandler): env['PATH_INFO'] = urllib.unquote(path) env['QUERY_STRING'] = query - - host = self.address_string() - if host != self.client_address[0]: - env['REMOTE_HOST'] = host env['REMOTE_ADDR'] = self.client_address[0] if self.headers.typeheader is None: diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py index 83fffacefb..2f557b90a6 100644 --- a/django/core/urlresolvers.py +++ b/django/core/urlresolvers.py @@ -86,10 +86,15 @@ class MatchChecker(object): class RegexURLPattern(object): def __init__(self, regex, callback, default_args=None): # regex is a string representing a regular expression. - # callback is something like 'foo.views.news.stories.story_detail', - # which represents the path to a module and a view function name. + # callback is either a string like 'foo.views.news.stories.story_detail' + # which represents the path to a module and a view function name, or a + # callable object (view). self.regex = re.compile(regex) - self.callback = callback + if callable(callback): + self._callback = callback + else: + self._callback = None + self._callback_str = callback self.default_args = default_args or {} def resolve(self, path): @@ -106,23 +111,28 @@ class RegexURLPattern(object): # In both cases, pass any extra_kwargs as **kwargs. kwargs.update(self.default_args) - try: # Lazily load self.func. - return self.func, args, kwargs - except AttributeError: - self.func = self.get_callback() - return self.func, args, kwargs + return self.callback, args, kwargs - def get_callback(self): - mod_name, func_name = get_mod_func(self.callback) + def _get_callback(self): + if self._callback is not None: + return self._callback + mod_name, func_name = get_mod_func(self._callback_str) try: - return getattr(__import__(mod_name, '', '', ['']), func_name) + self._callback = getattr(__import__(mod_name, '', '', ['']), func_name) except ImportError, e: raise ViewDoesNotExist, "Could not import %s. Error was: %s" % (mod_name, str(e)) except AttributeError, e: raise ViewDoesNotExist, "Tried %s in module %s. Error was: %s" % (func_name, mod_name, str(e)) + return self._callback + callback = property(_get_callback) def reverse(self, viewname, *args, **kwargs): - if viewname != self.callback: + mod_name, func_name = get_mod_func(viewname) + try: + lookup_view = getattr(__import__(mod_name, '', '', ['']), func_name) + except (ImportError, AttributeError): + raise NoReverseMatch + if lookup_view != self.callback: raise NoReverseMatch return self.reverse_helper(*args, **kwargs) @@ -130,12 +140,13 @@ class RegexURLPattern(object): return reverse_helper(self.regex, *args, **kwargs) class RegexURLResolver(object): - def __init__(self, regex, urlconf_name): + def __init__(self, regex, urlconf_name, default_kwargs=None): # regex is a string representing a regular expression. # urlconf_name is a string representing the module containing urlconfs. self.regex = re.compile(regex) self.urlconf_name = urlconf_name self.callback = None + self.default_kwargs = default_kwargs or {} def resolve(self, path): tried = [] @@ -149,7 +160,8 @@ class RegexURLResolver(object): tried.extend([(pattern.regex.pattern + ' ' + t) for t in e.args[0]['tried']]) else: if sub_match: - return sub_match[0], sub_match[1], dict(match.groupdict(), **sub_match[2]) + sub_match_dict = dict(self.default_kwargs, **sub_match[2]) + return sub_match[0], sub_match[1], dict(match.groupdict(), **sub_match_dict) tried.append(pattern.regex.pattern) raise Resolver404, {'tried': tried, 'path': new_path} @@ -183,22 +195,28 @@ class RegexURLResolver(object): def resolve500(self): return self._resolve_special('500') - def reverse(self, viewname, *args, **kwargs): + def reverse(self, lookup_view, *args, **kwargs): + if not callable(lookup_view): + mod_name, func_name = get_mod_func(lookup_view) + try: + lookup_view = getattr(__import__(mod_name, '', '', ['']), func_name) + except (ImportError, AttributeError): + raise NoReverseMatch for pattern in self.urlconf_module.urlpatterns: if isinstance(pattern, RegexURLResolver): try: - return pattern.reverse_helper(viewname, *args, **kwargs) + return pattern.reverse_helper(lookup_view, *args, **kwargs) except NoReverseMatch: continue - elif pattern.callback == viewname: + elif pattern.callback == lookup_view: try: return pattern.reverse_helper(*args, **kwargs) except NoReverseMatch: continue raise NoReverseMatch - def reverse_helper(self, viewname, *args, **kwargs): - sub_match = self.reverse(viewname, *args, **kwargs) + def reverse_helper(self, lookup_view, *args, **kwargs): + sub_match = self.reverse(lookup_view, *args, **kwargs) result = reverse_helper(self.regex, *args, **kwargs) return result + sub_match @@ -209,11 +227,11 @@ def resolve(path, urlconf=None): resolver = RegexURLResolver(r'^/', urlconf) return resolver.resolve(path) -def reverse(viewname, urlconf, args=None, kwargs=None): +def reverse(viewname, urlconf=None, args=None, kwargs=None): args = args or [] kwargs = kwargs or {} if urlconf is None: from django.conf import settings urlconf = settings.ROOT_URLCONF resolver = RegexURLResolver(r'^/', urlconf) - return resolver.reverse(viewname, *args, **kwargs) + return '/' + resolver.reverse(viewname, *args, **kwargs) -- cgit v1.3