1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

Merged to trunk r1152

git-svn-id: http://code.djangoproject.com/svn/django/branches/new-admin@1154 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Robert Wittams 2005-11-10 00:49:29 +00:00
commit dbaf9c6f8d
12 changed files with 191 additions and 85 deletions

View File

@ -57,7 +57,7 @@
{% else %}
<ul class="actionlist">
{% for entry in admin_log %}
<li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{{ entry.get_content_type.name|capfirst }}</span></li>
<li class="{% if entry.is_addition %}addlink{% endif %}{% if entry.is_change %}changelink{% endif %}{% if entry.is_deletion %}deletelink{% endif %}">{% if not entry.is_deletion %}<a href="{{ entry.get_admin_url }}">{% endif %}{{ entry.object_repr|escape }}{% if not entry.is_deletion %}</a>{% endif %}<br /><span class="mini quiet">{{ entry.get_content_type.name|capfirst }}</span></li>
{% endfor %}
</ul>
{% endif %}

View File

@ -113,7 +113,7 @@ class RelatedFilterSpec(FilterSpec):
'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
'display': _('All') }
for val in self.lookup_choices:
pk_val = getattr(val, self.field.rel.to.pk.column)
pk_val = getattr(val, self.field.rel.to.pk.attname)
yield { 'selected': self.lookup_val == str(pk_val),
'query_string': cl.get_query_string( {self.lookup_kwarg: pk_val}),
'display' : val }
@ -547,7 +547,7 @@ def render_change_form(opts, manipulator, app_label, context, add=False, change=
context_instance=context)
def log_add_message(user, opts,manipulator,new_object):
pk_value = getattr(new_object, opts.pk.column)
pk_value = getattr(new_object, opts.pk.attname)
log.log_action(user.id, opts.get_content_type_id(), pk_value, str(new_object), log.ADDITION)
def add_stage(request, app_label, module_name, show_delete=False, form_url='', post_url='../', post_url_continue='../%s/', object_id_override=None):
@ -566,7 +566,7 @@ def add_stage(request, app_label, module_name, show_delete=False, form_url='', p
new_object = manipulator.save(new_data)
log_add_message(request.user, opts,manipulator,new_object)
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name':opts.verbose_name, 'obj':new_object}
pk_value = getattr(new_object,opts.pk.column)
pk_value = getattr(new_object,opts.pk.attname)
# Here, we distinguish between different save types by checking for
# the presence of keys in request.POST.
if request.POST.has_key("_continue"):
@ -644,7 +644,7 @@ def change_stage(request, app_label, module_name, object_id):
new_object = manipulator.save(new_data)
log_change_message(request.user,opts,manipulator,new_object)
msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj':new_object}
pk_value = getattr(new_object,opts.pk.column)
pk_value = getattr(new_object,opts.pk.attname)
if request.POST.has_key("_continue"):
request.user.add_message(msg + ' ' + _("You may edit it again below."))
if request.REQUEST.has_key('_popup'):
@ -738,7 +738,7 @@ def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current
# Display a link to the admin page.
nh(deleted_objects, current_depth, ['%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
(capfirst(related.opts.verbose_name), related.opts.app_label, related.opts.module_name,
getattr(sub_obj, related.opts.pk.column), sub_obj), []])
getattr(sub_obj, related.opts.pk.attname), sub_obj), []])
_get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2)
else:
has_related_objs = False

View File

