Make Pokemon.form an actual relation
[zzz-pokedex.git] / pokedex / db / tables.py
index aaa2fcb..9553349 100644 (file)
@@ -15,14 +15,11 @@ Columns have a info dictionary with these keys:
   - identifier: A fan-made identifier in the [-_a-z0-9]* format. Not intended
     for translation.
   - latex: A formula in LaTeX syntax.
   - identifier: A fan-made identifier in the [-_a-z0-9]* format. Not intended
     for translation.
   - latex: A formula in LaTeX syntax.
+- ripped: True for text that has been ripped from the games, and can be ripped
+  again for new versions or languages
 
 
-A localizable text column is visible as two properties:
-The plural-name property (e.g. Pokemon.names) is a language-to-name dictionary:
-  bulbasaur.names['en'] == "Bulbasaur" and bulbasaur.names['de'] == "Bisasam".
-  You can use Pokemon.names['en'] to filter a query.
-The singular-name property returns the name in the default language, English.
-  For example bulbasaur.name == "Bulbasaur"
-  Setting pokedex.db.tables.default_lang changes the default language.
+See `pokedex.db.multilang` for how localizable text columns work.  The session
+classes in that module can be used to change the default language.
 """
 # XXX: Check if "gametext" is set correctly everywhere
 
 """
 # XXX: Check if "gametext" is set correctly everywhere
 
@@ -30,22 +27,14 @@ import collections
 from functools import partial
 
 from sqlalchemy import Column, ForeignKey, MetaData, PrimaryKeyConstraint, Table, UniqueConstraint
 from functools import partial
 
 from sqlalchemy import Column, ForeignKey, MetaData, PrimaryKeyConstraint, Table, UniqueConstraint
-from sqlalchemy.ext.declarative import (
-        declarative_base, declared_attr, DeclarativeMeta,
-    )
+from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta
 from sqlalchemy.ext.associationproxy import association_proxy
 from sqlalchemy.ext.associationproxy import association_proxy
-from sqlalchemy.orm import (
-        backref, compile_mappers, eagerload_all, relation, class_mapper, synonym, mapper,
-    )
-from sqlalchemy.orm.session import Session, object_session
+from sqlalchemy.orm import backref, relation
+from sqlalchemy.orm.session import Session
 from sqlalchemy.orm.interfaces import AttributeExtension
 from sqlalchemy.orm.interfaces import AttributeExtension
-from sqlalchemy.orm.collections import attribute_mapped_collection, MappedCollection, collection, collection_adapter
-from sqlalchemy.ext.associationproxy import _AssociationDict, association_proxy
-from sqlalchemy.sql import and_
-from sqlalchemy.sql.expression import ColumnOperators, bindparam
+from sqlalchemy.sql import and_, or_
 from sqlalchemy.schema import ColumnDefault
 from sqlalchemy.types import *
 from sqlalchemy.schema import ColumnDefault
 from sqlalchemy.types import *
-from inspect import isclass
 
 from pokedex.db import markdown, multilang
 
 
 from pokedex.db import markdown, multilang
 
@@ -73,14 +62,25 @@ class TableSuperclass(object):
     def __str__(self):
         return unicode(self).encode('utf8')
 
     def __str__(self):
         return unicode(self).encode('utf8')
 
+    def __repr__(self):
+        return unicode(self).encode('utf8')
+
+mapped_classes = []
+class TableMetaclass(DeclarativeMeta):
+    def __init__(cls, name, bases, attrs):
+        super(TableMetaclass, cls).__init__(name, bases, attrs)
+        if hasattr(cls, '__tablename__'):
+            mapped_classes.append(cls)
+            cls.translation_classes = []
+
 metadata = MetaData()
 metadata = MetaData()
-TableBase = declarative_base(metadata=metadata, cls=TableSuperclass)
+TableBase = declarative_base(metadata=metadata, cls=TableSuperclass, metaclass=TableMetaclass)
 
 
 ### Need Language first, to create the partial() below
 
 class Language(TableBase):
 
 
 ### Need Language first, to create the partial() below
 
 class Language(TableBase):
-    u"""A language the Pokémon games have been transleted into
+    u"""A language the Pokémon games have been translated into
     """
     __tablename__ = 'languages'
     __singlename__ = 'language'
     """
     __tablename__ = 'languages'
     __singlename__ = 'language'
@@ -119,13 +119,14 @@ class Ability(TableBase):
         info=dict(description="The ID of the generation this ability was introduced in", detail=True))
 
 create_translation_table('ability_names', Ability, 'names',
         info=dict(description="The ID of the generation this ability was introduced in", detail=True))
 
 create_translation_table('ability_names', Ability, 'names',
+    relation_lazy='joined',
     name = Column(Unicode(24), nullable=False, index=True,
     name = Column(Unicode(24), nullable=False, index=True,
-        info=dict(description="The name", format='plaintext', official=True)),
+        info=dict(description="The name", format='plaintext', official=True, ripped=True)),
 )
 create_translation_table('ability_prose', Ability, 'prose',
 )
 create_translation_table('ability_prose', Ability, 'prose',
-    effect = Column(markdown.MarkdownColumn(5120), nullable=False,
+    effect = Column(markdown.MarkdownColumn(5120), nullable=True,
         info=dict(description="A detailed description of this ability's effect", format='markdown')),
         info=dict(description="A detailed description of this ability's effect", format='markdown')),
-    short_effect = Column(markdown.MarkdownColumn(255), nullable=False,
+    short_effect = Column(markdown.MarkdownColumn(512), nullable=True,
         info=dict(description="A short summary of this ability's effect", format='markdown')),
 )
 
         info=dict(description="A short summary of this ability's effect", format='markdown')),
 )
 
@@ -196,6 +197,7 @@ class BerryFirmness(TableBase):
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('berry_firmness_names', BerryFirmness, 'names',
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('berry_firmness_names', BerryFirmness, 'names',
+    relation_lazy='joined',
     name = Column(Unicode(10), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
     name = Column(Unicode(10), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
@@ -233,9 +235,9 @@ class ContestEffect(TableBase):
         info=dict(description="The base number of hearts the user's opponent loses"))
 
 create_translation_table('contest_effect_prose', ContestEffect, 'prose',
         info=dict(description="The base number of hearts the user's opponent loses"))
 
 create_translation_table('contest_effect_prose', ContestEffect, 'prose',
-    flavor_text = Column(Unicode(64), nullable=False,
+    flavor_text = Column(Unicode(64), nullable=True,
         info=dict(description="The in-game description of this effect", official=True, format='gametext')),
         info=dict(description="The in-game description of this effect", official=True, format='gametext')),
-    effect = Column(Unicode(255), nullable=False,
+    effect = Column(Unicode(255), nullable=True,
         info=dict(description="A detailed description of the effect", format='plaintext')),
 )
 
         info=dict(description="A detailed description of the effect", format='plaintext')),
 )
 
@@ -250,11 +252,12 @@ class ContestType(TableBase):
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('contest_type_names', ContestType, 'names',
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('contest_type_names', ContestType, 'names',
-    name = Column(Unicode(6), nullable=False, index=True,
+    relation_lazy='joined',
+    name = Column(Unicode(6), nullable=True, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
         info=dict(description="The name", format='plaintext', official=True)),
-    flavor = Column(Unicode(6), nullable=False,
+    flavor = Column(Unicode(6), nullable=True,
         info=dict(description="The name of the corresponding Berry flavor", official=True, format='plaintext')),
         info=dict(description="The name of the corresponding Berry flavor", official=True, format='plaintext')),
-    color = Column(Unicode(6), nullable=False,
+    color = Column(Unicode(6), nullable=True,
         info=dict(description=u"The name of the corresponding Pokéblock color", official=True, format='plaintext')),
 )
 
         info=dict(description=u"The name of the corresponding Pokéblock color", official=True, format='plaintext')),
 )
 
@@ -271,8 +274,9 @@ class EggGroup(TableBase):
         info=dict(description=u"An identifier.", format='identifier'))
 
 create_translation_table('egg_group_prose', EggGroup, 'names',
         info=dict(description=u"An identifier.", format='identifier'))
 
 create_translation_table('egg_group_prose', EggGroup, 'names',
+    relation_lazy='joined',
     name = Column(Unicode(16), nullable=False, index=True,
     name = Column(Unicode(16), nullable=False, index=True,
-        info=dict(description="The name", format='plaintext', official=False)),
+        info=dict(description="The name", format='plaintext', official=True)),
 )
 
 class Encounter(TableBase):
 )
 
 class Encounter(TableBase):
@@ -284,10 +288,10 @@ class Encounter(TableBase):
     "slot" they are in and the state of the game world.
 
     What the player is doing to get an encounter, such as surfing or walking
     "slot" they are in and the state of the game world.
 
     What the player is doing to get an encounter, such as surfing or walking
-    through tall grass, is called terrain.  Each terrain has its own set of
+    through tall grass, is called a method.  Each method has its own set of
     encounter slots.
 
     encounter slots.
 
-    Within a terrain, slots are defined primarily by rarity.  Each slot can
+    Within a method, slots are defined primarily by rarity.  Each slot can
     also be affected by world conditions; for example, the 20% slot for walking
     in tall grass is affected by whether a swarm is in effect in that area.
     "Is there a swarm?" is a condition; "there is a swarm" and "there is not a
     also be affected by world conditions; for example, the 20% slot for walking
     in tall grass is affected by whether a swarm is in effect in that area.
     "Is there a swarm?" is a condition; "there is a swarm" and "there is not a
@@ -307,7 +311,7 @@ class Encounter(TableBase):
     location_area_id = Column(Integer, ForeignKey('location_areas.id'), nullable=False, autoincrement=False,
         info=dict(description="The ID of the location of this encounter"))
     encounter_slot_id = Column(Integer, ForeignKey('encounter_slots.id'), nullable=False, autoincrement=False,
     location_area_id = Column(Integer, ForeignKey('location_areas.id'), nullable=False, autoincrement=False,
         info=dict(description="The ID of the location of this encounter"))
     encounter_slot_id = Column(Integer, ForeignKey('encounter_slots.id'), nullable=False, autoincrement=False,
-        info=dict(description="The ID of the encounter slot, which determines terrain and rarity"))
+        info=dict(description="The ID of the encounter slot, which determines method and rarity"))
     pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False, autoincrement=False,
         info=dict(description=u"The ID of the encountered Pokémon"))
     min_level = Column(Integer, nullable=False, autoincrement=False,
     pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False, autoincrement=False,
         info=dict(description=u"The ID of the encountered Pokémon"))
     min_level = Column(Integer, nullable=False, autoincrement=False,
@@ -360,24 +364,24 @@ class EncounterConditionValueMap(TableBase):
     encounter_condition_value_id = Column(Integer, ForeignKey('encounter_condition_values.id'), primary_key=True, nullable=False, autoincrement=False,
         info=dict(description="The ID of the encounter condition value"))
 
     encounter_condition_value_id = Column(Integer, ForeignKey('encounter_condition_values.id'), primary_key=True, nullable=False, autoincrement=False,
         info=dict(description="The ID of the encounter condition value"))
 
-class EncounterTerrain(TableBase):
+class EncounterMethod(TableBase):
     u"""A way the player can enter a wild encounter, e.g., surfing, fishing, or walking through tall grass.
     """
 
     u"""A way the player can enter a wild encounter, e.g., surfing, fishing, or walking through tall grass.
     """
 
-    __tablename__ = 'encounter_terrain'
-    __singlename__ = __tablename__
+    __tablename__ = 'encounter_methods'
+    __singlename__ = 'encounter_method'
     id = Column(Integer, primary_key=True, nullable=False,
     id = Column(Integer, primary_key=True, nullable=False,
-        info=dict(description="A unique ID for the terrain"))
-    identifier = Column(Unicode(64), nullable=False,
+        info=dict(description="A unique ID for the method"))
+    identifier = Column(Unicode(16), nullable=False, unique=True,
         info=dict(description="An identifier", format='identifier'))
 
         info=dict(description="An identifier", format='identifier'))
 
-create_translation_table('encounter_terrain_prose', EncounterTerrain, 'prose',
+create_translation_table('encounter_method_prose', EncounterMethod, 'prose',
     name = Column(Unicode(64), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=False)),
 )
 
 class EncounterSlot(TableBase):
     name = Column(Unicode(64), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=False)),
 )
 
 class EncounterSlot(TableBase):
