Django

Code

Show
Ignore:
Timestamp:
07/19/08 08:30:47 (6 months ago)
Author:
jbronn
Message:

gis: Merged revisions 7921,7926-7928,7938-7941,7945-7947,7949-7950,7952,7955-7956,7961,7964-7968,7970-7978 via svnmerge from trunk.

This includes the newforms-admin branch, and thus is backwards-incompatible. The geographic admin is _not_ in this changeset, and is forthcoming.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/gis

    • Property svnmerge-integrated changed from /django/trunk:1-7917 to /django/trunk:1-7978
  • django/branches/gis/django/views/debug.py

    r7918 r7979  
    1919        p = template_source.find('\n', p+1) 
    2020    yield len(template_source) + 1 
    21  
    22 def get_template_exception_info(exc_type, exc_value, tb): 
    23     origin, (start, end) = exc_value.source 
    24     template_source = origin.reload() 
    25     context_lines = 10 
    26     line = 0 
    27     upto = 0 
    28     source_lines = [] 
    29     before = during = after = "" 
    30     for num, next in enumerate(linebreak_iter(template_source)): 
    31         if start >= upto and end <= next: 
    32             line = num 
    33             before = escape(template_source[upto:start]) 
    34             during = escape(template_source[start:end]) 
    35             after = escape(template_source[end:next]) 
    36         source_lines.append( (num, escape(template_source[upto:next])) ) 
    37         upto = next 
    38     total = len(source_lines) 
    39  
    40     top = max(1, line - context_lines) 
    41     bottom = min(total, line + 1 + context_lines) 
    42  
    43     template_info = { 
    44         'message': exc_value.args[0], 
    45         'source_lines': source_lines[top:bottom], 
    46         'before': before, 
    47         'during': during, 
    48         'after': after, 
    49         'top': top, 
    50         'bottom': bottom, 
    51         'total': total, 
    52         'line': line, 
    53         'name': origin.name, 
    54     } 
    55     exc_info = hasattr(exc_value, 'exc_info') and exc_value.exc_info or (exc_type, exc_value, tb) 
    56     return exc_info + (template_info,) 
    5721 
    5822def get_safe_settings(): 
     
    7236    the values returned from sys.exc_info() and friends. 
    7337    """ 
    74     html = get_traceback_html(request, exc_type, exc_value, tb) 
     38    reporter = ExceptionReporter(request, exc_type, exc_value, tb) 
     39    html = reporter.get_traceback_html() 
    7540    return HttpResponseServerError(html, mimetype='text/html') 
    7641 
    77 def get_traceback_html(request, exc_type, exc_value, tb): 
    78     "Return HTML code for traceback." 
    79     template_info = None 
    80     template_does_not_exist = False 
    81     loader_debug_info = None 
    82  
    83     # Handle deprecated string exceptions 
    84     if isinstance(exc_type, basestring): 
    85         exc_value = Exception('Deprecated String Exception: %r' % exc_type) 
    86         exc_type = type(exc_value) 
    87  
    88     if issubclass(exc_type, TemplateDoesNotExist): 
    89         from django.template.loader import template_source_loaders 
    90         template_does_not_exist = True 
    91         loader_debug_info = [] 
    92         for loader in template_source_loaders: 
     42class ExceptionReporter: 
     43    """ 
     44    A class to organize and coordinate reporting on exceptions. 
     45    """ 
     46    def __init__(self, request, exc_type, exc_value, tb): 
     47        self.request = request 
     48        self.exc_type = exc_type 
     49        self.exc_value = exc_value 
     50        self.tb = tb 
     51 
     52        self.template_info = None 
     53        self.template_does_not_exist = False 
     54        self.loader_debug_info = None 
     55 
     56        # Handle deprecated string exceptions 
     57        if isinstance(self.exc_type, basestring): 
     58            self.exc_value = Exception('Deprecated String Exception: %r' % self.exc_type) 
     59            self.exc_type = type(self.exc_value) 
     60 
     61    def get_traceback_html(self): 
     62        "Return HTML code for traceback." 
     63 
     64        if issubclass(self.exc_type, TemplateDoesNotExist): 
     65            from django.template.loader import template_source_loaders 
     66            self.template_does_not_exist = True 
     67            self.loader_debug_info = [] 
     68            for loader in template_source_loaders: 
     69                try: 
     70                    source_list_func = getattr(__import__(loader.__module__, {}, {}, ['get_template_sources']), 'get_template_sources') 
     71                    # NOTE: This assumes exc_value is the name of the template that 
     72                    # the loader attempted to load. 
     73                    template_list = [{'name': t, 'exists': os.path.exists(t)} \ 
     74                        for t in source_list_func(str(self.exc_value))] 
     75                except (ImportError, AttributeError): 
     76                    template_list = [] 
     77                self.loader_debug_info.append({ 
     78                    'loader': loader.__module__ + '.' + loader.__name__, 
     79                    'templates': template_list, 
     80                }) 
     81        if settings.TEMPLATE_DEBUG and hasattr(self.exc_value, 'source'): 
     82            self.get_template_exception_info() 
     83 
     84        frames = self.get_traceback_frames() 
     85 
     86        unicode_hint = '' 
     87        if issubclass(self.exc_type, UnicodeError): 
     88            start = getattr(self.exc_value, 'start', None) 
     89            end = getattr(self.exc_value, 'end', None) 
     90            if start is not None and end is not None: 
     91                unicode_str = self.exc_value.args[1] 
     92                unicode_hint = smart_unicode(unicode_str[max(start-5, 0):min(end+5, len(unicode_str))], 'ascii', errors='replace') 
     93        from django import get_version 
     94        t = Template(TECHNICAL_500_TEMPLATE, name='Technical 500 template') 
     95        c = Context({ 
     96            'exception_type': self.exc_type.__name__, 
     97            'exception_value': smart_unicode(self.exc_value, errors='replace'), 
     98            'unicode_hint': unicode_hint, 
     99            'frames': frames, 
     100            'lastframe': frames[-1], 
     101            'request': self.request, 
     102            'request_protocol': self.request.is_secure() and "https" or "http", 
     103            'settings': get_safe_settings(), 
     104            'sys_executable': sys.executable, 
     105            'sys_version_info': '%d.%d.%d' % sys.version_info[0:3], 
     106            'server_time': datetime.datetime.now(), 
     107            'django_version_info': get_version(), 
     108            'sys_path' : sys.path, 
     109            'template_info': self.template_info, 
     110            'template_does_not_exist': self.template_does_not_exist, 
     111            'loader_debug_info': self.loader_debug_info, 
     112        }) 
     113        return t.render(c) 
     114 
     115    def get_template_exception_info(self): 
     116        origin, (start, end) = self.exc_value.source 
     117        template_source = origin.reload() 
     118        context_lines = 10 
     119        line = 0 
     120        upto = 0 
     121        source_lines = [] 
     122        before = during = after = "" 
     123        for num, next in enumerate(linebreak_iter(template_source)): 
     124            if start >= upto and end <= next: 
     125                line = num 
     126                before = escape(template_source[upto:start]) 
     127                during = escape(template_source[start:end]) 
     128                after = escape(template_source[end:next]) 
     129            source_lines.append( (num, escape(template_source[upto:next])) ) 
     130            upto = next 
     131        total = len(source_lines) 
     132 
     133        top = max(1, line - context_lines) 
     134        bottom = min(total, line + 1 + context_lines) 
     135 
     136        self.template_info = { 
     137            'message': self.exc_value.args[0], 
     138            'source_lines': source_lines[top:bottom], 
     139            'before': before, 
     140            'during': during, 
     141            'after': after, 
     142            'top': top, 
     143            'bottom': bottom, 
     144            'total': total, 
     145            'line': line, 
     146            'name': origin.name, 
     147        } 
     148        if hasattr(self.exc_value, 'exc_info') and self.exc_value.exc_info: 
     149            exc_type, exc_value, tb = self.exc_value.exc_info 
     150 
     151    def _get_lines_from_file(self, filename, lineno, context_lines, loader=None, module_name=None): 
     152        """ 
     153        Returns context_lines before and after lineno from file. 
     154        Returns (pre_context_lineno, pre_context, context_line, post_context). 
     155        """ 
     156        source = None 
     157        if loader is not None and hasattr(loader, "get_source"): 
     158            source = loader.get_source(module_name) 
     159            if source is not None: 
     160                source = source.splitlines() 
     161        if source is None: 
    93162            try: 
    94                 source_list_func = getattr(__import__(loader.__module__, {}, {}, ['get_template_sources']), 'get_template_sources') 
    95                 # NOTE: This assumes exc_value is the name of the template that 
    96                 # the loader attempted to load. 
    97                 template_list = [{'name': t, 'exists': os.path.exists(t)} \ 
    98                     for t in source_list_func(str(exc_value))] 
    99             except (ImportError, AttributeError): 
    100                 template_list = [] 
    101             loader_debug_info.append({ 
    102                 'loader': loader.__module__ + '.' + loader.__name__, 
    103                 'templates': template_list, 
    104             }) 
    105     if settings.TEMPLATE_DEBUG and hasattr(exc_value, 'source'): 
    106         exc_type, exc_value, tb, template_info = get_template_exception_info(exc_type, exc_value, tb) 
    107     frames = [] 
    108     while tb is not None: 
    109         # support for __traceback_hide__ which is used by a few libraries 
    110         # to hide internal frames. 
    111         if tb.tb_frame.f_locals.get('__traceback_hide__'): 
     163                f = open(filename) 
     164                try: 
     165                    source = f.readlines() 
     166                finally: 
     167                    f.close() 
     168            except (OSError, IOError): 
     169                pass 
     170        if source is None: 
     171            return None, [], None, [] 
     172 
     173        encoding = 'ascii' 
     174        for line in source[:2]: 
     175            # File coding may be specified. Match pattern from PEP-263 
     176            # (http://www.python.org/dev/peps/pep-0263/) 
     177            match = re.search(r'coding[:=]\s*([-\w.]+)', line) 
     178            if match: 
     179                encoding = match.group(1) 
     180                break 
     181        source = [unicode(sline, encoding, 'replace') for sline in source] 
     182 
     183        lower_bound = max(0, lineno - context_lines) 
     184        upper_bound = lineno + context_lines 
     185 
     186        pre_context = [line.strip('\n') for line in source[lower_bound:lineno]] 
     187        context_line = source[lineno].strip('\n') 
     188        post_context = [line.strip('\n') for line in source[lineno+1:upper_bound]] 
     189 
     190        return lower_bound, pre_context, context_line, post_context 
     191 
     192    def get_traceback_frames(self): 
     193        frames = [] 
     194        tb = self.tb 
     195        while tb is not None: 
     196            # support for __traceback_hide__ which is used by a few libraries 
     197            # to hide internal frames. 
     198            if tb.tb_frame.f_locals.get('__traceback_hide__'): 
     199                tb = tb.tb_next 
     200                continue 
     201            filename = tb.tb_frame.f_code.co_filename 
     202            function = tb.tb_frame.f_code.co_name 
     203            lineno = tb.tb_lineno - 1 
     204            loader = tb.tb_frame.f_globals.get('__loader__') 
     205            module_name = tb.tb_frame.f_globals.get('__name__') 
     206            pre_context_lineno, pre_context, context_line, post_context = self._get_lines_from_file(filename, lineno, 7, loader, module_name) 
     207            if pre_context_lineno is not None: 
     208                frames.append({ 
     209                    'tb': tb, 
     210                    'filename': filename, 
     211                    'function': function, 
     212                    'lineno': lineno + 1, 
     213                    'vars': tb.tb_frame.f_locals.items(), 
     214                    'id': id(tb), 
     215                    'pre_context': pre_context, 
     216                    'context_line': context_line, 
     217                    'post_context': post_context, 
     218                    'pre_context_lineno': pre_context_lineno + 1, 
     219                }) 
    112220            tb = tb.tb_next 
    113             continue 
    114         filename = tb.tb_frame.f_code.co_filename 
    115         function = tb.tb_frame.f_code.co_name 
    116         lineno = tb.tb_lineno - 1 
    117         loader = tb.tb_frame.f_globals.get('__loader__') 
    118         module_name = tb.tb_frame.f_globals.get('__name__') 
    119         pre_context_lineno, pre_context, context_line, post_context = _get_lines_from_file(filename, lineno, 7, loader, module_name) 
    120         if pre_context_lineno is not None: 
    121             frames.append({ 
    122                 'tb': tb, 
    123                 'filename': filename, 
    124                 'function': function, 
    125                 'lineno': lineno + 1, 
    126                 'vars': tb.tb_frame.f_locals.items(), 
    127                 'id': id(tb), 
    128                 'pre_context': pre_context, 
    129                 'context_line': context_line, 
    130                 'post_context': post_context, 
    131                 'pre_context_lineno': pre_context_lineno + 1, 
    132             }) 
    133         tb = tb.tb_next 
    134  
    135     if not frames: 
    136         frames = [{ 
    137             'filename': '&lt;unknown&gt;', 
    138             'function': '?', 
    139             'lineno': '?', 
    140         }] 
    141  
    142     unicode_hint = '' 
    143     if issubclass(exc_type, UnicodeError): 
    144         start = getattr(exc_value, 'start', None) 
    145         end = getattr(exc_value, 'end', None) 
    146         if start is not None and end is not None: 
    147             unicode_str = exc_value.args[1] 
    148             unicode_hint = smart_unicode(unicode_str[max(start-5, 0):min(end+5, len(unicode_str))], 'ascii', errors='replace') 
    149     from django import get_version 
    150     t = Template(TECHNICAL_500_TEMPLATE, name='Technical 500 template') 
    151     c = Context({ 
    152         'exception_type': exc_type.__name__, 
    153         'exception_value': smart_unicode(exc_value, errors='replace'), 
    154         'unicode_hint': unicode_hint, 
    155         'frames': frames, 
    156         'lastframe': frames[-1], 
    157         'request': request, 
    158         'request_protocol': request.is_secure() and "https" or "http", 
    159         'settings': get_safe_settings(), 
    160         'sys_executable': sys.executable, 
    161         'sys_version_info': '%d.%d.%d' % sys.version_info[0:3], 
    162         'server_time': datetime.datetime.now(), 
    163         'django_version_info': get_version(), 
    164         'sys_path' : sys.path, 
    165         'template_info': template_info, 
    166         'template_does_not_exist': template_does_not_exist, 
    167         'loader_debug_info': loader_debug_info, 
    168     }) 
    169     return t.render(c) 
     221 
     222        if not frames: 
     223            frames = [{ 
     224                'filename': '&lt;unknown&gt;', 
     225                'function': '?', 
     226                'lineno': '?', 
     227                'context_line': '???', 
     228            }] 
     229 
     230        return frames 
     231 
     232    def format_exception(self): 
     233        """ 
     234        Return the same data as from traceback.format_exception. 
     235        """ 
     236        import traceback 
     237        frames = self.get_traceback_frames() 
     238        tb = [ (f['filename'], f['lineno'], f['function'], f['context_line']) for f in frames ] 
     239        list = ['Traceback (most recent call last):\n'] 
     240        list += traceback.format_list(tb) 
     241        list += traceback.format_exception_only(self.exc_type, self.exc_value) 
     242        return list 
     243 
    170244 
    171245def technical_404_response(request, exception): 
     
    199273    }) 
    200274    return HttpResponse(t.render(c), mimetype='text/html') 
    201  
    202 def _get_lines_from_file(filename, lineno, context_lines, loader=None, module_name=None): 
    203     """ 
    204     Returns context_lines before and after lineno from file. 
    205     Returns (pre_context_lineno, pre_context, context_line, post_context). 
    206     """ 
    207     source = None 
    208     if loader is not None and hasattr(loader, "get_source"): 
    209         source = loader.get_source(module_name) 
    210         if source is not None: 
    211             source = source.splitlines() 
    212     if source is None: 
    213         try: 
    214             f = open(filename) 
    215             try: 
    216                 source = f.readlines() 
    217             finally: 
    218                 f.close() 
    219         except (OSError, IOError): 
    220             pass 
    221     if source is None: 
    222         return None, [], None, [] 
    223  
    224     encoding = 'ascii' 
    225     for line in source[:2]: 
    226         # File coding may be specified. Match pattern from PEP-263 
    227         # (http://www.python.org/dev/peps/pep-0263/) 
    228         match = re.search(r'coding[:=]\s*([-\w.]+)', line) 
    229         if match: 
    230             encoding = match.group(1) 
    231             break 
    232     source = [unicode(sline, encoding, 'replace') for sline in source] 
    233  
    234     lower_bound = max(0, lineno - context_lines) 
    235     upper_bound = lineno + context_lines 
    236  
    237     pre_context = [line.strip('\n') for line in source[lower_bound:lineno]] 
    238     context_line = source[lineno].strip('\n') 
    239     post_context = [line.strip('\n') for line in source[lineno+1:upper_bound]] 
    240  
    241     return lower_bound, pre_context, context_line, post_context 
    242275 
    243276# 
  • django/branches/gis/django/views/generic/create_update.py

    r6018 r7979  
     1from django.forms.models import ModelFormMetaclass, ModelForm 
     2from django.template import RequestContext, loader 
     3from django.http import Http404, HttpResponse, HttpResponseRedirect 
    14from django.core.xheaders import populate_xheaders 
    2 from django.template import loader 
    3 from django import oldforms 
    4 from django.db.models import FileField 
    5 from django.contrib.auth.views import redirect_to_login 
    6 from django.template import RequestContext 
    7 from django.http import Http404, HttpResponse, HttpResponseRedirect 
    85from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured 
    96from django.utils.translation import ugettext 
    10  
    11 def create_object(request, model, template_name=None, 
     7from django.contrib.auth.views import redirect_to_login 
     8from django.views.generic import GenericViewError 
     9 
     10def deprecate_follow(follow): 
     11    """ 
     12    Issues a DeprecationWarning if follow is anything but None. 
     13 
     14    The old Manipulator-based forms used a follow argument that is no longer 
     15    needed for newforms-based forms. 
     16    """ 
     17    if follow is not None: 
     18        import warning 
     19        msg = ("Generic views have been changed to use newforms, and the" 
     20               "'follow' argument is no longer used.  Please update your code" 
     21               "to not use the 'follow' argument.") 
     22        warning.warn(msg, DeprecationWarning, stacklevel=3) 
     23 
     24def apply_extra_context(extra_context, context): 
     25    """ 
     26    Adds items from extra_context dict to context.  If a value in extra_context 
     27    is callable, then it is called and the result is added to context. 
     28    """ 
     29    for key, value in extra_context.iteritems(): 
     30        if callable(value): 
     31            context[key] = value() 
     32        else: 
     33            context[key] = value 
     34 
     35def get_model_and_form_class(model, form_class): 
     36    """ 
     37    Returns a model and form class based on the model and form_class 
     38    parameters that were passed to the generic view. 
     39 
     40    If ``form_class`` is given then its associated model will be returned along 
     41    with ``form_class`` itself.  Otherwise, if ``model`` is given, ``model`` 
     42    itself will be returned along with a ``ModelForm`` class created from 
     43    ``model``. 
     44    """ 
     45    if form_class: 
     46        return form_class._meta.model, form_class 
     47    if model: 
     48        # The inner Meta class fails if model = model is used for some reason. 
     49        tmp_model = model 
     50        # TODO: we should be able to construct a ModelForm without creating 
     51        # and passing in a temporary inner class. 
     52        class Meta: 
     53            model = tmp_model 
     54        class_name = model.__name__ + 'Form' 
     55        form_class = ModelFormMetaclass(class_name, (ModelForm,), {'Meta': Meta}) 
     56        return model, form_class 
     57    raise GenericViewError("Generic view must be called with either a model or" 
     58                           " form_class argument.") 
     59 
     60def redirect(post_save_redirect, obj): 
     61    """ 
     62    Returns a HttpResponseRedirect to ``post_save_redirect``. 
     63 
     64    ``post_save_redirect`` should be a string, and can contain named string- 
     65    substitution place holders of ``obj`` field names. 
     66 
     67    If ``post_save_redirect`` is None, then redirect to ``obj``'s URL returned 
     68    by ``get_absolute_url()``.  If ``obj`` has no ``get_absolute_url`` method, 
     69    then raise ImproperlyConfigured. 
     70 
     71    This function is meant to handle the post_save_redirect parameter to the 
     72    ``create_object`` and ``update_object`` views. 
     73    """ 
     74    if post_save_redirect: 
     75        return HttpResponseRedirect(post_save_redirect % obj.__dict__) 
     76    elif hasattr(obj, 'get_absolute_url'): 
     77        return HttpResponseRedirect(obj.get_absolute_url()) 
     78    else: 
     79        raise ImproperlyConfigured( 
     80            "No URL to redirect to.  Either pass a post_save_redirect" 
     81            " parameter to the generic view or define a get_absolute_url" 
     82            " method on the Model.") 
     83 
     84def lookup_object(model, object_id, slug, slug_field): 
     85    """ 
     86    Return the ``model`` object with the passed ``object_id``.  If 
     87    ``object_id`` is None, then return the the object whose ``slug_field`` 
     88    equals the passed ``slug``.  If ``slug`` and ``slug_field`` are not passed, 
     89    then raise Http404 exception. 
     90    """ 
     91    lookup_kwargs = {} 
     92    if object_id: 
     93        lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id 
     94    elif slug and slug_field: 
     95        lookup_kwargs['%s__exact' % slug_field] = slug 
     96    else: 
     97        raise GenericViewError( 
     98            "Generic view must be called with either an object_id or a" 
     99            " slug/slug_field.") 
     100    try: 
     101        return model.objects.get(**lookup_kwargs) 
     102    except ObjectDoesNotExist: 
     103        raise Http404("No %s found for %s" 
     104                      % (model._meta.verbose_name, lookup_kwargs)) 
     105 
     106def create_object(request, model=None, template_name=None, 
    12107        template_loader=loader, extra_context=None, post_save_redirect=None, 
    13         login_required=False, follow=None, context_processors=None): 
     108        login_required=False, follow=None, context_processors=None, 
     109        form_class=None): 
    14110    """ 
    15111    Generic object-creation function. 
     
    18114    Context: 
    19115        form 
    20             the form wrapper for the object 
    21     """ 
     116            the form for the object 
     117    """ 
     118    deprecate_follow(follow) 
    22119    if extra_context is None: extra_context = {} 
    23120    if login_required and not request.user.is_authenticated(): 
    24121        return redirect_to_login(request.path) 
    25122 
    26     manipulator = model.AddManipulator(follow=follow) 
    27     if request.POST: 
    28         # If data was POSTed, we're trying to create a new object 
    29         new_data = request.POST.copy() 
    30  
    31         if model._meta.has_field_type(FileField): 
    32             new_data.update(request.FILES) 
    33  
    34         # Check for errors 
    35         errors = manipulator.get_validation_errors(new_data) 
    36         manipulator.do_html2python(new_data) 
    37  
    38         if not errors: 
    39             # No errors -- this means we can save the data! 
    40             new_object = manipulator.save(new_data) 
    41  
     123    model, form_class = get_model_and_form_class(model, form_class) 
     124    if request.method == 'POST': 
     125        form = form_class(request.POST, request.FILES) 
     126        if form.is_valid(): 
     127            new_object = form.save() 
    42128            if request.user.is_authenticated(): 
    43129                request.user.message_set.create(message=ugettext("The %(verbose_name)s was created successfully.") % {"verbose_name": model._meta.verbose_name}) 
    44  
    45             # Redirect to the new object: first by trying post_save_redirect, 
    46             # then by obj.get_absolute_url; fail if neither works. 
    47             if post_save_redirect: 
    48                 return HttpResponseRedirect(post_save_redirect % new_object.__dict__) 
    49             elif hasattr(new_object, 'get_absolute_url'): 
    50                 return HttpResponseRedirect(new_object.get_absolute_url()) 
    51             else: 
    52                 raise ImproperlyConfigured("No URL to redirect to from generic create view.") 
    53     else: 
    54         # No POST, so we want a brand new form without any data or errors 
    55         errors = {} 
    56         new_data = manipulator.flatten_data() 
    57  
    58     # Create the FormWrapper, template, context, response 
    59     form = oldforms.FormWrapper(manipulator, new_data, errors) 
     130            return redirect(post_save_redirect, new_object) 
     131    else: 
     132        form = form_class() 
     133 
     134    # Create the template, context, response 
    60135    if not template_name: 
    61136        template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower()) 
     
    64139        'form': form, 
    65140    }, context_processors) 
    66     for key, value in extra_context.items(): 
    67         if callable(value): 
    68             c[key] = value() 
    69         else: 
    70             c[key] = value 
     141    apply_extra_context(extra_context, c) 
    71142    return HttpResponse(t.render(c)) 
    72143 
    73 def update_object(request, model, object_id=None, slug=None, 
     144def update_object(request, model=None, object_id=None, slug=None, 
    74145        slug_field='slug', template_name=None, template_loader=loader, 
    75146        extra_context=None, post_save_redirect=None, 
    76147        login_required=False, follow=None, context_processors=None, 
    77         template_object_name='object'): 
     148        template_object_name='object', form_class=None): 
    78149    """ 
    79150    Generic object-update function. 
     
    82153    Context: 
    83154        form 
    84             the form wrapper for the object 
     155            the form for the object 
    85156        object 
    86157            the original object being edited 
    87158    """ 
     159    deprecate_follow(follow) 
    88160    if extra_context is None: extra_context = {} 
    89161    if login_required and not request.user.is_authenticated(): 
    90162        return redirect_to_login(request.path) 
    91163 
    92     # Look up the object to be edited 
    93     lookup_kwargs = {} 
    94     if object_id: 
    95         lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id 
    96     elif slug and slug_field: 
    97         lookup_kwargs['%s__exact' % slug_field] = slug 
    98     else: 
    99         raise AttributeError("Generic edit view must be called with either an object_id or a slug/slug_field") 
    100     try: 
    101         object = model.objects.get(**lookup_kwargs) 
    102     except ObjectDoesNotExist: 
    103         raise Http404, "No %s found for %s" % (model._meta.verbose_name, lookup_kwargs) 
    104  
    105     manipulator = model.ChangeManipulator(getattr(object, object._meta.pk.attname), follow=follow) 
    106  
    107     if request.POST: 
    108         new_data = request.POST.copy() 
    109         if model._meta.has_field_type(FileField): 
    110             new_data.update(request.FILES) 
    111         errors = manipulator.get_validation_errors(new_data) 
    112         manipulator.do_html2python(new_data) 
    113         if not errors: 
    114             object = manipulator.save(new_data) 
    115  
     164    model, form_class = get_model_and_form_class(model, form_class) 
     165    obj = lookup_object(model, object_id, slug, slug_field) 
     166 
     167    if request.method == 'POST': 
     168        form = form_class(request.POST, request.FILES, instance=obj) 
     169        if form.is_valid(): 
     170            obj = form.save() 
    116171            if request.user.is_authenticated(): 
    117172                request.user.message_set.create(message=ugettext("The %(verbose_name)s was updated successfully.") % {"verbose_name": model._meta.verbose_name}) 
    118  
    119             # Do a post-after-redirect so that reload works, etc. 
    120             if post_save_redirect: 
    121                 return HttpResponseRedirect(post_save_redirect % object.__dict__) 
    122             elif hasattr(object, 'get_absolute_url'): 
    123                 return HttpResponseRedirect(object.get_absolute_url()) 
    124             else: 
    125                 raise ImproperlyConfigured("No URL to redirect to from generic create view.") 
    126     else: 
    127         errors = {} 
    128         # This makes sure the form acurate represents the fields of the place. 
    129         new_data = manipulator.flatten_data() 
    130  
    131     form = oldforms.FormWrapper(manipulator, new_data, errors) 
     173            return redirect(post_save_redirect, obj) 
     174    else: 
     175        form = form_class(instance=obj) 
     176 
    132177    if not template_name: 
    133178        template_name = "%s/%s_form.html" % (model._meta.app_label, model._meta.object_name.lower()) 
     
    135180    c = RequestContext(request, { 
    136181        'form': form, 
    137         template_object_name: object
     182        template_object_name: obj
    138183    }, context_processors) 
    139     for key, value in extra_context.items(): 
    140         if callable(value): 
    141             c[key] = value() 
    142         else: 
    143             c[key] = value 
     184    apply_extra_context(extra_context, c) 
    144185    response = HttpResponse(t.render(c)) 
    145     populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname)) 
     186    populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.attname)) 
    146187    return response 
    147188 
    148 def delete_object(request, model, post_delete_redirect, 
    149         object_id=None, slug=None, slug_field='slug', template_name=None, 
    150         template_loader=loader, extra_context=None, 
    151         login_required=False, context_processors=None, template_object_name='object'): 
     189def delete_object(request, model, post_delete_redirect, object_id=None, 
     190        slug=None, slug_field='slug', template_name=None, 
     191        template_loader=loader, extra_context=None, login_required=False, 
     192        context_processors=None, template_object_name='object'): 
    152193    """ 
    153194    Generic object-delete function. 
     
    166207        return redirect_to_login(request.path) 
    167208 
    168     # Look up the object to be edited 
    169     lookup_kwargs = {} 
    170     if object_id: 
    171         lookup_kwargs['%s__exact' % model._meta.pk.name] = object_id 
    172     elif slug and slug_field: 
    173         lookup_kwargs['%s__exact' % slug_field] = slug 
    174     else: 
    175         raise AttributeError("Generic delete view must be called with either an object_id or a slug/slug_field") 
    176     try: 
    177         object = model._default_manager.get(**lookup_kwargs) 
    178     except ObjectDoesNotExist: 
    179         raise Http404, "No %s found for %s" % (model._meta.app_label, lookup_kwargs) 
     209    obj = lookup_object(model, object_id, slug, slug_field) 
    180210 
    181211    if request.method == 'POST': 
    182         object.delete() 
     212        obj.delete() 
    183213        if request.user.is_authenticated(): 
    184214            request.user.message_set.create(message=ugettext("The %(verbose_name)s was deleted.") % {"verbose_name": model._meta.verbose_name}) 
     
    189219        t = template_loader.get_template(template_name) 
    190220        c = RequestContext(request, { 
    191             template_object_name: object
     221            template_object_name: obj
    192222        }, context_processors) 
    193         for key, value in extra_context.items(): 
    194             if callable(value): 
    195                 c[key] = value() 
    196             else: 
    197                 c[key] = value 
     223        apply_extra_context(extra_context, c) 
    198224        response = HttpResponse(t.render(c)) 
    199         populate_xheaders(request, response, model, getattr(object, object._meta.pk.attname)) 
     225        populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.attname)) 
    200226        return response 
  • django/branches/gis/django/views/generic/__init__.py

    r4265 r7979  
     1class GenericViewError(Exception): 
     2    """A problem in a generic view.""" 
     3    pass