@ -309,6 +309,7 @@ class FormField:
new_data.setlist(name, [])
def get_id(self):
"Returns the HTML 'id' attribute for this form field."
return FORM_FIELD_ID_PREFIX + self.field_name
####################
# GENERIC WIDGETS #
@ -408,10 +409,10 @@ class SelectField(FormField):
self.member_name = member_name
def render(self, data):
str_data = str(data) # normalize to string
output = ['<select id="%s" class="v%s%s" name="%s" size="%s">' % \
(self.get_id(), self.__class__.__name__,
(self.get_id(), self.__class__.__name__,
self.is_required and ' required' or '', self.field_name, self.size)]
str_data = str(data) # normalize to string
for value, display_name in self.choices:
selected_html = ''
if str(value) == str_data:
@ -593,8 +594,7 @@ class FileUploadField(FormField):
def render(self, data):
return '<input type="file" id="%s" class="v%s" name="%s" />' % \
(self.get_id(), self.__class__.__name__,
self.field_name)
(self.get_id(), self.__class__.__name__, self.field_name)
def html2python(data):
if data is None:

View File

@ -108,7 +108,23 @@ def get_sql_delete(mod):
cursor = db.db.cursor()
except:
cursor = None
# Determine whether the admin log table exists. It only exists if the
# person has installed the admin app.
try:
if cursor is not None:
# Check whether the table exists.
cursor.execute("SELECT 1 FROM django_admin_log LIMIT 1")
except:
# The table doesn't exist, so it doesn't need to be dropped.
db.db.rollback()
admin_log_exists = False
else:
admin_log_exists = True
output = []
# Output DROP TABLE statements for standard application tables.
for klass in mod._MODELS:
try:
if cursor is not None:
@ -119,6 +135,8 @@ def get_sql_delete(mod):
db.db.rollback()
else:
output.append("DROP TABLE %s;" % klass._meta.db_table)
# Output DROP TABLE statements for many-to-many tables.
for klass in mod._MODELS:
opts = klass._meta
for f in opts.many_to_many:
@ -140,8 +158,9 @@ def get_sql_delete(mod):
# Delete from the admin log.
if cursor is not None:
cursor.execute("SELECT id FROM content_types WHERE package = %s", [app_label])
for row in cursor.fetchall():
output.append("DELETE FROM django_admin_log WHERE content_type_id = %s;" % row[0])
if admin_log_exists:
for row in cursor.fetchall():
output.append("DELETE FROM django_admin_log WHERE content_type_id = %s;" % row[0])
# Close database connection explicitly, in case this output is being piped
# directly into a database client, to avoid locking issues.

View File

@ -889,7 +889,7 @@ def method_init(opts, self, *args, **kwargs):
except KeyError:
try:
# Object instance wasn't passed in -- must be an ID.
val = kwargs.pop(f.column)
val = kwargs.pop(f.attname)
except KeyError:
val = f.get_default()
else:
@ -901,17 +901,17 @@ def method_init(opts, self, *args, **kwargs):
val = getattr(rel_obj, f.rel.field_name)
except AttributeError:
raise TypeError, "Invalid value: %r should be a %s instance, not a %s" % (f.name, f.rel.to, type(rel_obj))
setattr(self, f.column, val)
setattr(self, f.attname, val)
else:
val = kwargs.pop(f.name, f.get_default())
setattr(self, f.name, val)
val = kwargs.pop(f.attname, f.get_default())
setattr(self, f.attname, val)
if kwargs:
raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0]
for i, arg in enumerate(args):
setattr(self, opts.fields[i].column, arg)
setattr(self, opts.fields[i].attname, arg)
def method_eq(opts, self, other):
return isinstance(other, self.__class__) and getattr(self, opts.pk.column) == getattr(other, opts.pk.column)
return isinstance(other, self.__class__) and getattr(self, opts.pk.attname) == getattr(other, opts.pk.attname)
def method_save(opts, self):
# Run any pre-save hooks.
@ -921,7 +921,7 @@ def method_save(opts, self):
cursor = db.db.cursor()
# First, try an UPDATE. If that doesn't update anything, do an INSERT.
pk_val = getattr(self, opts.pk.column)
pk_val = getattr(self, opts.pk.attname)
pk_set = bool(pk_val)
record_exists = True
if pk_set:
@ -929,33 +929,33 @@ def method_save(opts, self):
cursor.execute("SELECT 1 FROM %s WHERE %s=%%s LIMIT 1" % (opts.db_table, opts.pk.column), [pk_val])
# If it does already exist, do an UPDATE.
if cursor.fetchone():
db_values = [f.get_db_prep_save(f.pre_save(getattr(self, f.column), False)) for f in non_pks]
db_values = [f.get_db_prep_save(f.pre_save(getattr(self, f.attname), False)) for f in non_pks]
cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % (opts.db_table,
','.join(['%s=%%s' % f.column for f in non_pks]), opts.pk.column),
','.join(['%s=%%s' % f.column for f in non_pks]), opts.pk.attname),
db_values + [pk_val])
else:
record_exists = False
if not pk_set or not record_exists:
field_names = [f.column for f in opts.fields if not isinstance(f, AutoField)]
placeholders = ['%s'] * len(field_names)
db_values = [f.get_db_prep_save(f.pre_save(getattr(self, f.column), True)) for f in opts.fields if not isinstance(f, AutoField)]
db_values = [f.get_db_prep_save(f.pre_save(getattr(self, f.attname), True)) for f in opts.fields if not isinstance(f, AutoField)]
if opts.order_with_respect_to:
field_names.append('_order')
# TODO: This assumes the database supports subqueries.
placeholders.append('(SELECT COUNT(*) FROM %s WHERE %s = %%s)' % \
(opts.db_table, opts.order_with_respect_to.column))
db_values.append(getattr(self, opts.order_with_respect_to.column))
db_values.append(getattr(self, opts.order_with_respect_to.attname))
cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % (opts.db_table,
','.join(field_names), ','.join(placeholders)), db_values)
if opts.has_auto_field:
setattr(self, opts.pk.column, db.get_last_insert_id(cursor, opts.db_table, opts.pk.column))
setattr(self, opts.pk.attname, db.get_last_insert_id(cursor, opts.db_table, opts.pk.column))
db.db.commit()
# Run any post-save hooks.
if hasattr(self, '_post_save'):
self._post_save()
def method_delete(opts, self):
assert getattr(self, opts.pk.column) is not None, "%r can't be deleted because it doesn't have an ID."
assert getattr(self, opts.pk.attname) is not None, "%r can't be deleted because it doesn't have an ID."
# Run any pre-delete hooks.
if hasattr(self, '_pre_delete'):
self._pre_delete()
@ -974,15 +974,15 @@ def method_delete(opts, self):
sub_obj.delete()
for related in opts.get_all_related_many_to_many_objects():
cursor.execute("DELETE FROM %s WHERE %s_id=%%s" % (related.field.get_m2m_db_table(related.opts),
self._meta.object_name.lower()), [getattr(self, opts.pk.column)])
self._meta.object_name.lower()), [getattr(self, opts.pk.attname)])
for f in opts.many_to_many:
cursor.execute("DELETE FROM %s WHERE %s_id=%%s" % (f.get_m2m_db_table(opts), self._meta.object_name.lower()),
[getattr(self, opts.pk.column)])
cursor.execute("DELETE FROM %s WHERE %s=%%s" % (opts.db_table, opts.pk.column), [getattr(self, opts.pk.column)])
[getattr(self, opts.pk.attname)])
cursor.execute("DELETE FROM %s WHERE %s=%%s" % (opts.db_table, opts.pk.column), [getattr(self, opts.pk.attname)])
db.db.commit()
setattr(self, opts.pk.column, None)
setattr(self, opts.pk.attname, None)
for f in opts.fields:
if isinstance(f, FileField) and getattr(self, f.column):
if isinstance(f, FileField) and getattr(self, f.attname):
file_name = getattr(self, 'get_%s_filename' % f.name)()
# If the file exists and no other object of this type references it,
# delete it from the filesystem.
@ -997,7 +997,7 @@ def method_get_next_in_order(opts, order_field, self):
self._next_in_order_cache = opts.get_model_module().get_object(order_by=('_order',),
where=['_order > (SELECT _order FROM %s WHERE %s=%%s)' % (opts.db_table, opts.pk.column),
'%s=%%s' % order_field.column], limit=1,
params=[getattr(self, opts.pk.column), getattr(self, order_field.column)])
params=[getattr(self, opts.pk.attname), getattr(self, order_field.attname)])
return self._next_in_order_cache
def method_get_previous_in_order(opts, order_field, self):
@ -1005,7 +1005,7 @@ def method_get_previous_in_order(opts, order_field, self):
self._previous_in_order_cache = opts.get_model_module().get_object(order_by=('-_order',),
where=['_order < (SELECT _order FROM %s WHERE %s=%%s)' % (opts.db_table, opts.pk.column),
'%s=%%s' % order_field.column], limit=1,
params=[getattr(self, opts.pk.column), getattr(self, order_field.column)])
params=[getattr(self, opts.pk.attname), getattr(self, order_field.attname)])
return self._previous_in_order_cache
# RELATIONSHIP METHODS #####################
@ -1014,7 +1014,7 @@ def method_get_previous_in_order(opts, order_field, self):
def method_get_many_to_one(field_with_rel, self):
cache_var = field_with_rel.get_cache_name()
if not hasattr(self, cache_var):
val = getattr(self, field_with_rel.column)
val = getattr(self, field_with_rel.attname)
mod = field_with_rel.rel.to.get_model_module()
if val is None:
raise getattr(mod, '%sDoesNotExist' % field_with_rel.rel.to.object_name)
@ -1034,7 +1034,7 @@ def method_get_many_to_many(field_with_rel, self):
field_with_rel.get_m2m_db_table(self._meta), rel.pk.column,
rel.object_name.lower(), self._meta.object_name.lower(), rel.get_order_sql('a'))
cursor = db.db.cursor()
cursor.execute(sql, [getattr(self, self._meta.pk.column)])
cursor.execute(sql, [getattr(self, self._meta.pk.attname)])
setattr(self, cache_var, [getattr(mod, rel.object_name)(*row) for row in cursor.fetchall()])
return getattr(self, cache_var)
@ -1055,7 +1055,7 @@ def method_set_many_to_many(rel_field, self, id_list):
rel = rel_field.rel.to
m2m_table = rel_field.get_m2m_db_table(self._meta)
cursor = db.db.cursor()
this_id = getattr(self, self._meta.pk.column)
this_id = getattr(self, self._meta.pk.attname)
if ids_to_delete:
sql = "DELETE FROM %s WHERE %s_id = %%s AND %s_id IN (%s)" % (m2m_table, self._meta.object_name.lower(), rel.object_name.lower(), ','.join(map(str, ids_to_delete)))
cursor.execute(sql, [this_id])
@ -1082,11 +1082,11 @@ def method_get_related(method_name, rel_mod, rel_field, self, **kwargs):
# Handles adding related objects.
# Example: Poll.add_choice()
def method_add_related(rel_obj, rel_mod, rel_field, self, *args, **kwargs):
init_kwargs = dict(zip([f.name for f in rel_obj.fields if f != rel_field and not isinstance(f, AutoField)], args))
init_kwargs = dict(zip([f.attname for f in rel_obj.fields if f != rel_field and not isinstance(f, AutoField)], args))
init_kwargs.update(kwargs)
for f in rel_obj.fields:
if isinstance(f, AutoField):
init_kwargs[f.name] = None
init_kwargs[f.attname] = None
init_kwargs[rel_field.name] = self
obj = rel_mod.Klass(**init_kwargs)
obj.save()
@ -1095,7 +1095,7 @@ def method_add_related(rel_obj, rel_mod, rel_field, self, *args, **kwargs):
# Handles related many-to-many object retrieval.
# Examples: Album.get_song(), Album.get_song_list(), Album.get_song_count()
def method_get_related_many_to_many(method_name, opts, rel_mod, rel_field, self, **kwargs):
kwargs['%s__%s__exact' % (rel_field.name, opts.pk.name)] = getattr(self, opts.pk.column)
kwargs['%s__%s__exact' % (rel_field.name, opts.pk.name)] = getattr(self, opts.pk.attname)
return getattr(rel_mod, method_name)(**kwargs)
# Handles setting many-to-many related objects.
@ -1104,7 +1104,7 @@ def method_set_related_many_to_many(rel_opts, rel_field, self, id_list):
id_list = map(int, id_list) # normalize to integers
rel = rel_field.rel.to
m2m_table = rel_field.get_m2m_db_table(rel_opts)
this_id = getattr(self, self._meta.pk.column)
this_id = getattr(self, self._meta.pk.attname)
cursor = db.db.cursor()
cursor.execute("DELETE FROM %s WHERE %s_id = %%s" % (m2m_table, rel.object_name.lower()), [this_id])
sql = "INSERT INTO %s (%s_id, %s_id) VALUES (%%s, %%s)" % (m2m_table, rel.object_name.lower(), rel_opts.object_name.lower())
@ -1133,7 +1133,7 @@ def method_get_order(ordered_obj, self):
def method_get_next_or_previous(get_object_func, field, is_next, self, **kwargs):
kwargs.setdefault('where', []).append('%s %s %%s' % (field.column, (is_next and '>' or '<')))
kwargs.setdefault('params', []).append(str(getattr(self, field.name)))
kwargs.setdefault('params', []).append(str(getattr(self, field.attname)))
kwargs['order_by'] = [(not is_next and '-' or '') + field.name]
kwargs['limit'] = 1
return get_object_func(**kwargs)
@ -1141,18 +1141,18 @@ def method_get_next_or_previous(get_object_func, field, is_next, self, **kwargs)
# CHOICE-RELATED METHODS ###################
def method_get_display_value(field, self):
value = getattr(self, field.column)
value = getattr(self, field.attname)
return dict(field.choices).get(value, value)
# FILE-RELATED METHODS #####################
def method_get_file_filename(field, self):
return os.path.join(settings.MEDIA_ROOT, getattr(self, field.name))
return os.path.join(settings.MEDIA_ROOT, getattr(self, field.attname))
def method_get_file_url(field, self):
if getattr(self, field.name): # value is not blank
if getattr(self, field.attname): # value is not blank
import urlparse
return urlparse.urljoin(settings.MEDIA_URL, getattr(self, field.name)).replace('\\', '/')
return urlparse.urljoin(settings.MEDIA_URL, getattr(self, field.attname)).replace('\\', '/')
return ''
def method_get_file_size(field, self):
@ -1177,7 +1177,7 @@ def method_save_file(field, self, filename, raw_contents):
filename = filename[:dot_index] + '_' + filename[dot_index:]
# Write the file to disk.
setattr(self, field.name, filename)
setattr(self, field.attname, filename)
fp = open(getattr(self, 'get_%s_filename' % field.name)(), 'wb')
fp.write(raw_contents)
fp.close()
@ -1504,7 +1504,7 @@ def function_get_in_bulk(opts, klass, *args, **kwargs):
kwargs['where'] = ["%s.%s IN (%s)" % (opts.db_table, opts.pk.column, ",".join(['%s'] * len(id_list)))]
kwargs['params'] = id_list
obj_list = function_get_list(opts, klass, **kwargs)
return dict([(getattr(o, opts.pk.column), o) for o in obj_list])
return dict([(getattr(o, opts.pk.attname), o) for o in obj_list])
def function_get_latest(opts, klass, does_not_exist_exception, **kwargs):
kwargs['order_by'] = ('-' + opts.get_latest_by,)
@ -1578,8 +1578,8 @@ def manipulator_init(opts, add, change, self, obj_key=None, follow=None):
lookup_kwargs = opts.one_to_one_field.rel.limit_choices_to
lookup_kwargs['%s__exact' % opts.one_to_one_field.rel.field_name] = obj_key
_ = opts.one_to_one_field.rel.to.get_model_module().get_object(**lookup_kwargs)
params = dict([(f.column, f.get_default()) for f in opts.fields])
params[opts.pk.column] = obj_key
params = dict([(f.attname, f.get_default()) for f in opts.fields])
params[opts.pk.attname] = obj_key
self.original_object = opts.get_model_module().Klass(**params)
else:
raise
@ -1610,14 +1610,14 @@ def manipulator_save(opts, klass, add, change, self, new_data):
param = f.get_manipulator_new_data(new_data)
else:
if change:
param = getattr(self.original_object, f.column)
param = getattr(self.original_object, f.attname)
else:
param = f.get_default()
params[f.column] = param
params[f.attname] = param
if change:
params[opts.pk.column] = self.obj_key
params[opts.pk.attname] = self.obj_key
# First, save the basic object itself.
new_object = klass(**params)
@ -1632,7 +1632,7 @@ def manipulator_save(opts, klass, add, change, self, new_data):
if change:
self.fields_added, self.fields_changed, self.fields_deleted = [], [], []
for f in opts.fields:
if not f.primary_key and str(getattr(self.original_object, f.column)) != str(getattr(new_object, f.column)):
if not f.primary_key and str(getattr(self.original_object, f.attname)) != str(getattr(new_object, f.attname)):
self.fields_changed.append(f.verbose_name)
# Save many-to-many objects. Example: Poll.set_sites()
@ -1674,7 +1674,7 @@ def manipulator_save(opts, klass, add, change, self, new_data):
if change:
if rel_new_data[related.opts.pk.name][0]:
try:
old_rel_obj = getattr(self.original_object, 'get_%s' % related.get_method_name_part() )(**{'%s__exact' % related.opts.pk.name: rel_new_data[related.opts.pk.name][0]})
old_rel_obj = getattr(self.original_object, 'get_%s' % related.get_method_name_part() )(**{'%s__exact' % related.opts.pk.name: rel_new_data[related.opts.pk.attname][0]})
except ObjectDoesNotExist:
pass
@ -1700,7 +1700,7 @@ def manipulator_save(opts, klass, add, change, self, new_data):
else:
param = f.get_manipulator_new_data(rel_new_data, rel=True)
if param != None:
params[f.column] = param
params[f.attname] = param
# Related links are a special case, because we have to
@ -1731,13 +1731,13 @@ def manipulator_save(opts, klass, add, change, self, new_data):
self.fields_added.append('%s "%s"' % (related.opts.verbose_name, new_rel_obj))
else:
for f in related.opts.fields:
if not f.primary_key and f != related.field and str(getattr(old_rel_obj, f.column)) != str(getattr(new_rel_obj, f.column)):
if not f.primary_key and f != related.field and str(getattr(old_rel_obj, f.attname)) != str(getattr(new_rel_obj, f.attname)):
self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj))
# Save many-to-many objects.
for f in related.opts.many_to_many:
if child_follow.get(f.name, None) and not f.rel.edit_inline:
was_changed = getattr(new_rel_obj, 'set_%s' % f.name)(rel_new_data[f.name])
was_changed = getattr(new_rel_obj, 'set_%s' % f.name)(rel_new_data[f.attname])
if change and was_changed:
self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj))
@ -1777,7 +1777,7 @@ def manipulator_validator_unique_together(field_name_list, opts, self, field_dat
for f in field_list[1:]:
# This is really not going to work for fields that have different form fields, eg DateTime
# This validation needs to occur after html2python to be effective.
field_val = all_data.get(f.column, None)
field_val = all_data.get(f.attname, None)
if field_val is None:
# This will be caught by another validator, assuming the field
# doesn't have blank=True.
@ -1791,7 +1791,7 @@ def manipulator_validator_unique_together(field_name_list, opts, self, field_dat
old_obj = mod.get_object(**kwargs)
except ObjectDoesNotExist:
return
if hasattr(self, 'original_object') and getattr(self.original_object, opts.pk.column) == getattr(old_obj, opts.pk.column):
if hasattr(self, 'original_object') and getattr(self.original_object, opts.pk.attname) == getattr(old_obj, opts.pk.attname):
pass
else:
raise validators.ValidationError, "%s with this %s already exists for the given %s." % \
@ -1817,7 +1817,7 @@ def manipulator_validator_unique_for_date(from_field, date_field, opts, lookup_t
except ObjectDoesNotExist:
return
else:
if hasattr(self, 'original_object') and getattr(self.original_object, opts.pk.column) == getattr(old_obj, opts.pk.column):
if hasattr(self, 'original_object') and getattr(self.original_object, opts.pk.attname) == getattr(old_obj, opts.pk.attname):
pass
else:
format_string = (lookup_type == 'date') and '%B %d, %Y' or '%B %Y'

View File

@ -55,10 +55,24 @@ def manipulator_validator_unique(f, opts, self, field_data, all_data):
old_obj = opts.get_model_module().get_object(**{'%s__%s' % (f.name, lookup_type): field_data})
except ObjectDoesNotExist:
return
if hasattr(self, 'original_object') and getattr(self.original_object, opts.pk.column) == getattr(old_obj, opts.pk.column):
if hasattr(self, 'original_object') and getattr(self.original_object, opts.pk.attname) == getattr(old_obj, opts.pk.attname):
return
raise validators.ValidationError, "%s with this %s already exists." % (capfirst(opts.verbose_name), f.verbose_name)
# A guide to Field parameters:
#
# * name: The name of the field specifed in the model.
# * attname: The attribute to use on the model object. This is the same as
# "name", except in the case of ForeignKeys, where "_id" is
# appended.
# * db_column: The db_column specified in the model (or None).
# * column: The database column for this field. This is the same as
# "attname", except if db_column is specified.
#
# Code that introspects values, or does other dynamic things, should use
# attname. For example, this gets the primary key value of object "obj":
#
# getattr(obj, opts.pk.attname)
class BoundField(object):
def __init__(self, field, field_mapping, original):
self.field = field
@ -129,19 +143,20 @@ class Field(object):
self.creation_counter = Field.creation_counter
Field.creation_counter += 1
# Set the name of the database column.
self.column = self.get_db_column()
self.attname, self.column = self.get_attname_column()
def set_name(self, name):
self.name = name
self.verbose_name = self.verbose_name or name.replace('_', ' ')
self.column = self.get_db_column()
self.attname, self.column = self.get_attname_column()
def get_db_column(self):
if self.db_column: return self.db_column
def get_attname_column(self):
if isinstance(self.rel, ManyToOne):
return '%s_id' % self.name
return self.name
attname = '%s_id' % self.name
else:
attname = self.name
column = self.db_column or attname
return attname, column
def get_cache_name(self):
return '_%s_cache' % self.name
@ -297,7 +312,7 @@ class Field(object):
if self.choices:
return first_choice + list(self.choices)
rel_obj = self.rel.to
return first_choice + [(getattr(x, rel_obj.pk.column), str(x)) for x in rel_obj.get_model_module().get_list(**self.rel.limit_choices_to)]
return first_choice + [(getattr(x, rel_obj.pk.attlist), str(x)) for x in rel_obj.get_model_module().get_list(**self.rel.limit_choices_to)]
def get_choices_default(self):
if(self.radio_admin):

View File

@ -13,7 +13,7 @@ class Permission(meta.Model):
ordering = ('package', 'codename')
def __repr__(self):
return "%s | %s" % (self.package, self.name)
return "%s | %s" % (self.package_id, self.name)
class Group(meta.Model):
name = meta.CharField(_('name'), maxlength=80, unique=True)
@ -103,7 +103,7 @@ class User(meta.Model):
def get_all_permissions(self):
if not hasattr(self, '_perm_cache'):
import sets
self._perm_cache = sets.Set(["%s.%s" % (p.package, p.codename) for p in self.get_permission_list()])
self._perm_cache = sets.Set(["%s.%s" % (p.package_id, p.codename) for p in self.get_permission_list()])
self._perm_cache.update(self.get_group_permissions())
return self._perm_cache

View File

@ -48,11 +48,11 @@ class ContentType(meta.Model):
unique_together = (('package', 'python_module_name'),)
def __repr__(self):
return "%s | %s" % (self.package, self.name)
return "%s | %s" % (self.package_id, self.name)
def get_model_module(self):
"Returns the Python model module for accessing this type of content."
return __import__('django.models.%s.%s' % (self.package, self.python_module_name), '', '', [''])
return __import__('django.models.%s.%s' % (self.package_id, self.python_module_name), '', '', [''])
def get_object_for_this_type(self, **kwargs):
"""

View File

@ -30,9 +30,7 @@
>>> format(my_birthday, 'S')
'th'
>>> format(my_birthday, 't')
Traceback (most recent call last):
...
NotImplementedError
'31'
>>> format(my_birthday, 'T')
'CET'
>>> format(my_birthday, 'U')
@ -63,11 +61,13 @@ NotImplementedError
'1979 188 CET'
"""
from django.utils import dateformat
format = dateformat.format
from django.utils import dateformat, translation
import datetime, os, time
format = dateformat.format
os.environ['TZ'] = 'Europe/Copenhagen'
translation.activate('en-us')
time.tzset()
my_birthday = datetime.datetime(1979, 7, 7, 22, 00)

View File

@ -1,4 +1,4 @@
__all__ = ['basic', 'repr', 'custom_methods', 'many_to_one', 'many_to_many',
'ordering', 'lookup', 'get_latest', 'm2m_intermediary', 'one_to_one',
'm2o_recursive', 'm2o_recursive2', 'save_delete_hooks', 'custom_pk',
'subclassing', 'many_to_one_null']
'subclassing', 'many_to_one_null', 'custom_columns']

View File

@ -0,0 +1,53 @@
"""
17. Custom column names
If your database column name is different than your model attribute, use the
``db_column`` parameter. Note that you'll use the field's name, not its column
name, in API usage.
"""
from django.core import meta
class Person(meta.Model):
first_name = meta.CharField(maxlength=30, db_column='firstname')
last_name = meta.CharField(maxlength=30, db_column='last')
def __repr__(self):
return '%s %s' % (self.first_name, self.last_name)
API_TESTS = """
# Create a Person.
>>> p = persons.Person(first_name='John', last_name='Smith')
>>> p.save()
>>> p.id
1
>>> persons.get_list()
[John Smith]
>>> persons.get_list(first_name__exact='John')
[John Smith]
>>> persons.get_object(first_name__exact='John')
John Smith
>>> persons.get_list(firstname__exact='John')
Traceback (most recent call last):
...
TypeError: got unexpected keyword argument 'firstname__exact'
>>> p = persons.get_object(last_name__exact='Smith')
>>> p.first_name
'John'
>>> p.last_name
'Smith'
>>> p.firstname
Traceback (most recent call last):
...
AttributeError: 'Person' object has no attribute 'firstname'
>>> p.last
Traceback (most recent call last):
...
AttributeError: 'Person' object has no attribute 'last'
"""

View File

@ -18,18 +18,24 @@ class Article(meta.Model):
API_TESTS = """
# Create a couple of Articles.
>>> from datetime import datetime
>>> a1 = articles.Article(id=None, headline='Article 1', pub_date=datetime(2005, 7, 26))
>>> a1 = articles.Article(headline='Article 1', pub_date=datetime(2005, 7, 26))
>>> a1.save()
>>> a2 = articles.Article(id=None, headline='Article 2', pub_date=datetime(2005, 7, 27))
>>> a2 = articles.Article(headline='Article 2', pub_date=datetime(2005, 7, 27))
>>> a2.save()
>>> a3 = articles.Article(id=None, headline='Article 3', pub_date=datetime(2005, 7, 27))
>>> a3 = articles.Article(headline='Article 3', pub_date=datetime(2005, 7, 27))
>>> a3.save()
>>> a4 = articles.Article(id=None, headline='Article 4', pub_date=datetime(2005, 7, 28))
>>> a4 = articles.Article(headline='Article 4', pub_date=datetime(2005, 7, 28))
>>> a4.save()
>>> a5 = articles.Article(headline='Article 5', pub_date=datetime(2005, 8, 1, 9, 0))
>>> a5.save()
>>> a6 = articles.Article(headline='Article 6', pub_date=datetime(2005, 8, 1, 8, 0))
>>> a6.save()
# get_iterator() is just like get_list(), but it's a generator.
>>> for a in articles.get_iterator():
... print a.headline
Article 5
Article 6
Article 4
Article 2
Article 3
@ -42,7 +48,7 @@ Article 4
# get_count() returns the number of objects matching search criteria.
>>> articles.get_count()
4L
6L
>>> articles.get_count(pub_date__exact=datetime(2005, 7, 27))
2L
>>> articles.get_count(headline__startswith='Blah blah')
@ -61,10 +67,10 @@ Article 4
# dictionaries instead of object instances -- and you can specify which fields
# you want to retrieve.
>>> articles.get_values(fields=['headline'])
[{'headline': 'Article 4'}, {'headline': 'Article 2'}, {'headline': 'Article 3'}, {'headline': 'Article 1'}]
[{'headline': 'Article 5'}, {'headline': 'Article 6'}, {'headline': 'Article 4'}, {'headline': 'Article 2'}, {'headline': 'Article 3'}, {'headline': 'Article 1'}]
>>> articles.get_values(pub_date__exact=datetime(2005, 7, 27), fields=['id'])
[{'id': 2}, {'id': 3}]
>>> articles.get_values(fields=['id', 'headline']) == [{'id': 4, 'headline': 'Article 4'}, {'id': 2, 'headline': 'Article 2'}, {'id': 3, 'headline': 'Article 3'}, {'id': 1, 'headline': 'Article 1'}]
>>> articles.get_values(fields=['id', 'headline']) == [{'id': 5, 'headline': 'Article 5'}, {'id': 6, 'headline': 'Article 6'}, {'id': 4, 'headline': 'Article 4'}, {'id': 2, 'headline': 'Article 2'}, {'id': 3, 'headline': 'Article 3'}, {'id': 1, 'headline': 'Article 1'}]
True
# get_values_iterator() is just like get_values(), but it's a generator.
@ -72,6 +78,8 @@ True
... i = d.items()
... i.sort()
... i
[('headline', 'Article 5'), ('id', 5)]
[('headline', 'Article 6'), ('id', 6)]
[('headline', 'Article 4'), ('id', 4)]
[('headline', 'Article 2'), ('id', 2)]
[('headline', 'Article 3'), ('id', 3)]
@ -84,4 +92,15 @@ Article 4
>>> a2.get_previous_by_pub_date()
Article 1
# get_next_by_FOO() and get_previous_by_FOO() take the time into account.
>>> a4.get_next_by_pub_date()
Article 6
>>> a5.get_next_by_pub_date()
Traceback (most recent call last):
...
ArticleDoesNotExist: Article does not exist for ...
>>> a6.get_previous_by_pub_date()
Article 4
>>> a5.get_previous_by_pub_date()
Article 6
"""