-    u"""An abstract "slot" within a terrain, associated with both some set of conditions and a rarity.
+    u"""An abstract "slot" within a method, associated with both some set of conditions and a rarity.
 
     Note that there are two encounters per slot, so the rarities will only add
     up to 50.
 
     Note that there are two encounters per slot, so the rarities will only add
     up to 50.
@@ -388,11 +392,11 @@ class EncounterSlot(TableBase):
         info=dict(description="A unique ID for this slot"))
     version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False, autoincrement=False,
         info=dict(description="The ID of the version group this slot is in"))
         info=dict(description="A unique ID for this slot"))
     version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False, autoincrement=False,
         info=dict(description="The ID of the version group this slot is in"))
-    encounter_terrain_id = Column(Integer, ForeignKey('encounter_terrain.id'), primary_key=False, nullable=False, autoincrement=False,
-        info=dict(description="The ID of the terrain"))
+    encounter_method_id = Column(Integer, ForeignKey('encounter_methods.id'), primary_key=False, nullable=False, autoincrement=False,
+        info=dict(description="The ID of the method"))
     slot = Column(Integer, nullable=True,
     slot = Column(Integer, nullable=True,
-        info=dict(description="This slot's order for the location and terrain"))
-    rarity = Column(Integer, nullable=False,
+        info=dict(description="This slot's order for the location and method"))
+    rarity = Column(Integer, nullable=True,
         info=dict(description="The chance of the encounter as a percentage"))
 
 class EvolutionChain(TableBase):
         info=dict(description="The chance of the encounter as a percentage"))
 
 class EvolutionChain(TableBase):
@@ -439,14 +443,15 @@ class Generation(TableBase):
     __singlename__ = 'generation'
     id = Column(Integer, primary_key=True, nullable=False,
         info=dict(description="A numeric ID"))
     __singlename__ = 'generation'
     id = Column(Integer, primary_key=True, nullable=False,
         info=dict(description="A numeric ID"))
-    main_region_id = Column(Integer, ForeignKey('regions.id'),
+    main_region_id = Column(Integer, ForeignKey('regions.id'), nullable=False,
         info=dict(description="ID of the region this generation's main games take place in"))
         info=dict(description="ID of the region this generation's main games take place in"))
-    canonical_pokedex_id = Column(Integer, ForeignKey('pokedexes.id'),
+    canonical_pokedex_id = Column(Integer, ForeignKey('pokedexes.id'), nullable=False,
         info=dict(description=u"ID of the Pokédex this generation's main games use by default"))
     identifier = Column(Unicode(16), nullable=False,
         info=dict(description=u'An identifier', format='identifier'))
 
 create_translation_table('generation_names', Generation, 'names',
         info=dict(description=u"ID of the Pokédex this generation's main games use by default"))
     identifier = Column(Unicode(16), nullable=False,
         info=dict(description=u'An identifier', format='identifier'))
 
 create_translation_table('generation_names', Generation, 'names',
+    relation_lazy='joined',
     name = Column(Unicode(16), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
     name = Column(Unicode(16), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
@@ -493,15 +498,20 @@ class Item(TableBase):
         return any(flag.identifier == u'underground' for flag in self.flags)
 
 create_translation_table('item_names', Item, 'names',
         return any(flag.identifier == u'underground' for flag in self.flags)
 
 create_translation_table('item_names', Item, 'names',
+    relation_lazy='joined',
     name = Column(Unicode(20), nullable=False, index=True,
     name = Column(Unicode(20), nullable=False, index=True,
-        info=dict(description="The name", format='plaintext', official=True)),
+        info=dict(description="The name", format='plaintext', official=True, ripped=True)),
 )
 create_translation_table('item_prose', Item, 'prose',
 )
 create_translation_table('item_prose', Item, 'prose',
-    short_effect = Column(Unicode(256), nullable=False,
-        info=dict(description="A short summary of the effect", format='plaintext')),
-    effect = Column(markdown.MarkdownColumn(5120), nullable=False,
+    short_effect = Column(markdown.MarkdownColumn(256), nullable=True,
+        info=dict(description="A short summary of the effect", format='markdown')),
+    effect = Column(markdown.MarkdownColumn(5120), nullable=True,
         info=dict(description=u"Detailed description of the item's effect.", format='markdown')),
 )
         info=dict(description=u"Detailed description of the item's effect.", format='markdown')),
 )
+create_translation_table('item_flavor_summaries', Item, 'flavor_summaries',
+    flavor_summary = Column(Unicode(512), nullable=True,
+        info=dict(description=u"Text containing facts from all flavor texts, for languages without official game translations", official=False, format='plaintext', ripped=True)),
+)
 
 class ItemCategory(TableBase):
     u"""An item category
 
 class ItemCategory(TableBase):
     u"""An item category
@@ -517,6 +527,7 @@ class ItemCategory(TableBase):
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('item_category_prose', ItemCategory, 'prose',
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('item_category_prose', ItemCategory, 'prose',
+    relation_lazy='joined',
     name = Column(Unicode(16), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=False)),
 )
     name = Column(Unicode(16), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=False)),
 )
@@ -532,9 +543,9 @@ class ItemFlag(TableBase):
         info=dict(description="Identifier of the flag", format='identifier'))
 
 create_translation_table('item_flag_prose', ItemFlag, 'prose',
         info=dict(description="Identifier of the flag", format='identifier'))
 
 create_translation_table('item_flag_prose', ItemFlag, 'prose',
-    name = Column(Unicode(24), nullable=False, index=True,
+    name = Column(Unicode(24), nullable=True, index=True,
         info=dict(description="The name", format='plaintext', official=False)),
         info=dict(description="The name", format='plaintext', official=False)),
-    description = Column(Unicode(64), nullable=False,
+    description = Column(Unicode(64), nullable=True,
         info=dict(description="Short description of the flag", format='plaintext')),
 )
 
         info=dict(description="Short description of the flag", format='plaintext')),
 )
 
@@ -552,6 +563,7 @@ class ItemFlavorText(TableBase):
     """
     __tablename__ = 'item_flavor_text'
     __singlename__ = 'item_flavor_text'
     """
     __tablename__ = 'item_flavor_text'
     __singlename__ = 'item_flavor_text'
+    summary_column = Item.flavor_summaries_table, 'flavor_summary'
     item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, autoincrement=False, nullable=False,
         info=dict(description="The ID of the item"))
     version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, autoincrement=False, nullable=False,
     item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, autoincrement=False, nullable=False,
         info=dict(description="The ID of the item"))
     version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, autoincrement=False, nullable=False,
@@ -596,6 +608,7 @@ class ItemPocket(TableBase):
         info=dict(description="An identifier of this pocket", format='identifier'))
 
 create_translation_table('item_pocket_names', ItemPocket, 'names',
         info=dict(description="An identifier of this pocket", format='identifier'))
 
 create_translation_table('item_pocket_names', ItemPocket, 'names',
+    relation_lazy='joined',
     name = Column(Unicode(16), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
     name = Column(Unicode(16), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
@@ -613,6 +626,7 @@ class Location(TableBase):
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('location_names', Location, 'names',
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('location_names', Location, 'names',
+    relation_lazy='joined',
     name = Column(Unicode(64), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
     name = Column(Unicode(64), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
@@ -632,6 +646,7 @@ class LocationArea(TableBase):
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('location_area_prose', LocationArea, 'prose',
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('location_area_prose', LocationArea, 'prose',
+    relation_lazy='joined',
     name = Column(Unicode(64), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=False)),
 )
     name = Column(Unicode(64), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=False)),
 )
@@ -641,8 +656,8 @@ class LocationAreaEncounterRate(TableBase):
     __tablename__ = 'location_area_encounter_rates'
     location_area_id = Column(Integer, ForeignKey('location_areas.id'), primary_key=True, nullable=False, autoincrement=False,
         info=dict(description="ID of the area"))
     __tablename__ = 'location_area_encounter_rates'
     location_area_id = Column(Integer, ForeignKey('location_areas.id'), primary_key=True, nullable=False, autoincrement=False,
         info=dict(description="ID of the area"))
-    encounter_terrain_id = Column(Integer, ForeignKey('encounter_terrain.id'), primary_key=True, nullable=False, autoincrement=False,
-        info=dict(description="ID of the terrain"))
+    encounter_method_id = Column(Integer, ForeignKey('encounter_methods.id'), primary_key=True, nullable=False, autoincrement=False,
+        info=dict(description="ID of the method"))
     version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, autoincrement=False,
         info=dict(description="ID of the version"))
     rate = Column(Integer, nullable=True,
     version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, autoincrement=False,
         info=dict(description="ID of the version"))
     rate = Column(Integer, nullable=True,
@@ -656,7 +671,7 @@ class LocationGameIndex(TableBase):
         info=dict(description="Database ID of the locaion"))
     generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False, primary_key=True,
         info=dict(description="ID of the generation this entry to"))
         info=dict(description="Database ID of the locaion"))
     generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False, primary_key=True,
         info=dict(description="ID of the generation this entry to"))
-    game_index = Column(Integer, nullable=False,
+    game_index = Column(Integer, nullable=False, primary_key=True, autoincrement=False,
         info=dict(description="Internal game ID of the location"))
 
 class Machine(TableBase):
         info=dict(description="Internal game ID of the location"))
 
 class Machine(TableBase):
@@ -678,6 +693,52 @@ class Machine(TableBase):
         """
         return self.machine_number >= 100
 
         """
         return self.machine_number >= 100
 
+class Move(TableBase):
+    u"""A Move: technique or attack a Pokémon can learn to use
+    """
+    __tablename__ = 'moves'
+    __singlename__ = 'move'
+    id = Column(Integer, primary_key=True, nullable=False,
+        info=dict(description="A numeric ID"))
+    identifier = Column(Unicode(24), nullable=False,
+        info=dict(description="An identifier", format='identifier'))
+    generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
+        info=dict(description="ID of the generation this move first appeared in"))
+    type_id = Column(Integer, ForeignKey('types.id'), nullable=False,
+        info=dict(description="ID of the move's elemental type"))
+    power = Column(SmallInteger, nullable=False,
+        info=dict(description="Base power of the move"))
+    pp = Column(SmallInteger, nullable=True,
+        info=dict(description="Base PP (Power Points) of the move, nullable if not applicable (e.g. Struggle and Shadow moves)."))
+    accuracy = Column(SmallInteger, nullable=True,
+        info=dict(description="Accuracy of the move; NULL means it never misses"))
+    priority = Column(SmallInteger, nullable=False,
+        info=dict(description="The move's priority bracket"))
+    target_id = Column(Integer, ForeignKey('move_targets.id'), nullable=False,
+        info=dict(description="ID of the target (range) of the move"))
+    damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=False,
+        info=dict(description="ID of the damage class (physical/special) of the move"))
+    effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=False,
+        info=dict(description="ID of the move's effect"))
+    effect_chance = Column(Integer, nullable=True,
+        info=dict(description="The chance for a secondary effect. What this is a chance of is specified by the move's effect."))
+    contest_type_id = Column(Integer, ForeignKey('contest_types.id'), nullable=True,
+        info=dict(description="ID of the move's Contest type (e.g. cool or smart)"))
+    contest_effect_id = Column(Integer, ForeignKey('contest_effects.id'), nullable=True,
+        info=dict(description="ID of the move's Contest effect"))
+    super_contest_effect_id = Column(Integer, ForeignKey('super_contest_effects.id'), nullable=True,
+        info=dict(description="ID of the move's Super Contest effect"))
+
+create_translation_table('move_names', Move, 'names',
+    relation_lazy='joined',
+    name = Column(Unicode(24), nullable=False, index=True,
+        info=dict(description="The name", format='plaintext', official=True, ripped=True))
+)
+create_translation_table('move_flavor_summaries', Move, 'flavor_summaries',
+    flavor_summary = Column(Unicode(512), nullable=True,
+        info=dict(description=u"Text containing facts from all flavor texts, for languages without official game translations", official=False, format='plaintext', ripped=True)),
+)
+
 class MoveBattleStyle(TableBase):
     u"""A battle style of a move"""  # XXX: Explain better
     __tablename__ = 'move_battle_styles'
 class MoveBattleStyle(TableBase):
     u"""A battle style of a move"""  # XXX: Explain better
     __tablename__ = 'move_battle_styles'
