2008-07-19 07:54:34 +08:00
from django . core . exceptions import ObjectDoesNotExist
from django . db import models
from django . utils . html import escape
from django . utils . safestring import mark_safe
from django . utils . text import capfirst
from django . utils . encoding import force_unicode
from django . utils . translation import ugettext as _
def quote ( s ) :
"""
Ensure that primary key values do not confuse the admin URLs by escaping
any ' / ' , ' _ ' and ' : ' characters . Similar to urllib . quote , except that the
quoting is slightly different so that it doesn ' t get automatically
unquoted by the Web browser .
"""
if not isinstance ( s , basestring ) :
return s
res = list ( s )
for i in range ( len ( res ) ) :
c = res [ i ]
if c in """ :/_#?;@&=+$, " <> % \\ """ :
res [ i ] = ' _ %02X ' % ord ( c )
return ' ' . join ( res )
def unquote ( s ) :
"""
Undo the effects of quote ( ) . Based heavily on urllib . unquote ( ) .
"""
mychr = chr
myatoi = int
list = s . split ( ' _ ' )
res = [ list [ 0 ] ]
myappend = res . append
del list [ 0 ]
for item in list :
if item [ 1 : 2 ] :
try :
myappend ( mychr ( myatoi ( item [ : 2 ] , 16 ) ) + item [ 2 : ] )
except ValueError :
myappend ( ' _ ' + item )
else :
myappend ( ' _ ' + item )
return " " . join ( res )
2008-08-18 23:49:58 +08:00
def flatten_fieldsets ( fieldsets ) :
""" Returns a list of field names from an admin fieldsets structure. """
field_names = [ ]
for name , opts in fieldsets :
for field in opts [ ' fields ' ] :
# type checking feels dirty, but it seems like the best way here
if type ( field ) == tuple :
field_names . extend ( field )
else :
field_names . append ( field )
return field_names
2008-07-19 07:54:34 +08:00
def _nest_help ( obj , depth , val ) :
current = obj
for i in range ( depth ) :
current = current [ - 1 ]
current . append ( val )
def get_deleted_objects ( deleted_objects , perms_needed , user , obj , opts , current_depth , admin_site ) :
" Helper function that recursively populates deleted_objects. "
nh = _nest_help # Bind to local variable for performance
if current_depth > 16 :
return # Avoid recursing too deep.
opts_seen = [ ]
for related in opts . get_all_related_objects ( ) :
has_admin = related . model in admin_site . _registry
if related . opts in opts_seen :
continue
opts_seen . append ( related . opts )
rel_opts_name = related . get_accessor_name ( )
if isinstance ( related . field . rel , models . OneToOneRel ) :
try :
sub_obj = getattr ( obj , rel_opts_name )
except ObjectDoesNotExist :
pass
else :
if has_admin :
p = ' %s . %s ' % ( related . opts . app_label , related . opts . get_delete_permission ( ) )
if not user . has_perm ( p ) :
perms_needed . add ( related . opts . verbose_name )
# We don't care about populating deleted_objects now.
continue
if related . field . rel . edit_inline or not has_admin :
# Don't display link to edit, because it either has no
# admin or is edited inline.
nh ( deleted_objects , current_depth , [ mark_safe ( u ' %s : %s ' % ( force_unicode ( capfirst ( related . opts . verbose_name ) ) , sub_obj ) ) , [ ] ] )
else :
# Display a link to the admin page.
nh ( deleted_objects , current_depth , [ mark_safe ( u ' %s : <a href= " ../../../../ %s / %s / %s / " > %s </a> ' %
( escape ( force_unicode ( capfirst ( related . opts . verbose_name ) ) ) ,
related . opts . app_label ,
related . opts . object_name . lower ( ) ,
sub_obj . _get_pk_val ( ) , sub_obj ) ) , [ ] ] )
get_deleted_objects ( deleted_objects , perms_needed , user , sub_obj , related . opts , current_depth + 2 , admin_site )
else :
has_related_objs = False
for sub_obj in getattr ( obj , rel_opts_name ) . all ( ) :
has_related_objs = True
if related . field . rel . edit_inline or not has_admin :
# Don't display link to edit, because it either has no
# admin or is edited inline.
nh ( deleted_objects , current_depth , [ u ' %s : %s ' % ( force_unicode ( capfirst ( related . opts . verbose_name ) ) , escape ( sub_obj ) ) , [ ] ] )
else :
# Display a link to the admin page.
nh ( deleted_objects , current_depth , [ mark_safe ( u ' %s : <a href= " ../../../../ %s / %s / %s / " > %s </a> ' % \
( escape ( force_unicode ( capfirst ( related . opts . verbose_name ) ) ) , related . opts . app_label , related . opts . object_name . lower ( ) , sub_obj . _get_pk_val ( ) , escape ( sub_obj ) ) ) , [ ] ] )
get_deleted_objects ( deleted_objects , perms_needed , user , sub_obj , related . opts , current_depth + 2 , admin_site )
# If there were related objects, and the user doesn't have
# permission to delete them, add the missing perm to perms_needed.
if has_admin and has_related_objs :
p = ' %s . %s ' % ( related . opts . app_label , related . opts . get_delete_permission ( ) )
if not user . has_perm ( p ) :
perms_needed . add ( related . opts . verbose_name )
for related in opts . get_all_related_many_to_many_objects ( ) :
has_admin = related . model in admin_site . _registry
if related . opts in opts_seen :
continue
opts_seen . append ( related . opts )
rel_opts_name = related . get_accessor_name ( )
has_related_objs = False
# related.get_accessor_name() could return None for symmetrical relationships
if rel_opts_name :
rel_objs = getattr ( obj , rel_opts_name , None )
if rel_objs :
has_related_objs = True
if has_related_objs :
for sub_obj in rel_objs . all ( ) :
if related . field . rel . edit_inline or not has_admin :
# Don't display link to edit, because it either has no
# admin or is edited inline.
nh ( deleted_objects , current_depth , [ _ ( ' One or more %(fieldname)s in %(name)s : %(obj)s ' ) % \
{ ' fieldname ' : force_unicode ( related . field . verbose_name ) , ' name ' : force_unicode ( related . opts . verbose_name ) , ' obj ' : escape ( sub_obj ) } , [ ] ] )
else :
# Display a link to the admin page.
nh ( deleted_objects , current_depth , [
mark_safe ( ( _ ( ' One or more %(fieldname)s in %(name)s : ' ) % { ' fieldname ' : escape ( force_unicode ( related . field . verbose_name ) ) , ' name ' : escape ( force_unicode ( related . opts . verbose_name ) ) } ) + \
( u ' <a href= " ../../../../ %s / %s / %s / " > %s </a> ' % \
( related . opts . app_label , related . opts . module_name , sub_obj . _get_pk_val ( ) , escape ( sub_obj ) ) ) ) , [ ] ] )
# If there were related objects, and the user doesn't have
# permission to change them, add the missing perm to perms_needed.
if has_admin and has_related_objs :
p = u ' %s . %s ' % ( related . opts . app_label , related . opts . get_change_permission ( ) )
if not user . has_perm ( p ) :
perms_needed . add ( related . opts . verbose_name )