Give every db table a __str__.
[zzz-pokedex.git] / pokedex / db / tables.py
index 6c18177..1929210 100644 (file)
@@ -56,25 +56,34 @@ class TableMetaclass(DeclarativeMeta):
         if hasattr(cls, '__tablename__'):
             table_classes.append(cls)
 
-metadata = MetaData()
-TableBase = declarative_base(metadata=metadata, metaclass=TableMetaclass)
-
-### Helper classes
-# XXX this stuff isn't covered anywhere; maybe put it in TableBase??
-class Named(object):
-    """Mixin for objects that have names"""
+class TableSuperclass(object):
+    """Superclass for declarative tables, to give them some generic niceties
+    like stringification.
+    """
     def __unicode__(self):
+        """Be as useful as possible.  Show the primary key, and an identifier
+        if we've got one.
+        """
+        typename = u'.'.join((__name__, type(self).__name__))
+
+        pk_constraint = self.__table__.primary_key
+        if not pk_constraint:
+            return u"<%s object at %x>" % (typename, id(self))
+
+        pk = u', '.join(unicode(getattr(self, column.name))
+            for column in pk_constraint.columns)
         try:
-            return '<%s: %s>' % (type(self).__name__, self.identifier)
+            return u"<%s object (%s): %s>" % (typename, pk, self.identifier)
         except AttributeError:
-            return '<%s>' % type(self).__name__
+            return u"<%s object (%s)>" % (typename, pk)
 
     def __str__(self):
-        return unicode(self).encode('utf-8')
+        return unicode(self).encode('utf8')
 
-    def __repr__(self):
-        return str(self)
+metadata = MetaData()
+TableBase = declarative_base(metadata=metadata, cls=TableSuperclass, metaclass=TableMetaclass)
 
+### Helper classes
 class LanguageSpecific(object):
     """Mixin for prose and text tables"""
     @declared_attr
@@ -1884,24 +1893,22 @@ def makeTextTable(object_table, name_plural, name_singular, columns, lazy):
         )
 
     mapper(Strings, table,
-            properties={
-                    "object_id": synonym(safe_name + '_id'),
-                    "language": relation(
-                            Language,
-                            primaryjoin=table.c.language_id == Language.id,
-                        ),
-                },
-        )
+        properties={
+            "object_id": synonym(safe_name + '_id'),
+            "language": relation(Language,
+                primaryjoin=table.c.language_id == Language.id,
+            ),
+            safe_name: relation(object_table,
+                primaryjoin=(object_table.id == table.c[safe_name + "_id"]),
+                backref=backref(name_plural,
+                    collection_class=attribute_mapped_collection('language'),
+                    lazy=lazy,
+                ),
+            ),
+        },
+    )
 
     # The relation to the object
-    setattr(object_table, name_plural, relation(
-            Strings,
-            primaryjoin=(object_table.id == Strings.object_id),
-            backref=safe_name,
-            collection_class=attribute_mapped_collection('language'),
-            lazy=lazy,
-        ))
-    str(getattr(object_table, name_plural))  # [MORE MAGIC].  aka do not remove, or entire app fails.  XXX what the fuck man
     Strings.object = getattr(Strings, safe_name)
 
     # Link the tables themselves, so we can get them if needed