@@ -688,37 +749,31 @@ class MoveBattleStyle(TableBase):
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('move_battle_style_prose', MoveBattleStyle, 'prose',
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('move_battle_style_prose', MoveBattleStyle, 'prose',
+    relation_lazy='joined',
     name = Column(Unicode(8), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=False)),
 )
 
     name = Column(Unicode(8), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=False)),
 )
 
-class MoveEffectCategory(TableBase):
-    u"""Category of a move effect
-    """
-    __tablename__ = 'move_effect_categories'
-    __singlename__ = 'move_effect_category'
-    id = Column(Integer, primary_key=True, nullable=False,
-        info=dict(description="A numeric ID"))
-    identifier = Column(Unicode(64), nullable=False,
-        info=dict(description="An identifier", format='identifier'))
-    can_affect_user = Column(Boolean, nullable=False,
-        info=dict(description="Set if the user can be affected"))
-
-create_translation_table('move_effect_category_prose', MoveEffectCategory, 'prose',
-    name = Column(Unicode(64), nullable=False, index=True,
-        info=dict(description="The name", format='plaintext', official=False)),
-)
-
-class MoveEffectCategoryMap(TableBase):
-    u"""Maps a move effect category to a move effect
-    """
-    __tablename__ = 'move_effect_category_map'
-    move_effect_id = Column(Integer, ForeignKey('move_effects.id'), primary_key=True, nullable=False,
-        info=dict(description="ID of the move effect"))
-    move_effect_category_id = Column(Integer, ForeignKey('move_effect_categories.id'), primary_key=True, nullable=False,
-        info=dict(description="ID of the category"))
-    affects_user = Column(Boolean, primary_key=True, nullable=False,
-        info=dict(description="Set if the user is affected"))
+class MoveChangelog(TableBase):
+    """History of changes to moves across main game versions."""
+    __tablename__ = 'move_changelog'
+    __singlename__ = 'move_changelog'
+    move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False,
+        info=dict(description="ID of the move that changed"))
+    changed_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False,
+        info=dict(description="ID of the version group in which the move changed"))
+    type_id = Column(Integer, ForeignKey('types.id'), nullable=True,
+        info=dict(description="Prior type of the move, or NULL if unchanged"))
+    power = Column(SmallInteger, nullable=True,
+        info=dict(description="Prior base power of the move, or NULL if unchanged"))
+    pp = Column(SmallInteger, nullable=True,
+        info=dict(description="Prior base PP of the move, or NULL if unchanged"))
+    accuracy = Column(SmallInteger, nullable=True,
+        info=dict(description="Prior accuracy of the move, or NULL if unchanged"))
+    effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=True,
+        info=dict(description="Prior ID of the effect, or NULL if unchanged"))
+    effect_chance = Column(Integer, nullable=True,
+        info=dict(description="Prior effect chance, or NULL if unchanged"))
 
 class MoveDamageClass(TableBase):
     u"""Any of the damage classes moves can have, i.e. physical, special, or non-damaging.
 
 class MoveDamageClass(TableBase):
     u"""Any of the damage classes moves can have, i.e. physical, special, or non-damaging.
@@ -731,9 +786,10 @@ class MoveDamageClass(TableBase):
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('move_damage_class_prose', MoveDamageClass, 'prose',
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('move_damage_class_prose', MoveDamageClass, 'prose',
-    name = Column(Unicode(16), nullable=False, index=True,
+    relation_lazy='joined',
+    name = Column(Unicode(16), nullable=True, index=True,
         info=dict(description="The name", format='plaintext', official=False)),
         info=dict(description="The name", format='plaintext', official=False)),
-    description = Column(Unicode(64), nullable=False,
+    description = Column(Unicode(64), nullable=True,
         info=dict(description="A description of the class", format='plaintext')),
 )
 
         info=dict(description="A description of the class", format='plaintext')),
 )
 
@@ -746,10 +802,10 @@ class MoveEffect(TableBase):
         info=dict(description="A numeric ID"))
 
 create_translation_table('move_effect_prose', MoveEffect, 'prose',
         info=dict(description="A numeric ID"))
 
 create_translation_table('move_effect_prose', MoveEffect, 'prose',
-    short_effect = Column(Unicode(256), nullable=False,
+    short_effect = Column(Unicode(256), nullable=True,
         info=dict(description="A short summary of the effect", format='plaintext')),
         info=dict(description="A short summary of the effect", format='plaintext')),
-    effect = Column(Unicode(5120), nullable=False,
-        info=dict(description="A detailed description of the effect", format='plaintext')),
+    effect = Column(Unicode(5120), nullable=True,
+        info=dict(description="A detailed description of the effect", format='markdown')),
 )
 
 class MoveEffectChangelog(TableBase):
 )
 
 class MoveEffectChangelog(TableBase):
@@ -795,9 +851,10 @@ class MoveFlagType(TableBase):
         info=dict(description="A short identifier for the flag", format='identifier'))
 
 create_translation_table('move_flag_type_prose', MoveFlagType, 'prose',
         info=dict(description="A short identifier for the flag", format='identifier'))
 
 create_translation_table('move_flag_type_prose', MoveFlagType, 'prose',
-    name = Column(Unicode(32), nullable=False, index=True,
+    relation_lazy='joined',
+    name = Column(Unicode(32), nullable=True, index=True,
         info=dict(description="The name", format='plaintext', official=False)),
         info=dict(description="The name", format='plaintext', official=False)),
-    description = Column(markdown.MarkdownColumn(128), nullable=False,
+    description = Column(markdown.MarkdownColumn(256), nullable=True,
         info=dict(description="A short description of the flag", format='markdown')),
 )
 
         info=dict(description="A short description of the flag", format='markdown')),
 )
 
@@ -805,6 +862,7 @@ class MoveFlavorText(TableBase):
     u"""In-game description of a move
     """
     __tablename__ = 'move_flavor_text'
     u"""In-game description of a move
     """
     __tablename__ = 'move_flavor_text'
+    summary_column = Move.flavor_summaries_table, 'flavor_summary'
     move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
         info=dict(description="ID of the move"))
     version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
     move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False,
         info=dict(description="ID of the move"))
     version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False,
@@ -850,12 +908,13 @@ class MoveMetaAilment(TableBase):
     """
     __tablename__ = 'move_meta_ailments'
     __singlename__ = 'move_meta_ailment'
     """
     __tablename__ = 'move_meta_ailments'
     __singlename__ = 'move_meta_ailment'
-    id = Column(Integer, primary_key=True, nullable=False,
+    id = Column(Integer, primary_key=True, nullable=False, autoincrement=False,
         info=dict(description="A numeric ID"))
         info=dict(description="A numeric ID"))
-    identifier = Column(Unicode(24), nullable=False,
+    identifier = Column(Unicode(24), nullable=False, index=True, unique=True,
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('move_meta_ailment_names', MoveMetaAilment, 'names',
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('move_meta_ailment_names', MoveMetaAilment, 'names',
+    relation_lazy='joined',
     name = Column(Unicode(24), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
     name = Column(Unicode(24), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
@@ -866,10 +925,13 @@ class MoveMetaCategory(TableBase):
     __singlename__ = 'move_meta_category'
     id = Column(Integer, primary_key=True, nullable=False,
         info=dict(description="A numeric ID"))
     __singlename__ = 'move_meta_category'
     id = Column(Integer, primary_key=True, nullable=False,
         info=dict(description="A numeric ID"))
+    identifier = Column(Unicode(32), nullable=False, index=True, unique=True,
+        info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('move_meta_category_prose', MoveMetaCategory, 'prose',
 
 create_translation_table('move_meta_category_prose', MoveMetaCategory, 'prose',
+    relation_lazy='joined',
     description = Column(Unicode(64), nullable=False,
     description = Column(Unicode(64), nullable=False,
-        info=dict(description="A description of the category")),
+        info=dict(description="A description of the category", format="plaintext", official=False)),
 )
 
 class MoveMetaStatChange(TableBase):
 )
 
 class MoveMetaStatChange(TableBase):
@@ -893,75 +955,13 @@ class MoveTarget(TableBase):
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('move_target_prose', MoveTarget, 'prose',
         info=dict(description="An identifier", format='identifier'))
 
 create_translation_table('move_target_prose', MoveTarget, 'prose',
-    name = Column(Unicode(32), nullable=False, index=True,
+    relation_lazy='joined',
+    name = Column(Unicode(32), nullable=True, index=True,
         info=dict(description="The name", format='plaintext', official=False)),
         info=dict(description="The name", format='plaintext', official=False)),
-    description = Column(Unicode(128), nullable=False,
+    description = Column(Unicode(128), nullable=True,
         info=dict(description="A description", format='plaintext')),
 )
 
         info=dict(description="A description", format='plaintext')),
 )
 
-class Move(TableBase):
-    u"""A Move: technique or attack a Pokémon can learn to use
-    """
-    __tablename__ = 'moves'
-    __singlename__ = 'move'
-    id = Column(Integer, primary_key=True, nullable=False,
-        info=dict(description="A numeric ID"))
-    identifier = Column(Unicode(24), nullable=False,
-        info=dict(description="An identifier", format='identifier'))
-    generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False,
-        info=dict(description="ID of the generation this move first appeared in"))
-    type_id = Column(Integer, ForeignKey('types.id'), nullable=False,
-        info=dict(description="ID of the move's elemental type"))
-    power = Column(SmallInteger, nullable=False,
-        info=dict(description="Base power of the move"))
-    pp = Column(SmallInteger, nullable=True,
-        info=dict(description="Base PP (Power Points) of the move, nullable if not applicable (e.g. Struggle and Shadow moves)."))
-    accuracy = Column(SmallInteger, nullable=True,
-        info=dict(description="Accuracy of the move; NULL means it never misses"))
-    priority = Column(SmallInteger, nullable=False,
-        info=dict(description="The move's priority bracket"))
-    target_id = Column(Integer, ForeignKey('move_targets.id'), nullable=False,
-        info=dict(description="ID of the target (range) of the move"))
-    damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=False,
-        info=dict(description="ID of the damage class (physical/special) of the move"))
-    effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=False,
-        info=dict(description="ID of the move's effect"))
-    effect_chance = Column(Integer, nullable=True,
-        info=dict(description="The chance for a secondary effect. What this is a chance of is specified by the move's effect."))
-    contest_type_id = Column(Integer, ForeignKey('contest_types.id'), nullable=True,
-        info=dict(description="ID of the move's Contest type (e.g. cool or smart)"))
-    contest_effect_id = Column(Integer, ForeignKey('contest_effects.id'), nullable=True,
-        info=dict(description="ID of the move's Contest effect"))
-    super_contest_effect_id = Column(Integer, ForeignKey('super_contest_effects.id'), nullable=True,
-        info=dict(description="ID of the move's Super Contest effect"))
-
-create_translation_table('move_names', Move, 'names',
-    name = Column(Unicode(24), nullable=False, index=True,
-        info=dict(description="The name", format='plaintext', official=True))
-)
-
-
-class MoveChangelog(TableBase):
-    """History of changes to moves across main game versions."""
-    __tablename__ = 'move_changelog'
-    __singlename__ = 'move_changelog'
-    move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False,
-        info=dict(description="ID of the move that changed"))
-    changed_in_version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False,
-        info=dict(description="ID of the version group in which the move changed"))
-    type_id = Column(Integer, ForeignKey('types.id'), nullable=True,
-        info=dict(description="Prior type of the move, or NULL if unchanged"))
-    power = Column(SmallInteger, nullable=True,
-        info=dict(description="Prior base power of the move, or NULL if unchanged"))
-    pp = Column(SmallInteger, nullable=True,
-        info=dict(description="Prior base PP of the move, or NULL if unchanged"))
-    accuracy = Column(SmallInteger, nullable=True,
-        info=dict(description="Prior accuracy of the move, or NULL if unchanged"))
-    effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=True,
-        info=dict(description="Prior ID of the effect, or NULL if unchanged"))
-    effect_chance = Column(Integer, nullable=True,
-        info=dict(description="Prior effect chance, or NULL if unchanged"))
-
 class Nature(TableBase):
     u"""A nature a Pokémon can have, such as Calm or Brave
     """
 class Nature(TableBase):
     u"""A nature a Pokémon can have, such as Calm or Brave
     """
