Django

Code

Changeset 3732

Show
Ignore:
Timestamp:
09/06/06 20:36:27 (2 years ago)
Author:
clong
Message:

[per-object-permissions] Merged to trunk [3731]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/per-object-permissions/AUTHORS

    r3630 r3732  
    105105    Jason McBrayer <http://www.carcosa.net/jason/> 
    106106    michael.mcewan@gmail.com 
    107     mir@noris.de 
    108107    mmarshall 
    109108    Eric Moritz <http://eric.themoritzfamily.com/> 
     
    122121    Daniel Poelzleithner <http://poelzi.org/> 
    123122    J. Rademaker 
     123    Michael Radziej <mir@noris.de> 
    124124    Brian Ray <http://brianray.chipy.org/> 
    125125    rhettg@gmail.com 
     
    127127    Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/> 
    128128    David Schein 
     129    Pete Shinners <pete@shinners.org> 
     130    SmileyChris <smileychris@gmail.com> 
    129131    sopel 
    130132    Thomas Steinacher <tom@eggdrop.ch> 
     
    139141    Geert Vanderkelen 
    140142    Milton Waddams 
     143    Dan Watson <http://theidioteque.net/> 
    141144    Rachel Willmer <http://www.willmer.com/kb/> 
    142145    wojtek 
  • django/branches/per-object-permissions/django/bin/compile-messages.py

    r3630 r3732  
    2727                os.environ['djangocompilemo'] = pf + '.mo' 
    2828                os.environ['djangocompilepo'] = pf + '.po' 
    29                 cmd = 'msgfmt -o "$djangocompilemo" "$djangocompilepo"' 
     29                if sys.platform == 'win32': # Different shell-variable syntax 
     30                    cmd = 'msgfmt -o "%djangocompilemo%" "%djangocompilepo%"' 
     31                else: 
     32                    cmd = 'msgfmt -o "$djangocompilemo" "$djangocompilepo"' 
    3033                os.system(cmd) 
    3134 
  • django/branches/per-object-permissions/django/conf/global_settings.py

    r3669 r3732  
    302302########### 
    303303 
    304 TEST_RUNNER='django.test.simple.run_tests' 
     304# The name of the method to use to invoke the test suite 
     305TEST_RUNNER = 'django.test.simple.run_tests' 
     306 
     307# The name of the database to use for testing purposes. 
     308# If None, a name of 'test_' + DATABASE_NAME will be assumed 
     309TEST_DATABASE_NAME = None 
  • django/branches/per-object-permissions/django/contrib/admin/templates/admin/change_form.html

    r3629 r3732  
    7070 
    7171</div> 
     72 
     73 
    7274{% endblock %} 
  • django/branches/per-object-permissions/django/contrib/admin/templatetags/admin_modify.py

    r3669 r3732  
    145145        fields = self.relation.editable_fields() 
    146146        self.field_mappings.fill() 
     147 
    147148        self.form_field_collection_wrappers = [FormFieldCollectionWrapper(field_mapping ,fields, i) 
    148149                                               for (i,field_mapping) in self.field_mappings.items()] 
  • django/branches/per-object-permissions/django/contrib/admin/views/doc.py

    r3630 r3732  
    329329    views = [] 
    330330    for p in urlpatterns: 
    331         if hasattr(p, 'get_callback'): 
     331        if hasattr(p, '_get_callback'): 
    332332            try: 
    333                 views.append((p.get_callback(), base + p.regex.pattern)) 
     333                views.append((p._get_callback(), base + p.regex.pattern)) 
    334334            except ViewDoesNotExist: 
    335335                continue 
    336336        elif hasattr(p, '_get_url_patterns'): 
    337             views.extend(extract_views_from_urlpatterns(p.url_patterns, base + p.regex.pattern)) 
     337            try: 
     338                patterns = p.url_patterns 
     339            except ImportError: 
     340                continue 
     341            views.extend(extract_views_from_urlpatterns(patterns, base + p.regex.pattern)) 
    338342        else: 
    339343            raise TypeError, _("%s does not appear to be a urlpattern object") % p 
  • django/branches/per-object-permissions/django/contrib/auth/models.py

    r3682 r3732  
    3434    Permissions are set globally per type of object, not per specific object instance. It is possible to say "Mary may change news stories," but it's not currently possible to say "Mary may change news stories, but only the ones she created herself" or "Mary may only change news stories that have a certain status or publication date." 
    3535 
    36     Three basic permissions -- add, create and delete -- are automatically created for each Django model. 
     36    Three basic permissions -- add, change and delete -- are automatically created for each Django model. 
    3737    """ 
    3838    name = models.CharField(_('name'), maxlength=50) 
  • django/branches/per-object-permissions/django/core/management.py

    r3669 r3732  
    502502                initial_sql = get_sql_initial_data_for_model(model) 
    503503                if initial_sql: 
    504                     print "Installing initial data for %s model" % model._meta.object_name 
     504                    if verbosity >= 2: 
     505                        print "Installing initial data for %s model" % model._meta.object_name 
    505506                    try: 
    506507                        for sql in initial_sql: 
  • django/branches/per-object-permissions/django/core/serializers/base.py

    r3237 r3732  
    1212    """Something bad happened during serialization.""" 
    1313    pass 
    14      
     14 
    1515class DeserializationError(Exception): 
    1616    """Something bad happened during deserialization.""" 
     
    2121    Abstract serializer base class. 
    2222    """ 
    23      
     23 
    2424    def serialize(self, queryset, **options): 
    2525        """ 
     
    2727        """ 
    2828        self.options = options 
    29          
     29 
    3030        self.stream = options.get("stream", StringIO()) 
    31          
     31 
    3232        self.start_serialization() 
    3333        for obj in queryset: 
     
    4545        self.end_serialization() 
    4646        return self.getvalue() 
    47      
     47 
    4848    def get_string_value(self, obj, field): 
    4949        """ 
     
    5151        """ 
    5252        if isinstance(field, models.DateTimeField): 
    53             value = getattr(obj, field.name).strftime("%Y-%m-%d %H:%M:%S") 
     53            value = getattr(obj, field.name) 
     54            if value is None: 
     55                value = '' 
     56            else: 
     57                value = value.strftime("%Y-%m-%d %H:%M:%S") 
    5458        elif isinstance(field, models.FileField): 
    5559            value = getattr(obj, "get_%s_url" % field.name, lambda: None)() 
     
    5761            value = field.flatten_data(follow=None, obj=obj).get(field.name, "") 
    5862        return str(value) 
    59      
     63 
    6064    def start_serialization(self): 
    6165        """ 
     
    6367        """ 
    6468        raise NotImplementedError 
    65      
     69 
    6670    def end_serialization(self): 
    6771        """ 
     
    6973        """ 
    7074        pass 
    71      
     75 
    7276    def start_object(self, obj): 
    7377        """ 
     
    7579        """ 
    7680        raise NotImplementedError 
    77      
     81 
    7882    def end_object(self, obj): 
    7983        """ 
     
    8185        """ 
    8286        pass 
    83      
     87 
    8488    def handle_field(self, obj, field): 
    8589        """ 
     
    8791        """ 
    8892        raise NotImplementedError 
    89      
     93 
    9094    def handle_fk_field(self, obj, field): 
    9195        """ 
     
    9397        """ 
    9498        raise NotImplementedError 
    95      
     99 
    96100    def handle_m2m_field(self, obj, field): 
    97101        """ 
     
    99103        """ 
    100104        raise NotImplementedError 
    101      
     105 
    102106    def getvalue(self): 
    103107        """ 
     
    110114    Abstract base deserializer class. 
    111115    """ 
    112      
     116 
    113117    def __init__(self, stream_or_string, **options): 
    114118        """ 
     
    124128        # and friends might fail...) 
    125129        models.get_apps() 
    126      
     130 
    127131    def __iter__(self): 
    128132        return self 
    129      
     133 
    130134    def next(self): 
    131135        """Iteration iterface -- return the next item in the stream""" 
    132136        raise NotImplementedError 
    133          
     137 
    134138class DeserializedObject(object): 
    135139    """ 
    136140    A deserialzed model. 
    137      
     141 
    138142    Basically a container for holding the pre-saved deserialized data along 
    139143    with the many-to-many data saved with the object. 
    140      
     144 
    141145    Call ``save()`` to save the object (with the many-to-many data) to the 
    142146    database; call ``save(save_m2m=False)`` to save just the object fields 
    143147    (and not touch the many-to-many stuff.) 
    144148    """ 
    145      
     149 
    146150    def __init__(self, obj, m2m_data=None): 
    147151        self.object = obj 
    148152        self.m2m_data = m2m_data 
    149          
     153 
    150154    def __repr__(self): 
    151155        return "<DeserializedObject: %s>" % str(self.object) 
    152          
     156 
    153157    def save(self, save_m2m=True): 
    154158        self.object.save() 
     
    156160            for accessor_name, object_list in self.m2m_data.items(): 
    157161                setattr(self.object, accessor_name, object_list) 
    158          
    159         # prevent a second (possibly accidental) call to save() from saving  
     162 
     163        # prevent a second (possibly accidental) call to save() from saving 
    160164        # the m2m data twice. 
    161165        self.m2m_data = None 
  • django/branches/per-object-permissions/django/core/serializers/json.py

    r3583 r3732  
    4949            return o.strftime(self.TIME_FORMAT) 
    5050        else: 
    51             return super(self, DateTimeAwareJSONEncoder).default(o) 
     51            return super(DateTimeAwareJSONEncoder, self).default(o) 
  • django/branches/per-object-permissions/django/db/backends/postgresql_psycopg2/base.py

    r3583 r3732  
    1111    from django.core.exceptions import ImproperlyConfigured 
    1212    raise ImproperlyConfigured, "Error loading psycopg2 module: %s" % e 
    13  
    14 # Register Unicode conversions 
    15 import psycopg2.extensions 
    16 psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) 
    1713 
    1814DatabaseError = Database.DatabaseError 
     
    4844            self.connection.set_isolation_level(1) # make transactions transparent to all cursors 
    4945        cursor = self.connection.cursor() 
     46        cursor.tzinfo_factory = None 
    5047        cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE]) 
    5148        if settings.DEBUG: 
     
    7269    return '"%s"' % name 
    7370 
    74 def dictfetchone(cursor): 
    75     "Returns a row from the cursor as a dict" 
    76     # TODO: cursor.dictfetchone() doesn't exist in psycopg2, 
    77     # but no Django code uses this. Safe to remove? 
    78     return cursor.dictfetchone() 
    79  
    80 def dictfetchmany(cursor, number): 
    81     "Returns a certain number of rows from a cursor as a dict" 
    82     # TODO: cursor.dictfetchmany() doesn't exist in psycopg2, 
    83     # but no Django code uses this. Safe to remove? 
    84     return cursor.dictfetchmany(number) 
    85  
    86 def dictfetchall(cursor): 
    87     "Returns all rows from a cursor as a dict" 
    88     # TODO: cursor.dictfetchall() doesn't exist in psycopg2, 
    89     # but no Django code uses this. Safe to remove? 
    90     return cursor.dictfetchall() 
     71dictfetchone = util.dictfetchone 
     72dictfetchmany = util.dictfetchmany 
     73dictfetchall = util.dictfetchall 
    9174 
    9275def get_last_insert_id(cursor, table_name, pk_name): 
  • django/branches/per-object-permissions/django/db/backends/sqlite3/base.py

    r3115 r3732  
    6363 
    6464    def close(self): 
    65         if self.connection is not None: 
     65        from django.conf import settings 
     66        # If database is in memory, closing the connection destroys the database. 
     67        # To prevent accidental data loss, ignore close requests on an in-memory db. 
     68        if self.connection is not None and settings.DATABASE_NAME != ":memory:": 
    6669            self.connection.close() 
    6770            self.connection = None 
  • django/branches/per-object-permissions/django/db/backends/util.py

    r3113 r3732  
    9999def _dict_helper(desc, row): 
    100100    "Returns a dictionary for the given cursor.description and result row." 
    101     return dict([(desc[col[0]][0], col[1]) for col in enumerate(row)]
     101    return dict(zip([col[0] for col in desc], row)
    102102 
    103103def dictfetchone(cursor): 
  • django/branches/per-object-permissions/django/template/defaulttags.py

    r3268 r3732  
    8787        context.push() 
    8888        try: 
    89             values = self.sequence.resolve(context
     89            values = self.sequence.resolve(context, True
    9090        except VariableDoesNotExist: 
    9191            values = [] 
     
    213213 
    214214    def render(self, context): 
    215         obj_list = self.target.resolve(context
    216         if obj_list == '': # target_var wasn't found in context; fail silently 
     215        obj_list = self.target.resolve(context, True
     216        if obj_list == None: # target_var wasn't found in context; fail silently 
    217217            context[self.var_name] = [] 
    218218            return '' 
    219219        output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]} 
    220220        for obj in obj_list: 
    221             grouper = self.expression.resolve(Context({'var': obj})
     221            grouper = self.expression.resolve(Context({'var': obj}), True
    222222            # TODO: Is this a sensible way to determine equality? 
    223223            if output and repr(output[-1]['grouper']) == repr(grouper): 
     
    252252        if self.parsed: 
    253253            try: 
    254                 t = Template(output
     254                t = Template(output, name=self.filepath
    255255                return t.render(context) 
    256256            except TemplateSyntaxError, e: 
  • django/branches/per-object-permissions/django/template/__init__.py

    r3464 r3732  
    138138 
    139139class Template(object): 
    140     def __init__(self, template_string, origin=None): 
     140    def __init__(self, template_string, origin=None, name='<Unknown Template>'): 
    141141        "Compilation stage" 
    142142        if settings.TEMPLATE_DEBUG and origin == None: 
     
    145145            # came from... 
    146146        self.nodelist = compile_string(template_string, origin) 
     147        self.name = name 
    147148 
    148149    def __iter__(self): 
     
    435436                i += 1 
    436437            if i >= len(subject): 
    437                 raise TemplateSyntaxError, "Searching for value. Unexpected end of string in column %d: %s" % subject 
     438                raise TemplateSyntaxError, "Searching for value. Unexpected end of string in column %d: %s" % (i, subject) 
    438439            i += 1 
    439440            res = subject[p:i] 
     
    549550        except VariableDoesNotExist: 
    550551            if ignore_failures: 
    551                 return None 
     552                obj = None 
    552553            else: 
    553                 return settings.TEMPLATE_STRING_IF_INVALID 
     554                if settings.TEMPLATE_STRING_IF_INVALID: 
     555                    return settings.TEMPLATE_STRING_IF_INVALID 
     556                else: 
     557                    obj = settings.TEMPLATE_STRING_IF_INVALID 
    554558        for func, args in self.filters: 
    555559            arg_vals = [] 
     
    615619    (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.') 
    616620    """ 
    617     if path == 'False': 
    618         current = False 
    619     elif path == 'True': 
    620         current = True 
    621     elif path[0].isdigit(): 
     621    if path[0].isdigit(): 
    622622        number_type = '.' in path and float or int 
    623623        try: 
  • django/branches/per-object-permissions/django/template/loader.py

    r3464 r3732  
    7777    handling template inheritance recursively. 
    7878    """ 
    79     return get_template_from_string(*find_template_source(template_name)) 
     79    source, origin = find_template_source(template_name) 
     80    template = get_template_from_string(source, origin, template_name) 
     81    return template 
    8082 
    81 def get_template_from_string(source, origin=None): 
     83def get_template_from_string(source, origin=None, name=None): 
    8284    """ 
    8385    Returns a compiled Template object for the given template code, 
    8486    handling template inheritance recursively. 
    8587    """ 
    86     return Template(source, origin
     88    return Template(source, origin, name
    8789 
    8890def render_to_string(template_name, dictionary=None, context_instance=None): 
  • django/branches/per-object-permissions/django/template/loader_tags.py

    r3583 r3732  
    5252            raise TemplateSyntaxError, error_msg 
    5353        if hasattr(parent, 'render'): 
    54             return parent 
     54            return parent # parent is a Template object 
    5555        try: 
    5656            source, origin = find_template_source(parent, self.template_dirs) 
     
    5858            raise TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent 
    5959        else: 
    60             return get_template_from_string(source, origin
     60            return get_template_from_string(source, origin, parent
    6161 
    6262    def render(self, context): 
  • django/branches/per-object-permissions/django/test/client.py

    r3669 r3732  
    11from cStringIO import StringIO 
    2 from django.contrib.admin.views.decorators import LOGIN_FORM_KEY, _encode_post_data 
    32from django.core.handlers.base import BaseHandler 
    43from django.core.handlers.wsgi import WSGIRequest 
    54from django.dispatch import dispatcher 
    65from django.http import urlencode, SimpleCookie 
    7 from django.template import signals 
     6from django.test import signals 
    87from django.utils.functional import curry 
    98 
     
    9796    """ 
    9897    def __init__(self, **defaults): 
    99         self.handler = TestHandler() 
     98        self.handler = ClientHandler() 
    10099        self.defaults = defaults 
    101100        self.cookie = SimpleCookie() 
     
    127126        on_template_render = curry(store_rendered_templates, data) 
    128127        dispatcher.connect(on_template_render, signal=signals.template_rendered) 
    129  
     128         
    130129        response = self.handler(environ) 
    131130         
     
    181180        """ 
    182181        A specialized sequence of GET and POST to log into a view that 
    183         is protected by @login_required or a similar access decorator. 
    184          
    185         path should be the URL of the login page, or of any page that 
    186         is login protected. 
    187          
    188         Returns True if login was successful; False if otherwise.         
    189         """ 
    190         # First, GET the login page.  
    191         # This is required to establish the session
     182        is protected by a @login_required access decorator. 
     183         
     184        path should be the URL of the page that is login protected. 
     185         
     186        Returns the response from GETting the requested URL after  
     187        login is complete. Returns False if login process failed. 
     188        """ 
     189        # First, GET the page that is login protected.  
     190        # This page will redirect to the login page
    192191        response = self.get(path) 
     192        if response.status_code != 302: 
     193            return False 
     194             
     195        login_path, data = response['Location'].split('?') 
     196        next = data.split('=')[1] 
     197 
     198        # Second, GET the login page; required to set up cookies 
     199        response = self.get(login_path, **extra) 
    193200        if response.status_code != 200: 
    194201            return False 
    195  
    196         # Set up the block of form data required by the login page
     202             
     203        # Last, POST the login data
    197204        form_data = { 
    198205            'username': username, 
    199206            'password': password, 
    200             'this_is_the_login_form': 1, 
    201             'post_data': _encode_post_data({LOGIN_FORM_KEY: 1}) 
     207            'next' : next, 
    202208        } 
    203         response = self.post(path, data=form_data, **extra) 
    204          
    205         # login page should give response 200 (if you requested the login 
    206         # page specifically), or 302 (if you requested a login 
    207         # protected page, to which the login can redirect). 
    208         return response.status_code in (200,302) 
     209        response = self.post(login_path, data=form_data, **extra) 
     210 
     211        # Login page should 302 redirect to the originally requested page 
     212        if response.status_code != 302 or response['Location'] != path: 
     213            return False 
     214 
     215        # Since we are logged in, request the actual page again 
     216        return self.get(path) 
  • django/branches/per-object-permissions/django/test/simple.py

    r3669 r3732  
    22from django.conf import settings 
    33from django.core import management 
     4from django.test.utils import setup_test_environment, teardown_test_environment 
    45from django.test.utils import create_test_db, destroy_test_db 
    56from django.test.testcases import OutputChecker, DocTestRunner 
     
    5253    will be added to the test suite. 
    5354    """ 
     55    setup_test_environment() 
    5456     
    5557    settings.DEBUG = False     
     
    6264        suite.addTest(test) 
    6365 
    64     old_name = create_test_db(verbosity) 
     66    old_name = settings.DATABASE_NAME 
     67    create_test_db(verbosity) 
    6568    management.syncdb(verbosity, interactive=False) 
    6669    unittest.TextTestRunner(verbosity=verbosity).run(suite) 
    6770    destroy_test_db(old_name, verbosity) 
     71     
     72    teardown_test_environment() 
  • django/branches/per-object-permissions/django/test/utils.py

    r3669 r3732  
    11import sys, time 
    22from django.conf import settings 
    3 from django.db import connection, transaction 
     3from django.db import connection, transaction, backend 
     4from django.dispatch import dispatcher 
     5from django.test import signals 
     6from django.template import Template 
    47 
    58# The prefix to put on the default database name when creating 
     
    710TEST_DATABASE_PREFIX = 'test_' 
    811 
     12def instrumented_test_render(self, context): 
     13    """An instrumented Template render method, providing a signal  
     14    that can be intercepted by the test system Client 
     15     
     16    """ 
     17    dispatcher.send(signal=signals.template_rendered, sender=self, template=self, context=context) 
     18    return self.nodelist.render(context) 
     19     
     20def setup_test_environment(): 
     21    """Perform any global pre-test setup. This involves: 
     22         
     23        - Installing the instrumented test renderer 
     24         
     25    """ 
     26    Template.original_render = Template.render 
     27    Template.render = instrumented_test_render 
     28     
     29def teardown_test_environment(): 
     30    """Perform any global post-test teardown. This involves: 
     31 
     32        - Restoring the original test renderer 
     33         
     34    """ 
     35    Template.render = Template.original_render 
     36    del Template.original_render 
     37     
    938def _set_autocommit(connection): 
    1039    "Make sure a connection is in autocommit mode." 
     
    2251        TEST_DATABASE_NAME = ":memory:" 
    2352    else: 
    24         TEST_DATABASE_NAME = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 
     53        if settings.TEST_DATABASE_NAME: 
     54            TEST_DATABASE_NAME = settings.TEST_DATABASE_NAME 
     55        else: 
     56            TEST_DATABASE_NAME = TEST_DATABASE_PREFIX + settings.DATABASE_NAME 
    2557         
    2658        # Create the test database and connect to it. We need to autocommit 
     
    3062        _set_autocommit(connection) 
    3163        try: 
    32             cursor.execute("CREATE DATABASE %s" % TEST_DATABASE_NAME
     64            cursor.execute("CREATE DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME)
    3365        except Exception, e:             
    3466            sys.stderr.write("Got an error creating the test database: %s\n" % e) 
     
    3971                    if verbosity >= 1: 
    4072                        print "Destroying old test database..."                 
    41                     cursor.execute("DROP DATABASE %s" % TEST_DATABASE_NAME
     73                    cursor.execute("DROP DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME)
    4274                    if verbosity >= 1: 
    4375                        print "Creating test database..." 
    44                     cursor.execute("CREATE DATABASE %s" % TEST_DATABASE_NAME
     76                    cursor.execute("CREATE DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME)
    4577                except Exception, e: 
    4678                    sys.stderr.write("Got an error recreating the test database: %s\n" % e) 
     
    5183                
    5284    connection.close() 
    53     old_database_name = settings.DATABASE_NAME 
    5485    settings.DATABASE_NAME = TEST_DATABASE_NAME 
    5586 
     
    5788    # the side effect of initializing the test database. 
    5889    cursor = connection.cursor() 
    59              
    60     return old_database_name 
    6190 
    6291def destroy_test_db(old_database_name, verbosity=1): 
     
    6796    if verbosity >= 1: 
    6897        print "Destroying test database..." 
     98    connection.close() 
     99    TEST_DATABASE_NAME = settings.DATABASE_NAME 
     100    settings.DATABASE_NAME = old_database_name 
     101 
    69102    if settings.DATABASE_ENGINE != "sqlite3": 
    70         connection.close() 
    71         TEST_DATABASE_NAME = settings.DATABASE_NAME 
    72         settings.DATABASE_NAME = old_database_name 
    73103        cursor = connection.cursor() 
    74104        _set_autocommit(connection) 
    75105        time.sleep(1) # To avoid "database is being accessed by other users" errors. 
    76         cursor.execute("DROP DATABASE %s" % TEST_DATABASE_NAME
     106        cursor.execute("DROP DATABASE %s" % backend.quote_name(TEST_DATABASE_NAME)
    77107        connection.close() 
    78  
  • django/branches/per-object-permissions/django/utils/datastructures.py

    r3113 r3732  
    188188    &nbs