1
0
mirror of https://github.com/django/django.git synced 2024-12-23 01:25:58 +00:00

Fixed #24693 -- Added label and label_lower property to Model._meta

This commit is contained in:
Luis Del Giudice 2015-04-26 17:05:50 -04:00 committed by Markus Holtermann
parent 811d7870a5
commit 69ddc1b3da
10 changed files with 80 additions and 35 deletions

View File

@ -37,9 +37,7 @@ class CheckMessage(object):
elif isinstance(self.obj, models.base.ModelBase): elif isinstance(self.obj, models.base.ModelBase):
# We need to hardcode ModelBase and Field cases because its __str__ # We need to hardcode ModelBase and Field cases because its __str__
# method doesn't return "applabel.modellabel" and cannot be changed. # method doesn't return "applabel.modellabel" and cannot be changed.
model = self.obj obj = self.obj._meta.label
app = model._meta.app_label
obj = '%s.%s' % (app, model._meta.object_name)
else: else:
obj = force_str(self.obj) obj = force_str(self.obj)
id = "(%s) " % self.id if self.id else "" id = "(%s) " % self.id if self.id else ""

View File

@ -163,8 +163,8 @@ class DeserializedObject(object):
self.m2m_data = m2m_data self.m2m_data = m2m_data
def __repr__(self): def __repr__(self):
return "<DeserializedObject: %s.%s(pk=%s)>" % ( return "<DeserializedObject: %s(pk=%s)>" % (
self.object._meta.app_label, self.object._meta.object_name, self.object.pk) self.object._meta.label, self.object.pk)
def save(self, save_m2m=True, using=None): def save(self, save_m2m=True, using=None):
# Call save on the Model baseclass directly. This bypasses any # Call save on the Model baseclass directly. This bypasses any

View File