@@ -988,8 +988,9 @@ class Nature(TableBase):
         return self.increased_stat_id == self.decreased_stat_id
 
 create_translation_table('nature_names', Nature, 'names',
         return self.increased_stat_id == self.decreased_stat_id
 
 create_translation_table('nature_names', Nature, 'names',
+    relation_lazy='joined',
     name = Column(Unicode(8), nullable=False, index=True,
     name = Column(Unicode(8), nullable=False, index=True,
-        info=dict(description="The name", format='plaintext', official=True)),
+        info=dict(description="The name", format='plaintext', official=True, ripped=True)),
 )
 
 class NatureBattleStylePreference(TableBase):
 )
 
 class NatureBattleStylePreference(TableBase):
@@ -1047,9 +1048,10 @@ class Pokedex(TableBase):
         info=dict(description=u"An identifier", format='identifier'))
 
 create_translation_table('pokedex_prose', Pokedex, 'prose',
         info=dict(description=u"An identifier", format='identifier'))
 
 create_translation_table('pokedex_prose', Pokedex, 'prose',
-    name = Column(Unicode(16), nullable=False, index=True,
+    relation_lazy='joined',
+    name = Column(Unicode(16), nullable=True, index=True,
         info=dict(description="The name", format='plaintext', official=False)),
         info=dict(description="The name", format='plaintext', official=False)),
-    description = Column(Unicode(512), nullable=False,
+    description = Column(Unicode(512), nullable=True,
         info=dict(description=u"A longer description of the Pokédex", format='plaintext')),
 )
 
         info=dict(description=u"A longer description of the Pokédex", format='plaintext')),
 )
 
@@ -1066,13 +1068,15 @@ class Pokemon(TableBase):
         info=dict(description=u"ID of the generation this species first appeared in"))
     evolution_chain_id = Column(Integer, ForeignKey('evolution_chains.id'),
         info=dict(description=u"ID of the species' evolution chain (a.k.a. family)"))
         info=dict(description=u"ID of the generation this species first appeared in"))
     evolution_chain_id = Column(Integer, ForeignKey('evolution_chains.id'),
         info=dict(description=u"ID of the species' evolution chain (a.k.a. family)"))
+    evolves_from_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=True,
+        info=dict(description=u"The Pokémon species from which this one evolves"))
     height = Column(Integer, nullable=False,
         info=dict(description=u"The height of the Pokémon, in decimeters (tenths of a meter)"))
     weight = Column(Integer, nullable=False,
         info=dict(description=u"The weight of the Pokémon, in tenths of a kilogram (decigrams)"))
     color_id = Column(Integer, ForeignKey('pokemon_colors.id'), nullable=False,
         info=dict(description=u"ID of this Pokémon's Pokédex color, as used for a gimmick search function in the games."))
     height = Column(Integer, nullable=False,
         info=dict(description=u"The height of the Pokémon, in decimeters (tenths of a meter)"))
     weight = Column(Integer, nullable=False,
         info=dict(description=u"The weight of the Pokémon, in tenths of a kilogram (decigrams)"))
     color_id = Column(Integer, ForeignKey('pokemon_colors.id'), nullable=False,
         info=dict(description=u"ID of this Pokémon's Pokédex color, as used for a gimmick search function in the games."))
-    pokemon_shape_id = Column(Integer, ForeignKey('pokemon_shapes.id'), nullable=True,
+    pokemon_shape_id = Column(Integer, ForeignKey('pokemon_shapes.id'), nullable=False,
         info=dict(description=u"ID of this Pokémon's body shape, as used for a gimmick search function in the games."))
     habitat_id = Column(Integer, ForeignKey('pokemon_habitats.id'), nullable=True,
         info=dict(description=u"ID of this Pokémon's habitat, as used for a gimmick search function in the games."))
         info=dict(description=u"ID of this Pokémon's body shape, as used for a gimmick search function in the games."))
     habitat_id = Column(Integer, ForeignKey('pokemon_habitats.id'), nullable=True,
         info=dict(description=u"ID of this Pokémon's habitat, as used for a gimmick search function in the games."))
@@ -1096,12 +1100,6 @@ class Pokemon(TableBase):
     ### Stuff to handle alternate Pokémon forms
 
     @property
     ### Stuff to handle alternate Pokémon forms
 
     @property
-    def form(self):
-        u"""Returns the Pokémon's form, using its default form as fallback."""
-
-        return self.unique_form or self.default_form
-
-    @property
     def is_base_form(self):
         u"""Returns True iff the Pokémon is the base form for its species,
         e.g. Land Shaymin.
     def is_base_form(self):
         u"""Returns True iff the Pokémon is the base form for its species,
         e.g. Land Shaymin.
@@ -1125,7 +1123,7 @@ class Pokemon(TableBase):
         u"""Returns the Pokémon's name, including its form if applicable."""
 
         if self.form_name:
         u"""Returns the Pokémon's name, including its form if applicable."""
 
         if self.form_name:
-            return u'{0} {1}'.format(self.form_name, self.name)
+            return u'%s %s' % (self.form_name, self.name)
         else:
             return self.name
 
         else:
             return self.name
 
@@ -1176,12 +1174,17 @@ class Pokemon(TableBase):
             return None
 
 create_translation_table('pokemon_names', Pokemon, 'names',
             return None
 
 create_translation_table('pokemon_names', Pokemon, 'names',
-    name = Column(Unicode(20), nullable=False, index=True,
-        info=dict(description="The name", format='plaintext', official=True)),
-    species = Column(Unicode(16), nullable=False,
+    relation_lazy='joined',
+    name = Column(Unicode(20), nullable=True, index=True,
+        info=dict(description="The name", format='plaintext', official=True, ripped=True)),
+    species = Column(Unicode(16), nullable=True,
         info=dict(description=u'The short flavor text, such as "Seed" or "Lizard"; usually affixed with the word "Pokémon"',
         official=True, format='plaintext')),
 )
         info=dict(description=u'The short flavor text, such as "Seed" or "Lizard"; usually affixed with the word "Pokémon"',
         official=True, format='plaintext')),
 )
+create_translation_table('pokemon_flavor_summaries', Pokemon, 'flavor_summaries',
+    flavor_summary = Column(Unicode(512), nullable=True,
+        info=dict(description=u"Text containing facts from all flavor texts, for languages without official game translations", official=False, format='plaintext', ripped=True)),
+)
 
 class PokemonAbility(TableBase):
     u"""Maps an ability to a Pokémon that can have it
 
 class PokemonAbility(TableBase):
     u"""Maps an ability to a Pokémon that can have it
@@ -1210,6 +1213,7 @@ class PokemonColor(TableBase):
         info=dict(description=u"An identifier", format='identifier'))
 
 create_translation_table('pokemon_color_names', PokemonColor, 'names',
         info=dict(description=u"An identifier", format='identifier'))
 
 create_translation_table('pokemon_color_names', PokemonColor, 'names',
+    relation_lazy='joined',
     name = Column(Unicode(6), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
     name = Column(Unicode(6), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
@@ -1241,9 +1245,9 @@ class PokemonEvolution(TableBase):
     Any condition may be null if it does not apply for a particular Pokémon.
     """
     __tablename__ = 'pokemon_evolution'
     Any condition may be null if it does not apply for a particular Pokémon.
     """
     __tablename__ = 'pokemon_evolution'
-    from_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False,
-        info=dict(description=u"The ID of the pre-evolution Pokémon."))
-    to_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
+    id = Column(Integer, primary_key=True, nullable=False,
+        info=dict(description=u"A numeric ID"))
+    evolved_pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False,
         info=dict(description=u"The ID of the post-evolution Pokémon."))
     evolution_trigger_id = Column(Integer, ForeignKey('evolution_triggers.id'), nullable=False,
         info=dict(description=u"The ID of the evolution trigger."))
         info=dict(description=u"The ID of the post-evolution Pokémon."))
     evolution_trigger_id = Column(Integer, ForeignKey('evolution_triggers.id'), nullable=False,
         info=dict(description=u"The ID of the evolution trigger."))
@@ -1276,6 +1280,7 @@ class PokemonFlavorText(TableBase):
     u"""In-game Pokédex descrption of a Pokémon.
     """
     __tablename__ = 'pokemon_flavor_text'
     u"""In-game Pokédex descrption of a Pokémon.
     """
     __tablename__ = 'pokemon_flavor_text'
+    summary_column = Pokemon.flavor_summaries_table, 'flavor_summary'
     pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
         info=dict(description=u"ID of the Pokémon"))
     version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False,
     pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False,
         info=dict(description=u"ID of the Pokémon"))
     version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False,
@@ -1283,7 +1288,7 @@ class PokemonFlavorText(TableBase):
     language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
         info=dict(description="The language"))
     flavor_text = Column(Unicode(255), nullable=False,
     language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False,
         info=dict(description="The language"))
     flavor_text = Column(Unicode(255), nullable=False,
-        info=dict(description=u"ID of the version that has this flavor text", official=True, format='gametext'))
+        info=dict(description=u"The flavor text", official=True, format='gametext'))
 
 class PokemonForm(TableBase):
     u"""An individual form of a Pokémon.
 
 class PokemonForm(TableBase):
     u"""An individual form of a Pokémon.
@@ -1309,20 +1314,13 @@ class PokemonForm(TableBase):
         info=dict(description=u'The order in which forms should be sorted.  Multiple forms may have equal order, in which case they should fall back on sorting by name.'))
 
     @property
         info=dict(description=u'The order in which forms should be sorted.  Multiple forms may have equal order, in which case they should fall back on sorting by name.'))
 
     @property
-    def pokemon(self):
-        u"""Returns the Pokémon for this form, using the form base as fallback.
-        """
-
-        return self.unique_pokemon or self.form_base_pokemon
-
-    @property
     def full_name(self):
         u"""Returns the full name of this form, e.g. "Plant Cloak"."""
 
         if not self.name:
             return None
         elif self.form_group and self.form_group.term:
     def full_name(self):
         u"""Returns the full name of this form, e.g. "Plant Cloak"."""
 
         if not self.name:
             return None
         elif self.form_group and self.form_group.term:
-            return u'{0} {1}'.format(self.name, self.form_group.term)
+            return u'%s %s' % (self.name, self.form_group.term)
         else:
             return self.name
 
         else:
             return self.name
 
@@ -1333,11 +1331,12 @@ class PokemonForm(TableBase):
         """
 
         if self.name:
         """
 
         if self.name:
-            return u'{0} {1}'.format(self.name, self.form_base_pokemon.name)
+            return u'%s %s' % (self.name, self.form_base_pokemon.name)
         else:
             return self.form_base_pokemon.name
 
 create_translation_table('pokemon_form_names', PokemonForm, 'names',
         else:
             return self.form_base_pokemon.name
 
 create_translation_table('pokemon_form_names', PokemonForm, 'names',
+    relation_lazy='joined',
     name = Column(Unicode(16), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
     name = Column(Unicode(16), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
@@ -1356,7 +1355,7 @@ PokemonFormGroup.id = PokemonFormGroup.pokemon_id
 create_translation_table('pokemon_form_group_prose', PokemonFormGroup, 'prose',
     term = Column(Unicode(16), nullable=True,
         info=dict(description=u"The term for this Pokémon's forms, e.g. \"Cloak\" for Burmy or \"Forme\" for Deoxys.", official=True, format='plaintext')),
 create_translation_table('pokemon_form_group_prose', PokemonFormGroup, 'prose',
     term = Column(Unicode(16), nullable=True,
         info=dict(description=u"The term for this Pokémon's forms, e.g. \"Cloak\" for Burmy or \"Forme\" for Deoxys.", official=True, format='plaintext')),
-    description = Column(markdown.MarkdownColumn(1024), nullable=False,
+    description = Column(markdown.MarkdownColumn(1024), nullable=True,
         info=dict(description=u"Description of how the forms work", format='markdown')),
 )
 
         info=dict(description=u"Description of how the forms work", format='markdown')),
 )
 
@@ -1374,6 +1373,17 @@ class PokemonFormPokeathlonStat(TableBase):
     maximum_stat = Column(Integer, nullable=False, autoincrement=False,
         info=dict(description=u'The maximum value for this stat for this Pokémon form.'))
 
     maximum_stat = Column(Integer, nullable=False, autoincrement=False,
         info=dict(description=u'The maximum value for this stat for this Pokémon form.'))
 
+class PokemonGameIndex(TableBase):
+    u"""The number of a Pokémon a game uses internally
+    """
+    __tablename__ = 'pokemon_game_indices'
+    pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, autoincrement=False, nullable=False,
+        info=dict(description=u"Database ID of the Pokémon"))
+    generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, autoincrement=False, nullable=False,
+        info=dict(description=u"Database ID of the generation"))
+    game_index = Column(Integer, nullable=False,
+        info=dict(description=u"Internal ID the generation's games use for the Pokémon"))
+
 class PokemonHabitat(TableBase):
     u"""The habitat of a Pokémon, as given in the FireRed/LeafGreen version Pokédex
     """
 class PokemonHabitat(TableBase):
     u"""The habitat of a Pokémon, as given in the FireRed/LeafGreen version Pokédex
     """
@@ -1385,21 +1395,11 @@ class PokemonHabitat(TableBase):
         info=dict(description=u"An identifier", format='identifier'))
 
 create_translation_table('pokemon_habitat_names', PokemonHabitat, 'names',
         info=dict(description=u"An identifier", format='identifier'))
 
 create_translation_table('pokemon_habitat_names', PokemonHabitat, 'names',
+    relation_lazy='joined',
     name = Column(Unicode(16), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
 
     name = Column(Unicode(16), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
 
-class PokemonGameIndex(TableBase):
-    u"""The number of a Pokémon a game uses internally
-    """
-    __tablename__ = 'pokemon_game_indices'
-    pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, autoincrement=False, nullable=False,
-        info=dict(description=u"Database ID of the Pokémon"))
-    generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, autoincrement=False, nullable=False,
-        info=dict(description=u"Database ID of the generation"))
-    game_index = Column(Integer, nullable=False,
-        info=dict(description=u"Internal ID the generation's games use for the Pokémon"))
-
 class PokemonItem(TableBase):
     u"""Record of an item a Pokémon can hold in the wild
     """
 class PokemonItem(TableBase):
     u"""Record of an item a Pokémon can hold in the wild
     """
@@ -1446,13 +1446,13 @@ class PokemonMoveMethod(TableBase):
         info=dict(description=u"An identifier", format='identifier'))
 
 create_translation_table('pokemon_move_method_prose', PokemonMoveMethod, 'prose',
         info=dict(description=u"An identifier", format='identifier'))
 
 create_translation_table('pokemon_move_method_prose', PokemonMoveMethod, 'prose',
-    name = Column(Unicode(64), nullable=False, index=True,
+    relation_lazy='joined',
+    name = Column(Unicode(64), nullable=True, index=True,
         info=dict(description="The name", format='plaintext', official=False)),
         info=dict(description="The name", format='plaintext', official=False)),
-    description = Column(Unicode(255), nullable=False,
+    description = Column(Unicode(255), nullable=True,
         info=dict(description=u"A detailed description of how the method works", format='plaintext')),
 )
 
         info=dict(description=u"A detailed description of how the method works", format='plaintext')),
 )
 
-
 class PokemonShape(TableBase):
     u"""The shape of a Pokémon's body, as used in generation IV Pokédexes.
     """
 class PokemonShape(TableBase):
     u"""The shape of a Pokémon's body, as used in generation IV Pokédexes.
     """
@@ -1464,9 +1464,10 @@ class PokemonShape(TableBase):
         info=dict(description=u"An identifier", format='identifier'))
 
 create_translation_table('pokemon_shape_prose', PokemonShape, 'prose',
         info=dict(description=u"An identifier", format='identifier'))
 
 create_translation_table('pokemon_shape_prose', PokemonShape, 'prose',
-    name = Column(Unicode(24), nullable=False, index=True,
+    relation_lazy='joined',
+    name = Column(Unicode(24), nullable=True, index=True,
         info=dict(description="The name", format='plaintext', official=False)),
         info=dict(description="The name", format='plaintext', official=False)),
-    awesome_name = Column(Unicode(16), nullable=False,
+    awesome_name = Column(Unicode(16), nullable=True,
         info=dict(description=u"A splendiferous name of the body shape", format='plaintext')),
 )
 
         info=dict(description=u"A splendiferous name of the body shape", format='plaintext')),
 )
 
@@ -1505,6 +1506,7 @@ class Region(TableBase):
         info=dict(description=u"An identifier", format='identifier'))
 
 create_translation_table('region_names', Region, 'names',
         info=dict(description=u"An identifier", format='identifier'))
 
 create_translation_table('region_names', Region, 'names',
+    relation_lazy='joined',
     name = Column(Unicode(16), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
     name = Column(Unicode(16), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
@@ -1520,8 +1522,11 @@ class Stat(TableBase):
         info=dict(description=u"For offensive and defensive stats, the damage this stat relates to; otherwise None (the NULL value)"))
     identifier = Column(Unicode(16), nullable=False,
         info=dict(description=u"An identifier", format='identifier'))
         info=dict(description=u"For offensive and defensive stats, the damage this stat relates to; otherwise None (the NULL value)"))
     identifier = Column(Unicode(16), nullable=False,
         info=dict(description=u"An identifier", format='identifier'))
+    is_battle_only = Column(Boolean, nullable=False,
+        info=dict(description=u"Whether this stat only exists within a battle"))
 
 create_translation_table('stat_names', Stat, 'names',
 
 create_translation_table('stat_names', Stat, 'names',
+    relation_lazy='joined',
     name = Column(Unicode(16), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
     name = Column(Unicode(16), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
@@ -1540,6 +1545,7 @@ class StatHint(TableBase):
         info=dict(description=u"Value of the highest stat modulo 5"))
 
 create_translation_table('stat_hint_names', StatHint, 'names',
         info=dict(description=u"Value of the highest stat modulo 5"))
 
 create_translation_table('stat_hint_names', StatHint, 'names',
+    relation_lazy='joined',
     message = Column(Unicode(24), nullable=False, index=True,
         info=dict(description=u"The text displayed", official=True, format='plaintext')),
 )
     message = Column(Unicode(24), nullable=False, index=True,
         info=dict(description=u"The text displayed", official=True, format='plaintext')),
 )
@@ -1565,22 +1571,9 @@ class SuperContestEffect(TableBase):
 
 create_translation_table('super_contest_effect_prose', SuperContestEffect, 'prose',
     flavor_text = Column(Unicode(64), nullable=False,
 
 create_translation_table('super_contest_effect_prose', SuperContestEffect, 'prose',
     flavor_text = Column(Unicode(64), nullable=False,
-        info=dict(description=u"A description of the effect.", format='plaintext')),
+        info=dict(description=u"A description of the effect.", format='plaintext', official=True)),
 )
 
 )
 
-
-class TypeEfficacy(TableBase):
-    u"""The damage multiplier used when a move of a particular type damages a
-    Pokémon of a particular other type.
-    """
-    __tablename__ = 'type_efficacy'
-    damage_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
-        info=dict(description=u"The ID of the damaging type."))
-    target_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
-        info=dict(description=u"The ID of the defending Pokémon's type."))
-    damage_factor = Column(Integer, nullable=False,
-        info=dict(description=u"The multiplier, as a percentage of damage inflicted."))
-
 class Type(TableBase):
     u"""Any of the elemental types Pokémon and moves can have."""
     __tablename__ = 'types'
 class Type(TableBase):
     u"""Any of the elemental types Pokémon and moves can have."""
     __tablename__ = 'types'
@@ -1595,10 +1588,40 @@ class Type(TableBase):
         info=dict(description=u"The ID of the damage class this type's moves had before Generation IV, null if not applicable (e.g. ???)."))
 
 create_translation_table('type_names', Type, 'names',
         info=dict(description=u"The ID of the damage class this type's moves had before Generation IV, null if not applicable (e.g. ???)."))
 
 create_translation_table('type_names', Type, 'names',
+    relation_lazy='joined',
     name = Column(Unicode(12), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
 
     name = Column(Unicode(12), nullable=False, index=True,
         info=dict(description="The name", format='plaintext', official=True)),
 )
 
+class TypeEfficacy(TableBase):
+    u"""The damage multiplier used when a move of a particular type damages a
+    Pokémon of a particular other type.
+    """
+    __tablename__ = 'type_efficacy'
+    damage_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
+        info=dict(description=u"The ID of the damaging type."))
+    target_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False,
+        info=dict(description=u"The ID of the defending Pokémon's type."))
+    damage_factor = Column(Integer, nullable=False,
+        info=dict(description=u"The multiplier, as a percentage of damage inflicted."))
+
+class Version(TableBase):
+    u"""An individual main-series Pokémon game."""
+    __tablename__ = 'versions'
+    __singlename__ = 'version'
+    id = Column(Integer, primary_key=True, nullable=False,
+        info=dict(description=u"A unique ID for this version."))
+    version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False,
+        info=dict(description=u"The ID of the version group this game belongs to."))
+    identifier = Column(Unicode(32), nullable=False,
+        info=dict(description=u'And identifier', format='identifier'))
+
+create_translation_table('version_names', Version, 'names',
+    relation_lazy='joined',
+    name = Column(Unicode(32), nullable=False, index=True,
+        info=dict(description="The name", format='plaintext', official=True)),
+)
+
 class VersionGroup(TableBase):
     u"""A group of versions, containing either two paired versions (such as Red
     and Blue) or a single game (such as Yellow.)
 class VersionGroup(TableBase):
     u"""A group of versions, containing either two paired versions (such as Red
     and Blue) or a single game (such as Yellow.)
@@ -1619,198 +1642,301 @@ class VersionGroupRegion(TableBase):
     region_id = Column(Integer, ForeignKey('regions.id'), primary_key=True, nullable=False,
         info=dict(description=u"The ID of the region."))
 
     region_id = Column(Integer, ForeignKey('regions.id'), primary_key=True, nullable=False,
         info=dict(description=u"The ID of the region."))
 
-class Version(TableBase):
-    u"""An individual main-series Pokémon game."""
-    __tablename__ = 'versions'
-    __singlename__ = 'version'
-    id = Column(Integer, primary_key=True, nullable=False,
-        info=dict(description=u"A unique ID for this version."))
-    version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False,
-        info=dict(description=u"The ID of the version group this game belongs to."))
-    identifier = Column(Unicode(32), nullable=False,
-        info=dict(description=u'And identifier', format='identifier'))
-
-create_translation_table('version_names', Version, 'names',
-    name = Column(Unicode(32), nullable=False, index=True,
-        info=dict(description="The name", format='plaintext', official=True)),
-)
 
 
+### Relations down here, to avoid dependency ordering problems
 
 
-### Relations down here, to avoid ordering problems
 Ability.changelog = relation(AbilityChangelog,
     order_by=AbilityChangelog.changed_in_version_group_id.desc(),
 Ability.changelog = relation(AbilityChangelog,
     order_by=AbilityChangelog.changed_in_version_group_id.desc(),
-    backref='ability',
-)
-Ability.flavor_text = relation(AbilityFlavorText, order_by=AbilityFlavorText.version_group_id, backref='ability')
-Ability.generation = relation(Generation, backref='abilities')
-Ability.all_pokemon = relation(Pokemon,
-    secondary=PokemonAbility.__table__,
-    order_by=Pokemon.order,
-    #back_populates='all_abilities',
-)
-Ability.pokemon = relation(Pokemon,
-    secondary=PokemonAbility.__table__,
-    primaryjoin=and_(
-        PokemonAbility.ability_id == Ability.id,
-        PokemonAbility.is_dream == False
-    ),
-    order_by=Pokemon.order,
-    #back_populates='abilities',
-)
-Ability.dream_pokemon = relation(Pokemon,
-    secondary=PokemonAbility.__table__,
-    primaryjoin=and_(
-        PokemonAbility.ability_id == Ability.id,
-        PokemonAbility.is_dream == True
-    ),
-    order_by=Pokemon.order,
-    #back_populates='dream_ability',
-)
-
-AbilityChangelog.changed_in = relation(VersionGroup, backref='ability_changelog')
-
-AbilityFlavorText.version_group = relation(VersionGroup)
-AbilityFlavorText.language = relation(Language)
-
-Berry.berry_firmness = relation(BerryFirmness, backref='berries')
+    backref=backref('ability', innerjoin=True, lazy='joined'))
+Ability.flavor_text = relation(AbilityFlavorText,
+    order_by=AbilityFlavorText.version_group_id,
+    backref=backref('ability', innerjoin=True, lazy='joined'))
+Ability.generation = relation(Generation,
+    innerjoin=True,
+    backref='abilities')
+
+AbilityChangelog.changed_in = relation(VersionGroup,
+    innerjoin=True, lazy='joined',
+    backref='ability_changelog')
+
+AbilityFlavorText.version_group = relation(VersionGroup,
+    innerjoin=True)
+AbilityFlavorText.language = relation(Language,
+    innerjoin=True, lazy='joined')
+
+
+Berry.berry_firmness = relation(BerryFirmness,
+    innerjoin=True,
+    backref='berries')
 Berry.firmness = association_proxy('berry_firmness', 'name')
 Berry.firmness = association_proxy('berry_firmness', 'name')