@ -362,10 +362,9 @@ class ModelState(object):
try: try:
fields.append((name, field_class(*args, **kwargs))) fields.append((name, field_class(*args, **kwargs)))
except TypeError as e: except TypeError as e:
raise TypeError("Couldn't reconstruct field %s on %s.%s: %s" % ( raise TypeError("Couldn't reconstruct field %s on %s: %s" % (
name, name,
model._meta.app_label, model._meta.label,
model._meta.object_name,
e, e,
)) ))
if not exclude_rels: if not exclude_rels:
@ -423,7 +422,7 @@ class ModelState(object):
# Make our record # Make our record
bases = tuple( bases = tuple(
( (
"%s.%s" % (base._meta.app_label, base._meta.model_name) base._meta.label_lower
if hasattr(base, "_meta") else if hasattr(base, "_meta") else
base base
) )

View File

@ -326,9 +326,7 @@ class ModelBase(type):
if cls.__doc__ is None: if cls.__doc__ is None:
cls.__doc__ = "%s(%s)" % (cls.__name__, ", ".join(f.name for f in opts.fields)) cls.__doc__ = "%s(%s)" % (cls.__name__, ", ".join(f.name for f in opts.fields))
get_absolute_url_override = settings.ABSOLUTE_URL_OVERRIDES.get( get_absolute_url_override = settings.ABSOLUTE_URL_OVERRIDES.get(opts.label_lower)
'%s.%s' % (opts.app_label, opts.model_name)
)
if get_absolute_url_override: if get_absolute_url_override:
setattr(cls, 'get_absolute_url', get_absolute_url_override) setattr(cls, 'get_absolute_url', get_absolute_url_override)
@ -1248,10 +1246,7 @@ class Model(six.with_metaclass(ModelBase)):
errors.append( errors.append(
checks.Error( checks.Error(
"The model has two many-to-many relations through " "The model has two many-to-many relations through "
"the intermediate model '%s.%s'." % ( "the intermediate model '%s'." % f.remote_field.through._meta.label,
f.remote_field.through._meta.app_label,
f.remote_field.through._meta.object_name
),
hint=None, hint=None,
obj=cls, obj=cls,
id='models.E003', id='models.E003',

View File

@ -76,9 +76,7 @@ class BaseManager(object):
def __str__(self): def __str__(self):
""" Return "app_label.model_label.manager_name". """ """ Return "app_label.model_label.manager_name". """
model = self.model return '%s.%s' % (self.model._meta.label, self.name)
app = model._meta.app_label
return '%s.%s.%s' % (app, model._meta.object_name, self.name)
def deconstruct(self): def deconstruct(self):
""" """

View File

@ -176,6 +176,14 @@ class Options(object):
m2m = link.is_relation and link.many_to_many m2m = link.is_relation and link.many_to_many
return link, model, direct, m2m return link, model, direct, m2m
@property
def label(self):
return '%s.%s' % (self.app_label, self.object_name)
@property
def label_lower(self):
return '%s.%s' % (self.app_label, self.model_name)
@property @property
def app_config(self): def app_config(self):
# Don't go through get_app_config to avoid triggering imports. # Don't go through get_app_config to avoid triggering imports.
@ -377,7 +385,6 @@ class Options(object):
case insensitive, so we make sure we are case insensitive here. case insensitive, so we make sure we are case insensitive here.
""" """
if self.swappable: if self.swappable:
model_label = '%s.%s' % (self.app_label, self.model_name)
swapped_for = getattr(settings, self.swappable, None) swapped_for = getattr(settings, self.swappable, None)
if swapped_for: if swapped_for:
try: try:
@ -389,7 +396,7 @@ class Options(object):
# or as part of validation. # or as part of validation.
return swapped_for return swapped_for
if '%s.%s' % (swapped_label, swapped_object.lower()) not in (None, model_label): if '%s.%s' % (swapped_label, swapped_object.lower()) not in (None, self.label_lower):
return swapped_for return swapped_for
return None return None

View File

@ -973,12 +973,12 @@ def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False):
(fk.remote_field.model != parent_model and (fk.remote_field.model != parent_model and
fk.remote_field.model not in parent_model._meta.get_parent_list()): fk.remote_field.model not in parent_model._meta.get_parent_list()):
raise ValueError( raise ValueError(
"fk_name '%s' is not a ForeignKey to '%s.%s'." "fk_name '%s' is not a ForeignKey to '%s'." % (fk_name, parent_model._meta.label)
% (fk_name, parent_model._meta.app_label, parent_model._meta.object_name)) )
elif len(fks_to_parent) == 0: elif len(fks_to_parent) == 0:
raise ValueError( raise ValueError(
"'%s.%s' has no field named '%s'." "'%s' has no field named '%s'." % (model._meta.label, fk_name)
% (model._meta.app_label, model._meta.object_name, fk_name)) )
else: else:
# Try to discover what the ForeignKey from model to parent_model is # Try to discover what the ForeignKey from model to parent_model is
fks_to_parent = [ fks_to_parent = [
@ -993,20 +993,16 @@ def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False):
if can_fail: if can_fail:
return return
raise ValueError( raise ValueError(
"'%s.%s' has no ForeignKey to '%s.%s'." % ( "'%s' has no ForeignKey to '%s'." % (
model._meta.app_label, model._meta.label,
model._meta.object_name, parent_model._meta.label,
parent_model._meta.app_label,
parent_model._meta.object_name,
) )
) )
else: else:
raise ValueError( raise ValueError(
"'%s.%s' has more than one ForeignKey to '%s.%s'." % ( "'%s' has more than one ForeignKey to '%s'." % (
model._meta.app_label, model._meta.label,
model._meta.object_name, parent_model._meta.label,
parent_model._meta.app_label,
parent_model._meta.object_name,
) )
) )
return fk return fk

View File

@ -29,6 +29,12 @@ Available ``Meta`` options
app_label = 'myapp' app_label = 'myapp'
.. versionadded:: 1.9
If you want to represent a model with the format ``app_label.object_name``
or ``app_label.model_name`` you can use ``model._meta.label``
or ``model._meta.label_lower`` respectively.
``db_table`` ``db_table``
------------ ------------
@ -397,3 +403,26 @@ Django quotes column and table names behind the scenes.
verbose_name_plural = "stories" verbose_name_plural = "stories"
If this isn't given, Django will use :attr:`~Options.verbose_name` + ``"s"``. If this isn't given, Django will use :attr:`~Options.verbose_name` + ``"s"``.
Read-only ``Meta`` attributes
=============================
``label``
---------
.. attribute:: Options.label
.. versionadded:: 1.9
Representation of the object, returns ``app_label.object_name``, e.g.
``'polls.Question'``.
``label_lower``
---------------
.. attribute:: Options.label_lower
.. versionadded:: 1.9
Representation of the model, returns ``app_label.model_name``, e.g.
``'polls.question'``.

View File

@ -791,4 +791,16 @@ TEST_RESULTS = {
'content_object_abstract', 'content_object_abstract',
], ],
}, },
'labels': {
AbstractPerson: 'model_meta.AbstractPerson',
BasePerson: 'model_meta.BasePerson',
Person: 'model_meta.Person',
Relating: 'model_meta.Relating',
},
'lower_labels': {
AbstractPerson: 'model_meta.abstractperson',
BasePerson: 'model_meta.baseperson',
Person: 'model_meta.person',
Relating: 'model_meta.relating',
},
} }

View File

@ -49,6 +49,17 @@ class GetFieldsTests(OptionsBaseTests):
fields += ["errors"] fields += ["errors"]
class LabelTests(OptionsBaseTests):
def test_label(self):
for model, expected_result in TEST_RESULTS['labels'].items():
self.assertEqual(model._meta.label, expected_result)
def test_label_lower(self):
for model, expected_result in TEST_RESULTS['lower_labels'].items():
self.assertEqual(model._meta.label_lower, expected_result)
class DataTests(OptionsBaseTests): class DataTests(OptionsBaseTests):
def test_fields(self): def test_fields(self):