-Berry.flavors = relation(BerryFlavor, order_by=BerryFlavor.contest_type_id, backref='berry')
-Berry.natural_gift_type = relation(Type)
+Berry.flavors = relation(BerryFlavor,
+    order_by=BerryFlavor.contest_type_id,
+    backref=backref('berry', innerjoin=True))
+Berry.natural_gift_type = relation(Type, innerjoin=True)
 
 
-BerryFlavor.contest_type = relation(ContestType)
+BerryFlavor.contest_type = relation(ContestType, innerjoin=True)
 
 
-ContestCombo.first = relation(Move, primaryjoin=ContestCombo.first_move_id==Move.id,
-                                    backref='contest_combo_first')
-ContestCombo.second = relation(Move, primaryjoin=ContestCombo.second_move_id==Move.id,
-                                     backref='contest_combo_second')
 
 
-Encounter.location_area = relation(LocationArea, backref='encounters')
-Encounter.pokemon = relation(Pokemon, backref='encounters')
-Encounter.version = relation(Version, backref='encounters')
-Encounter.slot = relation(EncounterSlot, backref='encounters')
+ContestCombo.first = relation(Move,
+    primaryjoin=ContestCombo.first_move_id==Move.id,
+    innerjoin=True, lazy='joined',
+    backref='contest_combo_first')
+ContestCombo.second = relation(Move,
+    primaryjoin=ContestCombo.second_move_id==Move.id,
+    innerjoin=True, lazy='joined',
+    backref='contest_combo_second')
 
 
-EncounterConditionValue.condition = relation(EncounterCondition, backref='values')
 
 
-Encounter.condition_value_map = relation(EncounterConditionValueMap, backref='encounter')
+Encounter.condition_value_map = relation(EncounterConditionValueMap,
+    backref='encounter')
 Encounter.condition_values = association_proxy('condition_value_map', 'condition_value')
 Encounter.condition_values = association_proxy('condition_value_map', 'condition_value')
+Encounter.location_area = relation(LocationArea,
+    innerjoin=True, lazy='joined',
+    backref='encounters')
+Encounter.pokemon = relation(Pokemon,
+    innerjoin=True, lazy='joined',
+    backref='encounters')
+Encounter.version = relation(Version,
+    innerjoin=True, lazy='joined',
+    backref='encounters')
+Encounter.slot = relation(EncounterSlot,
+    innerjoin=True, lazy='joined',
+    backref='encounters')
+
+EncounterConditionValue.condition = relation(EncounterCondition,
+    innerjoin=True, lazy='joined',
+    backref='values')
 EncounterConditionValueMap.condition_value = relation(EncounterConditionValue,
 EncounterConditionValueMap.condition_value = relation(EncounterConditionValue,
-                                                      backref='encounter_map')
+    innerjoin=True, lazy='joined',
+    backref='encounter_map')
+
+EncounterSlot.method = relation(EncounterMethod,
+    innerjoin=True, lazy='joined',
+    backref='slots')
+EncounterSlot.version_group = relation(VersionGroup, innerjoin=True)
 
 
-EncounterSlot.terrain = relation(EncounterTerrain, backref='slots')
-EncounterSlot.version_group = relation(VersionGroup)
 
 
-EvolutionChain.growth_rate = relation(GrowthRate, backref='evolution_chains')
-EvolutionChain.baby_trigger_item = relation(Item, backref='evolution_chains')
-EvolutionChain.pokemon = relation(Pokemon, order_by=Pokemon.order)#, back_populates='evolution_chain')
+EvolutionChain.growth_rate = relation(GrowthRate,
+    innerjoin=True,
+    backref='evolution_chains')
+EvolutionChain.baby_trigger_item = relation(Item,
+    backref='evolution_chains')
 
 
-Experience.growth_rate = relation(GrowthRate, backref='experience_table')
 
 
-Generation.canonical_pokedex = relation(Pokedex, backref='canonical_for_generation')
-Generation.versions = relation(Version, secondary=VersionGroup.__table__)
-Generation.main_region = relation(Region)
+Experience.growth_rate = relation(GrowthRate,
+    innerjoin=True, lazy='joined',
+    backref='experience_table')
 
 
-GrowthRate.max_experience_obj = relation(Experience, primaryjoin=and_(Experience.growth_rate_id == GrowthRate.id, Experience.level == 100), uselist=False)
+
+Generation.canonical_pokedex = relation(Pokedex,
+    backref='canonical_for_generation')
+Generation.versions = relation(Version,
+    secondary=VersionGroup.__table__,
+    innerjoin=True)
+Generation.main_region = relation(Region, innerjoin=True)
+
+
+GrowthRate.max_experience_obj = relation(Experience,
+    primaryjoin=and_(
+        Experience.growth_rate_id == GrowthRate.id,
+        Experience.level == 100),
+    uselist=False, innerjoin=True)
 GrowthRate.max_experience = association_proxy('max_experience_obj', 'experience')
 
 GrowthRate.max_experience = association_proxy('max_experience_obj', 'experience')
 
-Item.berry = relation(Berry, uselist=False, backref='item')
-Item.flags = relation(ItemFlag, secondary=ItemFlagMap.__table__)
-Item.flavor_text = relation(ItemFlavorText, order_by=ItemFlavorText.version_group_id.asc(), backref='item')
-Item.fling_effect = relation(ItemFlingEffect, backref='items')
-Item.machines = relation(Machine, order_by=Machine.version_group_id.asc())
-Item.category = relation(ItemCategory)
+
+Item.berry = relation(Berry,
+    uselist=False,
+    backref='item')
+Item.flags = relation(ItemFlag,
+    secondary=ItemFlagMap.__table__)
+Item.flavor_text = relation(ItemFlavorText,
+    order_by=ItemFlavorText.version_group_id.asc(),
+    backref=backref('item', innerjoin=True, lazy='joined'))
+Item.fling_effect = relation(ItemFlingEffect,
+    backref='items')
+Item.machines = relation(Machine,
+    order_by=Machine.version_group_id.asc())
+Item.category = relation(ItemCategory,
+    innerjoin=True,
+    backref=backref('items', order_by=Item.identifier.asc()))
 Item.pocket = association_proxy('category', 'pocket')
 
 Item.pocket = association_proxy('category', 'pocket')
 
-ItemCategory.items = relation(Item, order_by=Item.identifier)
-ItemCategory.pocket = relation(ItemPocket)
+ItemCategory.pocket = relation(ItemPocket, innerjoin=True)
+
+ItemFlavorText.version_group = relation(VersionGroup,
+    innerjoin=True, lazy='joined')
+ItemFlavorText.language = relation(Language,
+    innerjoin=True, lazy='joined')
+
+ItemGameIndex.item = relation(Item,
+    innerjoin=True, lazy='joined',
+    backref='game_indices')
+ItemGameIndex.generation = relation(Generation,
+    innerjoin=True, lazy='joined')
 
 
-ItemFlavorText.version_group = relation(VersionGroup)
-ItemFlavorText.language = relation(Language)
+ItemPocket.categories = relation(ItemCategory,
+    innerjoin=True,
+    order_by=ItemCategory.identifier.asc())
 
 
-ItemGameIndex.item = relation(Item, backref='game_indices')
-ItemGameIndex.generation = relation(Generation)
 
 
-ItemPocket.categories = relation(ItemCategory, order_by=ItemCategory.identifier)
+Location.region = relation(Region,
+    innerjoin=True,
+    backref='locations')
 
 
-Location.region = relation(Region, backref='locations')
+LocationArea.location = relation(Location,
+    innerjoin=True, lazy='joined',
+    backref='areas')
 
 
-LocationArea.location = relation(Location, backref='areas')
+LocationAreaEncounterRate.location_area = relation(LocationArea,
+    innerjoin=True,
+    backref='encounter_rates')
+LocationAreaEncounterRate.method = relation(EncounterMethod,
+    innerjoin=True)
+
+LocationGameIndex.location = relation(Location,
+    innerjoin=True, lazy='joined',
+    backref='game_indices')
+LocationGameIndex.generation = relation(Generation,
+    innerjoin=True, lazy='joined')
 
 
-LocationGameIndex.location = relation(Location, backref='game_indices')
-LocationGameIndex.generation = relation(Generation)
 
 Machine.item = relation(Item)
 
 Machine.item = relation(Item)
-Machine.version_group = relation(VersionGroup)
+Machine.version_group = relation(VersionGroup,
+    innerjoin=True, lazy='joined')
+
 
 Move.changelog = relation(MoveChangelog,
     order_by=MoveChangelog.changed_in_version_group_id.desc(),
 
 Move.changelog = relation(MoveChangelog,
     order_by=MoveChangelog.changed_in_version_group_id.desc(),
-    backref='move',
-)
-Move.contest_effect = relation(ContestEffect, backref='moves')
+    backref=backref('move', innerjoin=True, lazy='joined'))
+Move.contest_effect = relation(ContestEffect,
+    backref='moves')
 Move.contest_combo_next = association_proxy('contest_combo_first', 'second')
 Move.contest_combo_prev = association_proxy('contest_combo_second', 'first')
 Move.contest_combo_next = association_proxy('contest_combo_first', 'second')
 Move.contest_combo_prev = association_proxy('contest_combo_second', 'first')
-Move.contest_type = relation(ContestType, backref='moves')
-Move.damage_class = relation(MoveDamageClass, backref='moves')
+Move.contest_type = relation(ContestType,
+    backref='moves')
+Move.damage_class = relation(MoveDamageClass,
+    innerjoin=True,
+    backref='moves')
 Move.flags = association_proxy('move_flags', 'flag')
 Move.flags = association_proxy('move_flags', 'flag')
-Move.flavor_text = relation(MoveFlavorText, order_by=MoveFlavorText.version_group_id, backref='move')
-Move.generation = relation(Generation, backref='moves')
-Move.machines = relation(Machine, backref='move')
-Move.meta = relation(MoveMeta, uselist=False, backref='move')
+Move.flavor_text = relation(MoveFlavorText,
+    order_by=MoveFlavorText.version_group_id, backref='move')
+Move.generation = relation(Generation,
+    innerjoin=True,
+    backref='moves')
+Move.machines = relation(Machine,
+    backref='move')
+Move.meta = relation(MoveMeta,
+    uselist=False, innerjoin=True,
+    backref='move')
 Move.meta_stat_changes = relation(MoveMetaStatChange)
 Move.meta_stat_changes = relation(MoveMetaStatChange)
-Move.move_effect = relation(MoveEffect, backref='moves')
-Move.move_flags = relation(MoveFlag, backref='move')
-Move.super_contest_effect = relation(SuperContestEffect, backref='moves')
+Move.move_effect = relation(MoveEffect,
+    innerjoin=True,
+    backref='moves')
+Move.move_flags = relation(MoveFlag,
+    backref='move')
+Move.super_contest_effect = relation(SuperContestEffect,
+    backref='moves')
 Move.super_contest_combo_next = association_proxy('super_contest_combo_first', 'second')
 Move.super_contest_combo_prev = association_proxy('super_contest_combo_second', 'first')
 Move.super_contest_combo_next = association_proxy('super_contest_combo_first', 'second')
 Move.super_contest_combo_prev = association_proxy('super_contest_combo_second', 'first')
-Move.target = relation(MoveTarget, backref='moves')
-Move.type = relation(Type)#, back_populates='moves')
-
-MoveChangelog.changed_in = relation(VersionGroup, backref='move_changelog')
-MoveChangelog.move_effect = relation(MoveEffect, backref='move_changelog')
-MoveChangelog.type = relation(Type, backref='move_changelog')
-
-MoveEffect.category_map = relation(MoveEffectCategoryMap)
-MoveEffect.categories = association_proxy('category_map', 'category')
-MoveEffect.changelog = relation(MoveEffectChangelog,
-    order_by=MoveEffectChangelog.changed_in_version_group_id.desc(),
-    backref='move_effect',
-)
-MoveEffectCategoryMap.category = relation(MoveEffectCategory)
+Move.target = relation(MoveTarget,
+    innerjoin=True,
+    backref='moves')
+Move.type = relation(Type,
+    innerjoin=True,
+    backref='moves')
 
 
-MoveEffectChangelog.changed_in = relation(VersionGroup, backref='move_effect_changelog')
+Move.effect = markdown.MoveEffectProperty('effect')
+Move.effect_map = markdown.MoveEffectPropertyMap('effect_map')
+Move.short_effect = markdown.MoveEffectProperty('short_effect')
+Move.short_effect_map = markdown.MoveEffectPropertyMap('short_effect_map')
 
 
-MoveFlag.flag = relation(MoveFlagType)
+MoveChangelog.changed_in = relation(VersionGroup,
+    innerjoin=True, lazy='joined',
+    backref='move_changelog')
+MoveChangelog.move_effect = relation(MoveEffect,
+    backref='move_changelog')
+MoveChangelog.type = relation(Type,
+    backref='move_changelog')
 
 
-MoveFlavorText.version_group = relation(VersionGroup)
-MoveFlavorText.language = relation(Language)
+MoveChangelog.effect = markdown.MoveEffectProperty('effect')
+MoveChangelog.effect_map = markdown.MoveEffectPropertyMap('effect_map')
+MoveChangelog.short_effect = markdown.MoveEffectProperty('short_effect')
+MoveChangelog.short_effect_map = markdown.MoveEffectPropertyMap('short_effect_map')
 
 
-MoveMeta.category = relation(MoveMetaCategory, backref='move_meta')
-MoveMeta.ailment = relation(MoveMetaAilment, backref='move_meta')
+MoveEffect.changelog = relation(MoveEffectChangelog,
+    order_by=MoveEffectChangelog.changed_in_version_group_id.desc(),
+    backref='move_effect')
+
+MoveEffectChangelog.changed_in = relation(VersionGroup,
+    innerjoin=True, lazy='joined',
+    backref='move_effect_changelog')
+
+MoveFlag.flag = relation(MoveFlagType, innerjoin=True, lazy='joined')
+
+MoveFlavorText.version_group = relation(VersionGroup,
+    innerjoin=True, lazy='joined')
+MoveFlavorText.language = relation(Language,
+    innerjoin=True, lazy='joined')
+
+MoveMeta.category = relation(MoveMetaCategory,
+    innerjoin=True, lazy='joined',
+    backref='move_meta')
+MoveMeta.ailment = relation(MoveMetaAilment,
+    innerjoin=True, lazy='joined',
+    backref='move_meta')
+
+MoveMetaStatChange.stat = relation(Stat,
+    innerjoin=True, lazy='joined',
+    backref='move_meta_stat_changes')
+
+
+Nature.decreased_stat = relation(Stat,
+    primaryjoin=Nature.decreased_stat_id==Stat.id,
+    innerjoin=True,
+    backref='decreasing_natures')
+Nature.increased_stat = relation(Stat,
+    primaryjoin=Nature.increased_stat_id==Stat.id,
+    innerjoin=True,
+    backref='increasing_natures')
+Nature.hates_flavor = relation(ContestType,
+    primaryjoin=Nature.hates_flavor_id==ContestType.id,
+    innerjoin=True,
+    backref='hating_natures')
+Nature.likes_flavor = relation(ContestType,
+    primaryjoin=Nature.likes_flavor_id==ContestType.id,
+    innerjoin=True,
+    backref='liking_natures')
+Nature.battle_style_preferences = relation(NatureBattleStylePreference,
+    order_by=NatureBattleStylePreference.move_battle_style_id.asc(),
+    backref='nature')
+Nature.pokeathlon_effects = relation(NaturePokeathlonStat,
+    order_by=NaturePokeathlonStat.pokeathlon_stat_id.asc())
 
 
-MoveMetaStatChange.stat = relation(Stat, backref='move_meta_stat_changes')
+NatureBattleStylePreference.battle_style = relation(MoveBattleStyle,
+    innerjoin=True, lazy='joined',
+    backref='nature_preferences')
 
 
-Nature.decreased_stat = relation(Stat, primaryjoin=Nature.decreased_stat_id==Stat.id,
-                                       backref='decreasing_natures')
-Nature.increased_stat = relation(Stat, primaryjoin=Nature.increased_stat_id==Stat.id,
-                                       backref='increasing_natures')
-Nature.hates_flavor = relation(ContestType, primaryjoin=Nature.hates_flavor_id==ContestType.id,
-                                       backref='hating_natures')
-Nature.likes_flavor = relation(ContestType, primaryjoin=Nature.likes_flavor_id==ContestType.id,
-                                       backref='liking_natures')
-Nature.battle_style_preferences = relation(NatureBattleStylePreference,
-                                           order_by=NatureBattleStylePreference.move_battle_style_id,
-                                           backref='nature')
-Nature.pokeathlon_effects = relation(NaturePokeathlonStat, order_by=NaturePokeathlonStat.pokeathlon_stat_id)
+NaturePokeathlonStat.pokeathlon_stat = relation(PokeathlonStat,
+    innerjoin=True, lazy='joined',
+    backref='nature_effects')
 
 
-NatureBattleStylePreference.battle_style = relation(MoveBattleStyle, backref='nature_preferences')
 
 
-NaturePokeathlonStat.pokeathlon_stat = relation(PokeathlonStat, backref='nature_effects')
+Pokedex.region = relation(Region,
+    innerjoin=True,
+    backref='pokedexes')
+Pokedex.version_groups = relation(VersionGroup,
+    innerjoin=True,
+    order_by=VersionGroup.id.asc(),
+    backref='pokedex')
 
 
-Pokedex.region = relation(Region, backref='pokedexes')
-Pokedex.version_groups = relation(VersionGroup, order_by=VersionGroup.id)#, back_populates='pokedex')
 
 Pokemon.all_abilities = relation(Ability,
     secondary=PokemonAbility.__table__,
 
 Pokemon.all_abilities = relation(Ability,
     secondary=PokemonAbility.__table__,
-    order_by=PokemonAbility.slot,
+    order_by=PokemonAbility.slot.asc(),
+    innerjoin=True,
+    backref=backref('all_pokemon',
+        order_by=Pokemon.order.asc(),
+    ),
 )
 Pokemon.abilities = relation(Ability,
     secondary=PokemonAbility.__table__,
 )
 Pokemon.abilities = relation(Ability,
     secondary=PokemonAbility.__table__,
@@ -1818,7 +1944,11 @@ Pokemon.abilities = relation(Ability,
         Pokemon.id == PokemonAbility.pokemon_id,
         PokemonAbility.is_dream == False,
     ),
         Pokemon.id == PokemonAbility.pokemon_id,
         PokemonAbility.is_dream == False,
     ),
-    order_by=PokemonAbility.slot,
+    innerjoin=True,
+    order_by=PokemonAbility.slot.asc(),
+    backref=backref('pokemon',
+        order_by=Pokemon.order.asc(),
+    ),
 )
 Pokemon.dream_ability = relation(Ability,
     secondary=PokemonAbility.__table__,
 )
 Pokemon.dream_ability = relation(Ability,
     secondary=PokemonAbility.__table__,
@@ -1827,152 +1957,200 @@ Pokemon.dream_ability = relation(Ability,
         PokemonAbility.is_dream == True,
     ),
     uselist=False,
         PokemonAbility.is_dream == True,
     ),
     uselist=False,
+    backref=backref('dream_pokemon',
+        order_by=Pokemon.order,
+    ),
 )
 )
-Pokemon.pokemon_color = relation(PokemonColor, backref='pokemon')
+Pokemon.pokemon_color = relation(PokemonColor,
+    innerjoin=True,
+    backref='pokemon')
 Pokemon.color = association_proxy('pokemon_color', 'name')
 Pokemon.color = association_proxy('pokemon_color', 'name')
-Pokemon.dex_numbers = relation(PokemonDexNumber, order_by=PokemonDexNumber.pokedex_id.asc(), backref='pokemon')
-Pokemon.egg_groups = relation(EggGroup, secondary=PokemonEggGroup.__table__,
-                                        order_by=PokemonEggGroup.egg_group_id,
-                                        backref=backref('pokemon', order_by=Pokemon.order))
-Pokemon.evolution_chain = relation(EvolutionChain)#, back_populates='pokemon')
-Pokemon.child_pokemon = relation(Pokemon,
-    primaryjoin=Pokemon.id==PokemonEvolution.from_pokemon_id,
-    secondary=PokemonEvolution.__table__,
-    secondaryjoin=PokemonEvolution.to_pokemon_id==Pokemon.id,
-    backref=backref('parent_pokemon', uselist=False),
-)
-Pokemon.flavor_text = relation(PokemonFlavorText, order_by=PokemonFlavorText.version_id.asc(), backref='pokemon')
-Pokemon.forms = relation(PokemonForm, primaryjoin=Pokemon.id==PokemonForm.form_base_pokemon_id,
-                         order_by=(PokemonForm.order.asc(), PokemonForm.identifier.asc()))
+Pokemon.dex_numbers = relation(PokemonDexNumber,
+    innerjoin=True,
+    order_by=PokemonDexNumber.pokedex_id.asc(),
+    backref='pokemon')
+Pokemon.egg_groups = relation(EggGroup,
+    secondary=PokemonEggGroup.__table__,
+    innerjoin=True,
+    order_by=PokemonEggGroup.egg_group_id.asc(),
+    backref=backref('pokemon', order_by=Pokemon.order.asc()))
+Pokemon.evolution_chain = relation(EvolutionChain,
+    innerjoin=True,
+    backref=backref('pokemon', order_by=Pokemon.order.asc()))
+Pokemon.parent_pokemon = relation(Pokemon,
+    primaryjoin=Pokemon.evolves_from_pokemon_id==Pokemon.id,
+    remote_side=[Pokemon.id],
+    backref='child_pokemon')
+Pokemon.evolutions = relation(PokemonEvolution,
+    primaryjoin=Pokemon.id==PokemonEvolution.evolved_pokemon_id,
+    backref=backref('evolved_pokemon', innerjoin=True, lazy='joined'))
+Pokemon.flavor_text = relation(PokemonFlavorText,
+    order_by=PokemonFlavorText.version_id.asc(),
+    backref='pokemon')
+Pokemon.forms = relation(PokemonForm,
+    primaryjoin=Pokemon.id==PokemonForm.form_base_pokemon_id,
+    order_by=(PokemonForm.order.asc(), PokemonForm.identifier.asc()))
 Pokemon.default_form = relation(PokemonForm,
 Pokemon.default_form = relation(PokemonForm,
-    primaryjoin=and_(Pokemon.id==PokemonForm.form_base_pokemon_id, PokemonForm.is_default==True),
-    uselist=False,
-)
-Pokemon.pokemon_habitat = relation(PokemonHabitat, backref='pokemon')
+    primaryjoin=and_(
+        Pokemon.id==PokemonForm.form_base_pokemon_id,
+        PokemonForm.is_default==True),
+    uselist=False)
+Pokemon.pokemon_habitat = relation(PokemonHabitat,
+    backref='pokemon')
 Pokemon.habitat = association_proxy('pokemon_habitat', 'name')
 Pokemon.habitat = association_proxy('pokemon_habitat', 'name')
-Pokemon.items = relation(PokemonItem, backref='pokemon')
-Pokemon.generation = relation(Generation, backref='pokemon')
-Pokemon.shape = relation(PokemonShape, backref='pokemon')
-Pokemon.stats = relation(PokemonStat, backref='pokemon', order_by=PokemonStat.stat_id.asc())
-Pokemon.types = relation(Type, secondary=PokemonType.__table__,
-                               order_by=PokemonType.slot.asc(),
-                               )#back_populates='pokemon')
-
-PokemonDexNumber.pokedex = relation(Pokedex)
-
-PokemonEvolution.from_pokemon = relation(Pokemon,
-    primaryjoin=PokemonEvolution.from_pokemon_id==Pokemon.id,
-    backref='child_evolutions',
-)
-PokemonEvolution.to_pokemon = relation(Pokemon,
-    primaryjoin=PokemonEvolution.to_pokemon_id==Pokemon.id,
-    backref=backref('parent_evolution', uselist=False),
-)
-PokemonEvolution.child_evolutions = relation(PokemonEvolution,
-    primaryjoin=PokemonEvolution.from_pokemon_id==PokemonEvolution.to_pokemon_id,
-    foreign_keys=[PokemonEvolution.to_pokemon_id],
-    backref=backref('parent_evolution',
-        remote_side=[PokemonEvolution.from_pokemon_id],
-        uselist=False,
-    ),
-)
-PokemonEvolution.trigger = relation(EvolutionTrigger, backref='evolutions')
+Pokemon.items = relation(PokemonItem,
+    backref='pokemon')
+Pokemon.generation = relation(Generation,
+    innerjoin=True,
+    backref='pokemon')
+Pokemon.shape = relation(PokemonShape,
+    innerjoin=True,
+    backref='pokemon')
+Pokemon.stats = relation(PokemonStat,
+    innerjoin=True,
+    order_by=PokemonStat.stat_id.asc(),
+    backref='pokemon')
+Pokemon.types = relation(Type,
+    secondary=PokemonType.__table__,
+    innerjoin=True,
+    order_by=PokemonType.slot.asc(),
+    backref=backref('pokemon', order_by=Pokemon.order))
+Pokemon.form = relation(PokemonForm,
+    primaryjoin=or_(
+        PokemonForm.unique_pokemon_id==Pokemon.id,
+        and_(PokemonForm.unique_pokemon_id==None, 
+            PokemonForm.form_base_pokemon_id==Pokemon.id,
+            PokemonForm.is_default==True)
+        ),
+        uselist=False)
+
+PokemonDexNumber.pokedex = relation(Pokedex,
+    innerjoin=True, lazy='joined')
+
+PokemonEvolution.trigger = relation(EvolutionTrigger,
+    innerjoin=True, lazy='joined',
+    backref='evolutions')
 PokemonEvolution.trigger_item = relation(Item,
     primaryjoin=PokemonEvolution.trigger_item_id==Item.id,
 PokemonEvolution.trigger_item = relation(Item,
     primaryjoin=PokemonEvolution.trigger_item_id==Item.id,
-    backref='triggered_evolutions',
-)
+    backref='triggered_evolutions')
 PokemonEvolution.held_item = relation(Item,
     primaryjoin=PokemonEvolution.held_item_id==Item.id,
 PokemonEvolution.held_item = relation(Item,
     primaryjoin=PokemonEvolution.held_item_id==Item.id,
-    backref='required_for_evolutions',
-)
-PokemonEvolution.location = relation(Location, backref='triggered_evolutions')
-PokemonEvolution.known_move = relation(Move, backref='triggered_evolutions')
+    backref='required_for_evolutions')
+PokemonEvolution.location = relation(Location,
+    backref='triggered_evolutions')
+PokemonEvolution.known_move = relation(Move,
+    backref='triggered_evolutions')
 PokemonEvolution.party_pokemon = relation(Pokemon,
     primaryjoin=PokemonEvolution.party_pokemon_id==Pokemon.id,
 PokemonEvolution.party_pokemon = relation(Pokemon,
     primaryjoin=PokemonEvolution.party_pokemon_id==Pokemon.id,
-    backref='triggered_evolutions',
-)
+    backref='triggered_evolutions')
 PokemonEvolution.trade_pokemon = relation(Pokemon,
 PokemonEvolution.trade_pokemon = relation(Pokemon,
-    primaryjoin=PokemonEvolution.trade_pokemon_id==Pokemon.id,
-)
-
-PokemonFlavorText.version = relation(Version)
-PokemonFlavorText.language = relation(Language)
-
-PokemonForm.form_base_pokemon = relation(Pokemon, primaryjoin=PokemonForm.form_base_pokemon_id==Pokemon.id)
-PokemonForm.unique_pokemon = relation(Pokemon, backref=backref('unique_form', uselist=False),
-                                      primaryjoin=PokemonForm.unique_pokemon_id==Pokemon.id)
-PokemonForm.version_group = relation(VersionGroup)
+    primaryjoin=PokemonEvolution.trade_pokemon_id==Pokemon.id)
+
+PokemonFlavorText.version = relation(Version, innerjoin=True, lazy='joined')
+PokemonFlavorText.language = relation(Language, innerjoin=True, lazy='joined')
+
+PokemonForm.form_base_pokemon = relation(Pokemon,
+    primaryjoin=PokemonForm.form_base_pokemon_id==Pokemon.id,
+    innerjoin=True)
+PokemonForm.unique_pokemon = relation(Pokemon,
+    primaryjoin=PokemonForm.unique_pokemon_id==Pokemon.id,
+    backref=backref('unique_form', uselist=False))
+PokemonForm.pokemon = relation(Pokemon,
+    primaryjoin=or_(
+        PokemonForm.unique_pokemon_id==Pokemon.id,
+        and_(PokemonForm.unique_pokemon_id==None, 
+            PokemonForm.form_base_pokemon_id==Pokemon.id)
+        ), uselist=False)
+PokemonForm.version_group = relation(VersionGroup,
+    innerjoin=True)
 PokemonForm.form_group = association_proxy('form_base_pokemon', 'form_group')
 PokemonForm.pokeathlon_stats = relation(PokemonFormPokeathlonStat,
 PokemonForm.form_group = association_proxy('form_base_pokemon', 'form_group')
 PokemonForm.pokeathlon_stats = relation(PokemonFormPokeathlonStat,
-                                        order_by=PokemonFormPokeathlonStat.pokeathlon_stat_id,
-                                        backref='pokemon_form')
+    order_by=PokemonFormPokeathlonStat.pokeathlon_stat_id,
+    backref='pokemon_form')
+
+PokemonFormGroup.pokemon = relation(Pokemon,
+    innerjoin=True,
+    backref=backref('form_group', uselist=False))
+
+PokemonFormPokeathlonStat.pokeathlon_stat = relation(PokeathlonStat,
+    innerjoin=True, lazy='joined')
+
+PokemonItem.item = relation(Item,
+    innerjoin=True, lazy='joined',
+    backref='pokemon')
+PokemonItem.version = relation(Version,
+    innerjoin=True, lazy='joined')
+
+PokemonMove.pokemon = relation(Pokemon,
+    innerjoin=True, lazy='joined',
+    backref='pokemon_moves')
+PokemonMove.version_group = relation(VersionGroup,
+    innerjoin=True, lazy='joined')
+PokemonMove.machine = relation(Machine,
+    primaryjoin=and_(
+        Machine.version_group_id==PokemonMove.version_group_id,
+        Machine.move_id==PokemonMove.move_id),
+    foreign_keys=[Machine.version_group_id, Machine.move_id],
+    uselist=False,
+    backref='pokemon_moves')
+PokemonMove.move = relation(Move,
+    innerjoin=True, lazy='joined',
+    backref='pokemon_moves')
+PokemonMove.method = relation(PokemonMoveMethod,
+    innerjoin=True, lazy='joined')
 
 
-PokemonFormGroup.pokemon = relation(Pokemon, backref=backref('form_group',
-                                                             uselist=False))
+PokemonStat.stat = relation(Stat,
+    innerjoin=True, lazy='joined')
 
 
-PokemonFormPokeathlonStat.pokeathlon_stat = relation(PokeathlonStat)
 
 
-PokemonItem.item = relation(Item, backref='pokemon')
-PokemonItem.version = relation(Version)
+Region.generation = relation(Generation, uselist=False)
+Region.version_group_regions = relation(VersionGroupRegion,
+    order_by=VersionGroupRegion.version_group_id.asc(),
+    backref='region')
+Region.version_groups = association_proxy('version_group_regions', 'version_group')
 
 
-PokemonMove.pokemon = relation(Pokemon, backref='pokemon_moves')
-PokemonMove.version_group = relation(VersionGroup)
-PokemonMove.machine = relation(Machine, backref='pokemon_moves',
-                               primaryjoin=and_(Machine.version_group_id==PokemonMove.version_group_id,
-                                                Machine.move_id==PokemonMove.move_id),
-                                foreign_keys=[Machine.version_group_id, Machine.move_id],
-                                uselist=False)
-PokemonMove.move = relation(Move, backref='pokemon_moves')
-PokemonMove.method = relation(PokemonMoveMethod)
 
 
-PokemonStat.stat = relation(Stat)
+Stat.damage_class = relation(MoveDamageClass,
+    backref='stats')
 
 
-# This is technically a has-many; Generation.main_region_id -> Region.id
-Region.generation = relation(Generation, uselist=False)
-Region.version_group_regions = relation(VersionGroupRegion, backref='region',
-                                        order_by='VersionGroupRegion.version_group_id')
-Region.version_groups = association_proxy('version_group_regions', 'version_group')
+StatHint.stat = relation(Stat,
+    innerjoin=True,
+    backref='hints')
 
 
-Stat.damage_class = relation(MoveDamageClass, backref='stats')
 
 
-StatHint.stat = relation(Stat, backref='hints')
+SuperContestCombo.first = relation(Move,
+    primaryjoin=SuperContestCombo.first_move_id==Move.id,
+    innerjoin=True, lazy='joined',
+    backref='super_contest_combo_first')
+SuperContestCombo.second = relation(Move,
+    primaryjoin=SuperContestCombo.second_move_id==Move.id,
+    innerjoin=True, lazy='joined',
+    backref='super_contest_combo_second')
 
 
-SuperContestCombo.first = relation(Move, primaryjoin=SuperContestCombo.first_move_id==Move.id,
-                                        backref='super_contest_combo_first')
-SuperContestCombo.second = relation(Move, primaryjoin=SuperContestCombo.second_move_id==Move.id,
-                                         backref='super_contest_combo_second')
 
 Type.damage_efficacies = relation(TypeEfficacy,
 
 Type.damage_efficacies = relation(TypeEfficacy,
-                                  primaryjoin=Type.id
-                                      ==TypeEfficacy.damage_type_id,
-                                  backref='damage_type')
+    primaryjoin=Type.id==TypeEfficacy.damage_type_id,
+    backref=backref('damage_type', innerjoin=True, lazy='joined'))
 Type.target_efficacies = relation(TypeEfficacy,
 Type.target_efficacies = relation(TypeEfficacy,
-                                  primaryjoin=Type.id
-                                      ==TypeEfficacy.target_type_id,
-                                  backref='target_type')
-
-Type.generation = relation(Generation, backref='types')
-Type.damage_class = relation(MoveDamageClass, backref='types')
-Type.pokemon = relation(Pokemon, secondary=PokemonType.__table__,
-                                 order_by=Pokemon.order,
-                                 )#back_populates='types')
-Type.moves = relation(Move, back_populates='type', order_by=Move.id)
-
-Version.version_group = relation(VersionGroup)#, back_populates='versions')
-Version.generation = association_proxy('version_group', 'generation')
+    primaryjoin=Type.id==TypeEfficacy.target_type_id,
+    backref=backref('target_type', innerjoin=True, lazy='joined'))
 
 
-VersionGroup.versions = relation(Version, order_by=Version.id, back_populates='version_group')
-VersionGroup.generation = relation(Generation, backref='version_groups')
-VersionGroup.version_group_regions = relation(VersionGroupRegion, backref='version_group')
-VersionGroup.regions = association_proxy('version_group_regions', 'region')
-VersionGroup.pokedex = relation(Pokedex, back_populates='version_groups')
+Type.generation = relation(Generation,
+    innerjoin=True,
+    backref='types')
+Type.damage_class = relation(MoveDamageClass,
+    backref='types')
 
 
-Move.effect = markdown.MoveEffectProperty('effect')
-Move.effect_map = markdown.MoveEffectProperty('effect_map')
-Move.short_effect = markdown.MoveEffectProperty('short_effect')
-Move.short_effect_map = markdown.MoveEffectProperty('short_effect_map')
 
 
-MoveChangelog.effect = markdown.MoveEffectProperty('effect')
-MoveChangelog.effect_map = markdown.MoveEffectProperty('effect_map')
-MoveChangelog.short_effect = markdown.MoveEffectProperty('short_effect')
-MoveChangelog.short_effect_map = markdown.MoveEffectProperty('short_effect_map')
+Version.generation = association_proxy('version_group', 'generation')
+
+VersionGroup.versions = relation(Version,
+    innerjoin=True,
+    order_by=Version.id,
+    backref=backref('version_group', lazy='joined'))
+VersionGroup.generation = relation(Generation,
+    innerjoin=True, lazy='joined',
+    backref='version_groups')
+VersionGroup.version_group_regions = relation(VersionGroupRegion,
+    backref='version_group')
+VersionGroup.regions = association_proxy('version_group_regions', 'region')