3 from sqlalchemy
import Column
, ForeignKey
, MetaData
, Table
4 from sqlalchemy
.ext
.declarative
import declarative_base
5 from sqlalchemy
.ext
.associationproxy
import association_proxy
6 from sqlalchemy
.orm
import backref
, eagerload_all
, relation
7 from sqlalchemy
.orm
.session
import Session
8 from sqlalchemy
.sql
import and_
9 from sqlalchemy
.types
import *
11 from pokedex
.db
import rst
14 TableBase
= declarative_base(metadata
=metadata
)
16 class Ability(TableBase
):
17 __tablename__
= 'abilities'
18 __singlename__
= 'ability'
19 id = Column(Integer
, primary_key
=True, nullable
=False)
20 name
= Column(Unicode(24), nullable
=False)
21 generation_id
= Column(Integer
, ForeignKey('generations.id'), nullable
=False)
22 effect
= Column(rst
.RstTextColumn(5120), nullable
=False)
23 short_effect
= Column(rst
.RstTextColumn(255), nullable
=False)
25 class AbilityFlavorText(TableBase
):
26 __tablename__
= 'ability_flavor_text'
27 ability_id
= Column(Integer
, ForeignKey('abilities.id'), primary_key
=True, nullable
=False, autoincrement
=False)
28 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), primary_key
=True, nullable
=False, autoincrement
=False)
29 flavor_text
= Column(Unicode(64), nullable
=False)
31 class Berry(TableBase
):
32 __tablename__
= 'berries'
33 id = Column(Integer
, primary_key
=True, nullable
=False)
34 item_id
= Column(Integer
, ForeignKey('items.id'), nullable
=False)
35 firmness_id
= Column(Integer
, ForeignKey('berry_firmness.id'), nullable
=False)
36 natural_gift_power
= Column(Integer
, nullable
=True)
37 natural_gift_type_id
= Column(Integer
, ForeignKey('types.id'), nullable
=True)
38 size
= Column(Integer
, nullable
=False)
39 max_harvest
= Column(Integer
, nullable
=False)
40 growth_time
= Column(Integer
, nullable
=False)
41 soil_dryness
= Column(Integer
, nullable
=False)
42 smoothness
= Column(Integer
, nullable
=False)
44 class BerryFirmness(TableBase
):
45 __tablename__
= 'berry_firmness'
46 id = Column(Integer
, primary_key
=True, nullable
=False)
47 name
= Column(Unicode(10), nullable
=False)
49 class BerryFlavor(TableBase
):
50 __tablename__
= 'berry_flavors'
51 berry_id
= Column(Integer
, ForeignKey('berries.id'), primary_key
=True, nullable
=False, autoincrement
=False)
52 contest_type_id
= Column(Integer
, ForeignKey('contest_types.id'), primary_key
=True, nullable
=False, autoincrement
=False)
53 flavor
= Column(Integer
, nullable
=False)
55 class ContestCombo(TableBase
):
56 __tablename__
= 'contest_combos'
57 first_move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False)
58 second_move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False)
60 class ContestEffect(TableBase
):
61 __tablename__
= 'contest_effects'
62 id = Column(Integer
, primary_key
=True, nullable
=False)
63 appeal
= Column(SmallInteger
, nullable
=False)
64 jam
= Column(SmallInteger
, nullable
=False)
65 flavor_text
= Column(Unicode(64), nullable
=False)
66 effect
= Column(Unicode(255), nullable
=False)
68 class ContestType(TableBase
):
69 __tablename__
= 'contest_types'
70 id = Column(Integer
, primary_key
=True, nullable
=False)
71 name
= Column(Unicode(6), nullable
=False)
72 flavor
= Column(Unicode(6), nullable
=False)
73 color
= Column(Unicode(6), nullable
=False)
75 class EggGroup(TableBase
):
76 __tablename__
= 'egg_groups'
77 id = Column(Integer
, primary_key
=True, nullable
=False)
78 name
= Column(Unicode(16), nullable
=False)
80 class Encounter(TableBase
):
81 """Rows in this table represent encounters with wild Pokémon. Bear with
84 Within a given area in a given game, encounters are differentiated by the
85 "slot" they are in and the state of the game world.
87 What the player is doing to get an encounter, such as surfing or walking
88 through tall grass, is called terrain. Each terrain has its own set of
91 Within a terrain, slots are defined primarily by rarity. Each slot can
92 also be affected by world conditions; for example, the 20% slot for walking
93 in tall grass is affected by whether a swarm is in effect in that area.
94 "Is there a swarm?" is a condition; "there is a swarm" and "there is not a
95 swarm" are the possible values of this condition.
97 A slot (20% walking in grass) and any appropriate world conditions (no
98 swarm) are thus enough to define a specific encounter.
100 Well, okay, almost: each slot actually appears twice.
103 __tablename__
= 'encounters'
104 id = Column(Integer
, primary_key
=True, nullable
=False)
105 version_id
= Column(Integer
, ForeignKey('versions.id'), nullable
=False, autoincrement
=False)
106 location_area_id
= Column(Integer
, ForeignKey('location_areas.id'), nullable
=False, autoincrement
=False)
107 encounter_slot_id
= Column(Integer
, ForeignKey('encounter_slots.id'), nullable
=False, autoincrement
=False)
108 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), nullable
=False, autoincrement
=False)
109 min_level
= Column(Integer
, nullable
=False, autoincrement
=False)
110 max_level
= Column(Integer
, nullable
=False, autoincrement
=False)
112 class EncounterCondition(TableBase
):
113 """Rows in this table represent varying conditions in the game world, such
117 __tablename__
= 'encounter_conditions'
118 id = Column(Integer
, primary_key
=True, nullable
=False)
119 name
= Column(Unicode(64), nullable
=False)
121 class EncounterConditionValue(TableBase
):
122 """Rows in this table represent possible states for a condition; for
123 example, the state of 'swarm' could be 'swarm' or 'no swarm'.
126 __tablename__
= 'encounter_condition_values'
127 id = Column(Integer
, primary_key
=True, nullable
=False)
128 encounter_condition_id
= Column(Integer
, ForeignKey('encounter_conditions.id'), primary_key
=False, nullable
=False, autoincrement
=False)
129 name
= Column(Unicode(64), nullable
=False)
130 is_default
= Column(Boolean
, nullable
=False)
132 class EncounterConditionValueMap(TableBase
):
133 """Maps encounters to the specific conditions under which they occur."""
135 __tablename__
= 'encounter_condition_value_map'
136 encounter_id
= Column(Integer
, ForeignKey('encounters.id'), primary_key
=True, nullable
=False, autoincrement
=False)
137 encounter_condition_value_id
= Column(Integer
, ForeignKey('encounter_condition_values.id'), primary_key
=True, nullable
=False, autoincrement
=False)
139 class EncounterTerrain(TableBase
):
140 """Rows in this table represent ways the player can enter a wild encounter,
141 e.g., surfing, fishing, or walking through tall grass.
144 __tablename__
= 'encounter_terrain'
145 id = Column(Integer
, primary_key
=True, nullable
=False)
146 name
= Column(Unicode(64), nullable
=False)
148 class EncounterSlot(TableBase
):
149 """Rows in this table represent an abstract "slot" within a terrain,
150 associated with both some set of conditions and a rarity.
152 Note that there are two encounters per slot, so the rarities will only add
156 __tablename__
= 'encounter_slots'
157 id = Column(Integer
, primary_key
=True, nullable
=False)
158 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), nullable
=False, autoincrement
=False)
159 encounter_terrain_id
= Column(Integer
, ForeignKey('encounter_terrain.id'), primary_key
=False, nullable
=False, autoincrement
=False)
160 slot
= Column(Integer
, nullable
=True)
161 rarity
= Column(Integer
, nullable
=False)
163 class EncounterSlotCondition(TableBase
):
164 """Lists all conditions that affect each slot."""
166 __tablename__
= 'encounter_slot_conditions'
167 encounter_slot_id
= Column(Integer
, ForeignKey('encounter_slots.id'), primary_key
=True, nullable
=False, autoincrement
=False)
168 encounter_condition_id
= Column(Integer
, ForeignKey('encounter_conditions.id'), primary_key
=True, nullable
=False, autoincrement
=False)
170 class EvolutionChain(TableBase
):
171 __tablename__
= 'evolution_chains'
172 id = Column(Integer
, primary_key
=True, nullable
=False)
173 growth_rate_id
= Column(Integer
, ForeignKey('growth_rates.id'), nullable
=False)
174 steps_to_hatch
= Column(Integer
, nullable
=False)
175 baby_trigger_item
= Column(Unicode(12))
177 class EvolutionTrigger(TableBase
):
178 __tablename__
= 'evolution_triggers'
179 id = Column(Integer
, primary_key
=True, nullable
=False)
180 identifier
= Column(Unicode(16), nullable
=False)
182 class Experience(TableBase
):
183 __tablename__
= 'experience'
184 growth_rate_id
= Column(Integer
, ForeignKey('growth_rates.id'), primary_key
=True, nullable
=False)
185 level
= Column(Integer
, primary_key
=True, nullable
=False, autoincrement
=False)
186 experience
= Column(Integer
, nullable
=False)
188 class Generation(TableBase
):
189 __tablename__
= 'generations'
190 id = Column(Integer
, primary_key
=True, nullable
=False)
191 main_region_id
= Column(Integer
, ForeignKey('regions.id'))
192 canonical_pokedex_id
= Column(Integer
, ForeignKey('pokedexes.id'))
193 name
= Column(Unicode(16), nullable
=False)
195 class GrowthRate(TableBase
):
196 """`formula` is written in LaTeX math notation."""
197 __tablename__
= 'growth_rates'
198 id = Column(Integer
, primary_key
=True, nullable
=False)
199 name
= Column(Unicode(20), nullable
=False)
200 formula
= Column(Unicode(500), nullable
=False)
202 class Item(TableBase
):
203 __tablename__
= 'items'
204 __singlename__
= 'item'
205 id = Column(Integer
, primary_key
=True, nullable
=False)
206 name
= Column(Unicode(16), nullable
=False)
207 category_id
= Column(Integer
, ForeignKey('item_categories.id'), nullable
=False)
208 cost
= Column(Integer
, nullable
=False)
209 fling_power
= Column(Integer
, nullable
=True)
210 fling_effect_id
= Column(Integer
, ForeignKey('item_fling_effects.id'), nullable
=True)
211 effect
= Column(rst
.RstTextColumn(5120), nullable
=False)
214 def appears_underground(self
):
215 return any(flag
.identifier
== u
'underground' for flag
in self
.flags
)
217 class ItemCategory(TableBase
):
218 __tablename__
= 'item_categories'
219 id = Column(Integer
, primary_key
=True, nullable
=False)
220 pocket_id
= Column(Integer
, ForeignKey('item_pockets.id'), nullable
=False)
221 name
= Column(Unicode(16), nullable
=False)
223 class ItemFlag(TableBase
):
224 __tablename__
= 'item_flags'
225 id = Column(Integer
, primary_key
=True, nullable
=False)
226 identifier
= Column(Unicode(24), nullable
=False)
227 name
= Column(Unicode(64), nullable
=False)
229 class ItemFlagMap(TableBase
):
230 __tablename__
= 'item_flag_map'
231 item_id
= Column(Integer
, ForeignKey('items.id'), primary_key
=True, autoincrement
=False, nullable
=False)
232 item_flag_id
= Column(Integer
, ForeignKey('item_flags.id'), primary_key
=True, autoincrement
=False, nullable
=False)
234 class ItemFlavorText(TableBase
):
235 __tablename__
= 'item_flavor_text'
236 item_id
= Column(Integer
, ForeignKey('items.id'), primary_key
=True, autoincrement
=False, nullable
=False)
237 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), primary_key
=True, autoincrement
=False, nullable
=False)
238 flavor_text
= Column(Unicode(255), nullable
=False)
240 class ItemFlingEffect(TableBase
):
241 __tablename__
= 'item_fling_effects'
242 id = Column(Integer
, primary_key
=True, nullable
=False)
243 effect
= Column(Unicode(255), nullable
=False)
245 class ItemInternalID(TableBase
):
246 __tablename__
= 'item_internal_ids'
247 item_id
= Column(Integer
, ForeignKey('items.id'), primary_key
=True, autoincrement
=False, nullable
=False)
248 generation_id
= Column(Integer
, ForeignKey('generations.id'), primary_key
=True, autoincrement
=False, nullable
=False)
249 internal_id
= Column(Integer
, nullable
=False)
251 class ItemPocket(TableBase
):
252 __tablename__
= 'item_pockets'
253 id = Column(Integer
, primary_key
=True, nullable
=False)
254 identifier
= Column(Unicode(16), nullable
=False)
255 name
= Column(Unicode(16), nullable
=False)
257 class Language(TableBase
):
258 __tablename__
= 'languages'
259 id = Column(Integer
, primary_key
=True, nullable
=False)
260 iso639
= Column(Unicode(2), nullable
=False)
261 iso3166
= Column(Unicode(2), nullable
=False)
262 name
= Column(Unicode(16), nullable
=False)
264 class Location(TableBase
):
265 __tablename__
= 'locations'
266 __singlename__
= 'location'
267 id = Column(Integer
, primary_key
=True, nullable
=False)
268 region_id
= Column(Integer
, ForeignKey('regions.id'))
269 name
= Column(Unicode(64), nullable
=False)
271 class LocationArea(TableBase
):
272 __tablename__
= 'location_areas'
273 id = Column(Integer
, primary_key
=True, nullable
=False)
274 location_id
= Column(Integer
, ForeignKey('locations.id'), nullable
=False)
275 internal_id
= Column(Integer
, nullable
=False)
276 name
= Column(Unicode(64), nullable
=True)
278 class LocationAreaEncounterRate(TableBase
):
279 __tablename__
= 'location_area_encounter_rates'
280 location_area_id
= Column(Integer
, ForeignKey('location_areas.id'), primary_key
=True, nullable
=False, autoincrement
=False)
281 encounter_terrain_id
= Column(Integer
, ForeignKey('encounter_terrain.id'), primary_key
=True, nullable
=False, autoincrement
=False)
282 version_id
= Column(Integer
, ForeignKey('versions.id'), primary_key
=True, autoincrement
=False)
283 rate
= Column(Integer
, nullable
=True)
285 class Machine(TableBase
):
286 __tablename__
= 'machines'
287 machine_number
= Column(Integer
, primary_key
=True, nullable
=False, autoincrement
=False)
288 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), primary_key
=True, nullable
=False, autoincrement
=False)
289 item_id
= Column(Integer
, ForeignKey('items.id'), nullable
=False)
290 move_id
= Column(Integer
, ForeignKey('moves.id'), nullable
=False)
294 return self
.machine_number
>= 100
296 class MoveBattleStyle(TableBase
):
297 __tablename__
= 'move_battle_styles'
298 id = Column(Integer
, primary_key
=True, nullable
=False)
299 name
= Column(Unicode(8), nullable
=False)
301 class MoveEffectCategory(TableBase
):
302 __tablename__
= 'move_effect_categories'
303 id = Column(Integer
, primary_key
=True, nullable
=False)
304 name
= Column(Unicode(64), nullable
=False)
305 can_affect_user
= Column(Boolean
, nullable
=False)
307 class MoveEffectCategoryMap(TableBase
):
308 __tablename__
= 'move_effect_category_map'
309 move_effect_id
= Column(Integer
, ForeignKey('move_effects.id'), primary_key
=True, nullable
=False)
310 move_effect_category_id
= Column(Integer
, ForeignKey('move_effect_categories.id'), primary_key
=True, nullable
=False)
311 affects_user
= Column(Boolean
, primary_key
=True, nullable
=False)
313 class MoveDamageClass(TableBase
):
314 __tablename__
= 'move_damage_classes'
315 id = Column(Integer
, primary_key
=True, nullable
=False)
316 name
= Column(Unicode(8), nullable
=False)
317 description
= Column(Unicode(64), nullable
=False)
319 class MoveEffect(TableBase
):
320 __tablename__
= 'move_effects'
321 id = Column(Integer
, primary_key
=True, nullable
=False)
322 priority
= Column(SmallInteger
, nullable
=False)
323 short_effect
= Column(Unicode(256), nullable
=False)
324 effect
= Column(Unicode(5120), nullable
=False)
326 class MoveFlag(TableBase
):
327 __tablename__
= 'move_flags'
328 move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False)
329 move_flag_type_id
= Column(Integer
, ForeignKey('move_flag_types.id'), primary_key
=True, nullable
=False, autoincrement
=False)
331 class MoveFlagType(TableBase
):
332 __tablename__
= 'move_flag_types'
333 id = Column(Integer
, primary_key
=True, nullable
=False)
334 name
= Column(Unicode(32), nullable
=False)
335 description
= Column(rst
.RstTextColumn(128), nullable
=False)
337 class MoveFlavorText(TableBase
):
338 __tablename__
= 'move_flavor_text'
339 move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False)
340 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), primary_key
=True, nullable
=False, autoincrement
=False)
341 flavor_text
= Column(Unicode(255), nullable
=False)
343 class MoveName(TableBase
):
344 __tablename__
= 'move_names'
345 move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False)
346 language_id
= Column(Integer
, ForeignKey('languages.id'), primary_key
=True, nullable
=False, autoincrement
=False)
347 name
= Column(Unicode(16), nullable
=False)
349 class MoveTarget(TableBase
):
350 __tablename__
= 'move_targets'
351 id = Column(Integer
, primary_key
=True, nullable
=False)
352 name
= Column(Unicode(32), nullable
=False)
353 description
= Column(Unicode(128), nullable
=False)
355 class Move(TableBase
):
356 __tablename__
= 'moves'
357 __singlename__
= 'move'
358 id = Column(Integer
, primary_key
=True, nullable
=False)
359 name
= Column(Unicode(12), nullable
=False)
360 generation_id
= Column(Integer
, ForeignKey('generations.id'), nullable
=False)
361 type_id
= Column(Integer
, ForeignKey('types.id'), nullable
=False)
362 power
= Column(SmallInteger
)
363 pp
= Column(SmallInteger
, nullable
=False)
364 accuracy
= Column(SmallInteger
)
365 target_id
= Column(Integer
, ForeignKey('move_targets.id'), nullable
=False)
366 damage_class_id
= Column(Integer
, ForeignKey('move_damage_classes.id'), nullable
=False)
367 effect_id
= Column(Integer
, ForeignKey('move_effects.id'), nullable
=False)
368 effect_chance
= Column(Integer
)
369 contest_type_id
= Column(Integer
, ForeignKey('contest_types.id'), nullable
=True)
370 contest_effect_id
= Column(Integer
, ForeignKey('contest_effects.id'), nullable
=True)
371 super_contest_effect_id
= Column(Integer
, ForeignKey('super_contest_effects.id'), nullable
=False)
373 class Nature(TableBase
):
374 __tablename__
= 'natures'
375 __singlename__
= 'nature'
376 id = Column(Integer
, primary_key
=True, nullable
=False)
377 name
= Column(Unicode(8), nullable
=False)
378 decreased_stat_id
= Column(Integer
, ForeignKey('stats.id'), nullable
=False)
379 increased_stat_id
= Column(Integer
, ForeignKey('stats.id'), nullable
=False)
380 hates_flavor_id
= Column(Integer
, ForeignKey('contest_types.id'), nullable
=False)
381 likes_flavor_id
= Column(Integer
, ForeignKey('contest_types.id'), nullable
=False)
383 class NatureBattleStylePreference(TableBase
):
384 __tablename__
= 'nature_battle_style_preferences'
385 nature_id
= Column(Integer
, ForeignKey('natures.id'), primary_key
=True, nullable
=False)
386 move_battle_style_id
= Column(Integer
, ForeignKey('move_battle_styles.id'), primary_key
=True, nullable
=False)
387 low_hp_preference
= Column(Integer
, nullable
=False)
388 high_hp_preference
= Column(Integer
, nullable
=False)
390 class NaturePokeathlonStat(TableBase
):
391 __tablename__
= 'nature_pokeathlon_stats'
392 nature_id
= Column(Integer
, ForeignKey('natures.id'), primary_key
=True, nullable
=False)
393 pokeathlon_stat_id
= Column(Integer
, ForeignKey('pokeathlon_stats.id'), primary_key
=True, nullable
=False)
394 max_change
= Column(Integer
, nullable
=False)
396 class PokeathlonStat(TableBase
):
397 __tablename__
= 'pokeathlon_stats'
398 id = Column(Integer
, primary_key
=True, nullable
=False)
399 name
= Column(Unicode(8), nullable
=False)
401 class Pokedex(TableBase
):
402 __tablename__
= 'pokedexes'
403 id = Column(Integer
, primary_key
=True, nullable
=False)
404 region_id
= Column(Integer
, ForeignKey('regions.id'), nullable
=True)
405 name
= Column(Unicode(16), nullable
=False)
406 description
= Column(Unicode(512))
408 class PokedexVersionGroup(TableBase
):
409 __tablename__
= 'pokedex_version_groups'
410 pokedex_id
= Column(Integer
, ForeignKey('pokedexes.id'), primary_key
=True, nullable
=False, autoincrement
=False)
411 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), primary_key
=True, nullable
=False, autoincrement
=False)
413 class Pokemon(TableBase
):
414 """The core to this whole mess.
416 Note that I use both 'forme' and 'form' in both code and the database. I
417 only use 'forme' when specifically referring to Pokémon that have multiple
418 distinct species as forms—i.e., different stats or movesets. 'Form' is a
419 more general term referring to any variation within a species, including
420 purely cosmetic forms like Unown.
422 __tablename__
= 'pokemon'
423 __singlename__
= 'pokemon'
424 id = Column(Integer
, primary_key
=True, nullable
=False)
425 name
= Column(Unicode(20), nullable
=False)
426 forme_name
= Column(Unicode(16))
427 forme_base_pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'))
428 generation_id
= Column(Integer
, ForeignKey('generations.id'))
429 evolution_chain_id
= Column(Integer
, ForeignKey('evolution_chains.id'))
430 height
= Column(Integer
, nullable
=False)
431 weight
= Column(Integer
, nullable
=False)
432 species
= Column(Unicode(16), nullable
=False)
433 color_id
= Column(Integer
, ForeignKey('pokemon_colors.id'), nullable
=False)
434 pokemon_shape_id
= Column(Integer
, ForeignKey('pokemon_shapes.id'), nullable
=False)
435 habitat_id
= Column(Integer
, ForeignKey('pokemon_habitats.id'), nullable
=True)
436 gender_rate
= Column(Integer
, nullable
=False)
437 capture_rate
= Column(Integer
, nullable
=False)
438 base_experience
= Column(Integer
, nullable
=False)
439 base_happiness
= Column(Integer
, nullable
=False)
440 is_baby
= Column(Boolean
, nullable
=False)
441 has_gen4_fem_sprite
= Column(Boolean
, nullable
=False)
442 has_gen4_fem_back_sprite
= Column(Boolean
, nullable
=False)
444 ### Stuff to handle alternate Pokémon forms
447 def national_id(self
):
448 """Returns the National Pokédex number for this Pokémon. Use this
449 instead of the id directly; alternate formes may make the id incorrect.
452 if self
.forme_base_pokemon_id
:
453 return self
.forme_base_pokemon_id
458 """Returns the name of this Pokémon, including its Forme, if any."""
461 return "%s %s" %
(self
.forme_name
.title(), self
.name
)
465 def normal_form(self
):
466 """Returns the normal form for this Pokémon; i.e., this will return
467 regular Deoxys when called on any Deoxys form.
470 if self
.forme_base_pokemon
:
471 return self
.forme_base_pokemon
477 def stat(self
, stat_name
):
478 """Returns a PokemonStat record for the given stat name (or Stat row
479 object). Uses the normal has-many machinery, so all the stats are
482 if isinstance(stat_name
, Stat
):
483 stat_name
= stat_name
.name
485 for pokemon_stat
in self
.stats
:
486 if pokemon_stat
.stat
.name
== stat_name
:
491 class PokemonAbility(TableBase
):
492 __tablename__
= 'pokemon_abilities'
493 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False)
494 ability_id
= Column(Integer
, ForeignKey('abilities.id'), nullable
=False)
495 slot
= Column(Integer
, primary_key
=True, nullable
=False, autoincrement
=False)
497 class PokemonColor(TableBase
):
498 __tablename__
= 'pokemon_colors'
499 id = Column(Integer
, primary_key
=True, nullable
=False, autoincrement
=False)
500 name
= Column(Unicode(6), nullable
=False)
502 class PokemonDexNumber(TableBase
):
503 __tablename__
= 'pokemon_dex_numbers'
504 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False)
505 pokedex_id
= Column(Integer
, ForeignKey('pokedexes.id'), primary_key
=True, nullable
=False, autoincrement
=False)
506 pokedex_number
= Column(Integer
, nullable
=False)
508 class PokemonEggGroup(TableBase
):
509 __tablename__
= 'pokemon_egg_groups'
510 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False)
511 egg_group_id
= Column(Integer
, ForeignKey('egg_groups.id'), primary_key
=True, nullable
=False, autoincrement
=False)
513 class PokemonEvolution(TableBase
):
514 __tablename__
= 'pokemon_evolution'
515 from_pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), nullable
=False)
516 to_pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False)
517 evolution_trigger_id
= Column(Integer
, ForeignKey('evolution_triggers.id'), nullable
=False)
518 trigger_item_id
= Column(Integer
, ForeignKey('items.id'), nullable
=True)
519 minimum_level
= Column(Integer
, nullable
=True)
520 gender
= Column(Enum('male', 'female', name
='pokemon_evolution_gender'), nullable
=True)
521 location_id
= Column(Integer
, ForeignKey('locations.id'), nullable
=True)
522 held_item_id
= Column(Integer
, ForeignKey('items.id'), nullable
=True)
523 time_of_day
= Column(Enum('morning', 'day', 'night', name
='pokemon_evolution_time_of_day'), nullable
=True)
524 known_move_id
= Column(Integer
, ForeignKey('moves.id'), nullable
=True)
525 minimum_happiness
= Column(Integer
, nullable
=True)
526 minimum_beauty
= Column(Integer
, nullable
=True)
527 relative_physical_stats
= Column(Integer
, nullable
=True)
528 party_pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), nullable
=True)
530 class PokemonFlavorText(TableBase
):
531 __tablename__
= 'pokemon_flavor_text'
532 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False)
533 version_id
= Column(Integer
, ForeignKey('versions.id'), primary_key
=True, nullable
=False, autoincrement
=False)
534 flavor_text
= Column(Unicode(255), nullable
=False)
536 class PokemonFormGroup(TableBase
):
537 __tablename__
= 'pokemon_form_groups'
538 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False)
539 is_battle_only
= Column(Boolean
, nullable
=False)
540 description
= Column(Unicode(512), nullable
=False)
542 class PokemonFormSprite(TableBase
):
543 __tablename__
= 'pokemon_form_sprites'
544 id = Column(Integer
, primary_key
=True, nullable
=False)
545 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False)
546 introduced_in_version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), primary_key
=True, nullable
=False, autoincrement
=False)
547 name
= Column(Unicode(16), nullable
=True)
548 is_default
= Column(Boolean
, nullable
=True)
550 class PokemonHabitat(TableBase
):
551 __tablename__
= 'pokemon_habitats'
552 id = Column(Integer
, primary_key
=True, nullable
=False, autoincrement
=False)
553 name
= Column(Unicode(16), nullable
=False)
555 class PokemonItem(TableBase
):
556 __tablename__
= 'pokemon_items'
557 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False)
558 version_id
= Column(Integer
, ForeignKey('versions.id'), primary_key
=True, nullable
=False, autoincrement
=False)
559 item_id
= Column(Integer
, ForeignKey('items.id'), primary_key
=True, nullable
=False, autoincrement
=False)
560 rarity
= Column(Integer
, nullable
=False)
562 class PokemonMove(TableBase
):
563 __tablename__
= 'pokemon_moves'
564 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False)
565 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), primary_key
=True, nullable
=False, autoincrement
=False)
566 move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False, index
=True)
567 pokemon_move_method_id
= Column(Integer
, ForeignKey('pokemon_move_methods.id'), primary_key
=True, nullable
=False, autoincrement
=False)
568 level
= Column(Integer
, primary_key
=True, nullable
=True, autoincrement
=False)
569 order
= Column(Integer
, nullable
=True)
571 class PokemonMoveMethod(TableBase
):
572 __tablename__
= 'pokemon_move_methods'
573 id = Column(Integer
, primary_key
=True, nullable
=False, autoincrement
=False)
574 name
= Column(Unicode(64), nullable
=False)
575 description
= Column(Unicode(255), nullable
=False)
577 class PokemonName(TableBase
):
578 __tablename__
= 'pokemon_names'
579 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False)
580 language_id
= Column(Integer
, ForeignKey('languages.id'), primary_key
=True, nullable
=False, autoincrement
=False)
581 name
= Column(Unicode(16), nullable
=False)
583 class PokemonShape(TableBase
):
584 __tablename__
= 'pokemon_shapes'
585 id = Column(Integer
, primary_key
=True, nullable
=False)
586 name
= Column(Unicode(24), nullable
=False)
587 awesome_name
= Column(Unicode(16), nullable
=False)
589 class PokemonStat(TableBase
):
590 __tablename__
= 'pokemon_stats'
591 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False)
592 stat_id
= Column(Integer
, ForeignKey('stats.id'), primary_key
=True, nullable
=False, autoincrement
=False)
593 base_stat
= Column(Integer
, nullable
=False)
594 effort
= Column(Integer
, nullable
=False)
596 class PokemonType(TableBase
):
597 __tablename__
= 'pokemon_types'
598 pokemon_id
= Column(Integer
, ForeignKey('pokemon.id'), primary_key
=True, nullable
=False, autoincrement
=False)
599 type_id
= Column(Integer
, ForeignKey('types.id'), nullable
=False)
600 slot
= Column(Integer
, primary_key
=True, nullable
=False, autoincrement
=False)
602 class Region(TableBase
):
603 """Major areas of the world: Kanto, Johto, etc."""
604 __tablename__
= 'regions'
605 id = Column(Integer
, primary_key
=True, nullable
=False)
606 name
= Column(Unicode(16), nullable
=False)
608 class Stat(TableBase
):
609 __tablename__
= 'stats'
610 id = Column(Integer
, primary_key
=True, nullable
=False)
611 name
= Column(Unicode(16), nullable
=False)
613 class SuperContestCombo(TableBase
):
614 __tablename__
= 'super_contest_combos'
615 first_move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False)
616 second_move_id
= Column(Integer
, ForeignKey('moves.id'), primary_key
=True, nullable
=False, autoincrement
=False)
618 class SuperContestEffect(TableBase
):
619 __tablename__
= 'super_contest_effects'
620 id = Column(Integer
, primary_key
=True, nullable
=False)
621 appeal
= Column(SmallInteger
, nullable
=False)
622 flavor_text
= Column(Unicode(64), nullable
=False)
624 class TypeEfficacy(TableBase
):
625 __tablename__
= 'type_efficacy'
626 damage_type_id
= Column(Integer
, ForeignKey('types.id'), primary_key
=True, nullable
=False, autoincrement
=False)
627 target_type_id
= Column(Integer
, ForeignKey('types.id'), primary_key
=True, nullable
=False, autoincrement
=False)
628 damage_factor
= Column(Integer
, nullable
=False)
630 class Type(TableBase
):
631 __tablename__
= 'types'
632 __singlename__
= 'type'
633 id = Column(Integer
, primary_key
=True, nullable
=False)
634 name
= Column(Unicode(8), nullable
=False)
635 abbreviation
= Column(Unicode(3), nullable
=False)
636 generation_id
= Column(Integer
, ForeignKey('generations.id'), nullable
=False)
637 damage_class_id
= Column(Integer
, ForeignKey('move_damage_classes.id'), nullable
=False) ## ??? is none; everything else is physical or special
639 class VersionGroup(TableBase
):
640 __tablename__
= 'version_groups'
641 id = Column(Integer
, primary_key
=True, nullable
=False)
642 generation_id
= Column(Integer
, ForeignKey('generations.id'), nullable
=False)
644 class VersionGroupRegion(TableBase
):
645 __tablename__
= 'version_group_regions'
646 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), primary_key
=True, nullable
=False)
647 region_id
= Column(Integer
, ForeignKey('regions.id'), primary_key
=True, nullable
=False)
649 class Version(TableBase
):
650 __tablename__
= 'versions'
651 id = Column(Integer
, primary_key
=True, nullable
=False)
652 version_group_id
= Column(Integer
, ForeignKey('version_groups.id'), nullable
=False)
653 name
= Column(Unicode(32), nullable
=False)
656 ### Relations down here, to avoid ordering problems
657 Ability
.flavor_text
= relation(AbilityFlavorText
, order_by
=AbilityFlavorText
.version_group_id
, backref
='abilities')
658 Ability
.generation
= relation(Generation
, backref
='abilities')
660 AbilityFlavorText
.version_group
= relation(VersionGroup
)
662 Berry
.berry_firmness
= relation(BerryFirmness
, backref
='berries')
663 Berry
.firmness
= association_proxy('berry_firmness', 'name')
664 Berry
.flavors
= relation(BerryFlavor
, order_by
=BerryFlavor
.contest_type_id
, backref
='berry')
665 Berry
.natural_gift_type
= relation(Type
)
667 BerryFlavor
.contest_type
= relation(ContestType
)
669 ContestCombo
.first
= relation(Move
, primaryjoin
=ContestCombo
.first_move_id
==Move
.id,
670 backref
='contest_combo_first')
671 ContestCombo
.second
= relation(Move
, primaryjoin
=ContestCombo
.second_move_id
==Move
.id,
672 backref
='contest_combo_second')
674 Encounter
.location_area
= relation(LocationArea
, backref
='encounters')
675 Encounter
.pokemon
= relation(Pokemon
, backref
='encounters')
676 Encounter
.version
= relation(Version
, backref
='encounters')
677 Encounter
.slot
= relation(EncounterSlot
, backref
='encounters')
679 EncounterConditionValue
.condition
= relation(EncounterCondition
, backref
='values')
681 Encounter
.condition_value_map
= relation(EncounterConditionValueMap
, backref
='encounter')
682 Encounter
.condition_values
= association_proxy('condition_value_map', 'condition_value')
683 EncounterConditionValueMap
.condition_value
= relation(EncounterConditionValue
,
684 backref
='encounter_map')
686 EncounterSlot
.terrain
= relation(EncounterTerrain
, backref
='slots')
688 EncounterSlot
.condition_map
= relation(EncounterSlotCondition
, backref
='slot')
689 EncounterSlot
.conditions
= association_proxy('condition_map', 'condition')
690 EncounterSlotCondition
.condition
= relation(EncounterCondition
,
693 EvolutionChain
.growth_rate
= relation(GrowthRate
, backref
='evolution_chains')
695 Experience
.growth_rate
= relation(GrowthRate
, backref
='experience_table')
697 Generation
.canonical_pokedex
= relation(Pokedex
, backref
='canonical_for_generation')
698 Generation
.versions
= relation(Version
, secondary
=VersionGroup
.__table__
)
699 Generation
.main_region
= relation(Region
)
701 GrowthRate
.max_experience_obj
= relation(Experience
, primaryjoin
=and_(Experience
.growth_rate_id
== GrowthRate
.id, Experience
.level
== 100), uselist
=False)
702 GrowthRate
.max_experience
= association_proxy('max_experience_obj', 'experience')
704 Item
.berry
= relation(Berry
, uselist
=False, backref
='item')
705 Item
.flags
= relation(ItemFlag
, secondary
=ItemFlagMap
.__table__
)
706 Item
.flavor_text
= relation(ItemFlavorText
, order_by
=ItemFlavorText
.version_group_id
.asc(), backref
='item')
707 Item
.fling_effect
= relation(ItemFlingEffect
, backref
='items')
708 Item
.machines
= relation(Machine
, order_by
=Machine
.version_group_id
.asc())
709 Item
.category
= relation(ItemCategory
)
710 Item
.pocket
= association_proxy('category', 'pocket')
712 ItemCategory
.items
= relation(Item
, order_by
=Item
.name
)
713 ItemCategory
.pocket
= relation(ItemPocket
)
715 ItemFlavorText
.version_group
= relation(VersionGroup
)
717 ItemPocket
.categories
= relation(ItemCategory
, order_by
=ItemCategory
.name
)
719 Location
.region
= relation(Region
, backref
='locations')
721 LocationArea
.location
= relation(Location
, backref
='areas')
723 Machine
.item
= relation(Item
)
724 Machine
.version_group
= relation(VersionGroup
)
726 Move
.contest_effect
= relation(ContestEffect
, backref
='moves')
727 Move
.contest_combo_next
= association_proxy('contest_combo_first', 'second')
728 Move
.contest_combo_prev
= association_proxy('contest_combo_second', 'first')
729 Move
.contest_type
= relation(ContestType
, backref
='moves')
730 Move
.damage_class
= relation(MoveDamageClass
, backref
='moves')
731 Move
.flags
= association_proxy('move_flags', 'flag')
732 Move
.flavor_text
= relation(MoveFlavorText
, order_by
=MoveFlavorText
.version_group_id
, backref
='move')
733 Move
.foreign_names
= relation(MoveName
, backref
='pokemon')
734 Move
.generation
= relation(Generation
, backref
='moves')
735 Move
.machines
= relation(Machine
, backref
='move')
736 Move
.move_effect
= relation(MoveEffect
, backref
='moves')
737 Move
.move_flags
= relation(MoveFlag
, backref
='move')
738 Move
.super_contest_effect
= relation(SuperContestEffect
, backref
='moves')
739 Move
.super_contest_combo_next
= association_proxy('super_contest_combo_first', 'second')
740 Move
.super_contest_combo_prev
= association_proxy('super_contest_combo_second', 'first')
741 Move
.target
= relation(MoveTarget
, backref
='moves')
742 Move
.type = relation(Type
, backref
='moves')
744 Move
.effect
= rst
.MoveEffectProperty('effect')
745 Move
.priority
= association_proxy('move_effect', 'priority')
746 Move
.short_effect
= rst
.MoveEffectProperty('short_effect')
748 MoveEffect
.category_map
= relation(MoveEffectCategoryMap
)
749 MoveEffect
.categories
= association_proxy('category_map', 'category')
750 MoveEffectCategoryMap
.category
= relation(MoveEffectCategory
)
752 MoveFlag
.flag
= relation(MoveFlagType
)
754 MoveFlavorText
.version_group
= relation(VersionGroup
)
756 MoveName
.language
= relation(Language
)
758 Nature
.decreased_stat
= relation(Stat
, primaryjoin
=Nature
.decreased_stat_id
==Stat
.id,
759 backref
='decreasing_natures')
760 Nature
.increased_stat
= relation(Stat
, primaryjoin
=Nature
.increased_stat_id
==Stat
.id,
761 backref
='increasing_natures')
762 Nature
.hates_flavor
= relation(ContestType
, primaryjoin
=Nature
.hates_flavor_id
==ContestType
.id,
763 backref
='hating_natures')
764 Nature
.likes_flavor
= relation(ContestType
, primaryjoin
=Nature
.likes_flavor_id
==ContestType
.id,
765 backref
='liking_natures')
766 Nature
.battle_style_preferences
= relation(NatureBattleStylePreference
,
767 order_by
=NatureBattleStylePreference
.move_battle_style_id
,
769 Nature
.pokeathlon_effects
= relation(NaturePokeathlonStat
, order_by
=NaturePokeathlonStat
.pokeathlon_stat_id
)
771 NatureBattleStylePreference
.battle_style
= relation(MoveBattleStyle
, backref
='nature_preferences')
773 NaturePokeathlonStat
.pokeathlon_stat
= relation(PokeathlonStat
, backref
='nature_effects')
775 Pokedex
.region
= relation(Region
, backref
='pokedexes')
776 Pokedex
.version_groups
= relation(VersionGroup
, secondary
=PokedexVersionGroup
.__table__
, backref
='pokedexes')
778 Pokemon
.abilities
= relation(Ability
, secondary
=PokemonAbility
.__table__
,
779 order_by
=PokemonAbility
.slot
,
781 Pokemon
.formes
= relation(Pokemon
, primaryjoin
=Pokemon
.id==Pokemon
.forme_base_pokemon_id
,
782 backref
=backref('forme_base_pokemon',
783 remote_side
=[Pokemon
.id]))
784 Pokemon
.pokemon_color
= relation(PokemonColor
, backref
='pokemon')
785 Pokemon
.color
= association_proxy('pokemon_color', 'name')
786 Pokemon
.dex_numbers
= relation(PokemonDexNumber
, backref
='pokemon')
787 Pokemon
.default_form_sprite
= relation(PokemonFormSprite
,
789 Pokemon
.id==PokemonFormSprite
.pokemon_id
,
790 PokemonFormSprite
.is_default
==True,
793 Pokemon
.egg_groups
= relation(EggGroup
, secondary
=PokemonEggGroup
.__table__
,
794 order_by
=PokemonEggGroup
.egg_group_id
,
796 Pokemon
.evolution_chain
= relation(EvolutionChain
, backref
='pokemon')
797 Pokemon
.evolution_children
= relation(Pokemon
,
798 secondary
=PokemonEvolution
.__table__
,
799 primaryjoin
=Pokemon
.id==PokemonEvolution
.from_pokemon_id
,
800 secondaryjoin
=PokemonEvolution
.to_pokemon_id
==Pokemon
.id,
801 backref
=backref('evolution_parent',
802 remote_side
=[Pokemon
.id],
806 Pokemon
.flavor_text
= relation(PokemonFlavorText
, order_by
=PokemonFlavorText
.version_id
.asc(), backref
='pokemon')
807 Pokemon
.foreign_names
= relation(PokemonName
, backref
='pokemon')
808 Pokemon
.pokemon_habitat
= relation(PokemonHabitat
, backref
='pokemon')
809 Pokemon
.habitat
= association_proxy('pokemon_habitat', 'name')
810 Pokemon
.items
= relation(PokemonItem
, backref
='pokemon')
811 Pokemon
.generation
= relation(Generation
, backref
='pokemon')
812 Pokemon
.shape
= relation(PokemonShape
, backref
='pokemon')
813 Pokemon
.stats
= relation(PokemonStat
, backref
='pokemon')
814 Pokemon
.types
= relation(Type
, secondary
=PokemonType
.__table__
, order_by
=PokemonType
.slot
.asc())
816 PokemonDexNumber
.pokedex
= relation(Pokedex
)
818 PokemonEvolution
.from_pokemon
= relation(Pokemon
,
819 primaryjoin
=PokemonEvolution
.from_pokemon_id
==Pokemon
.id,
820 backref
='child_evolutions',
822 PokemonEvolution
.to_pokemon
= relation(Pokemon
,
823 primaryjoin
=PokemonEvolution
.to_pokemon_id
==Pokemon
.id,
824 backref
=backref('parent_evolution', uselist
=False),
826 PokemonEvolution
.child_evolutions
= relation(PokemonEvolution
,
827 primaryjoin
=PokemonEvolution
.from_pokemon_id
==PokemonEvolution
.to_pokemon_id
,
828 foreign_keys
=[PokemonEvolution
.to_pokemon_id
],
829 backref
=backref('parent_evolution',
830 remote_side
=[PokemonEvolution
.from_pokemon_id
],
834 PokemonEvolution
.trigger
= relation(EvolutionTrigger
, backref
='evolutions')
835 PokemonEvolution
.trigger_item
= relation(Item
,
836 primaryjoin
=PokemonEvolution
.trigger_item_id
==Item
.id,
837 backref
='triggered_evolutions',
839 PokemonEvolution
.held_item
= relation(Item
,
840 primaryjoin
=PokemonEvolution
.held_item_id
==Item
.id,
841 backref
='required_for_evolutions',
843 PokemonEvolution
.location
= relation(Location
, backref
='triggered_evolutions')
844 PokemonEvolution
.known_move
= relation(Move
, backref
='triggered_evolutions')
845 PokemonEvolution
.party_pokemon
= relation(Pokemon
,
846 primaryjoin
=PokemonEvolution
.party_pokemon_id
==Pokemon
.id,
847 backref
='triggered_evolutions',
850 PokemonFlavorText
.version
= relation(Version
)
852 PokemonItem
.item
= relation(Item
, backref
='pokemon')
853 PokemonItem
.version
= relation(Version
)
855 PokemonFormGroup
.pokemon
= relation(Pokemon
, backref
=backref('form_group',
857 PokemonFormSprite
.pokemon
= relation(Pokemon
, backref
='form_sprites')
858 PokemonFormSprite
.introduced_in
= relation(VersionGroup
)
860 PokemonMove
.pokemon
= relation(Pokemon
, backref
='pokemon_moves')
861 PokemonMove
.version_group
= relation(VersionGroup
)
862 PokemonMove
.machine
= relation(Machine
, backref
='pokemon_moves',
863 primaryjoin
=and_(Machine
.version_group_id
==PokemonMove
.version_group_id
,
864 Machine
.move_id
==PokemonMove
.move_id
),
865 foreign_keys
=[Machine
.version_group_id
, Machine
.move_id
],
867 PokemonMove
.move
= relation(Move
, backref
='pokemon_moves')
868 PokemonMove
.method
= relation(PokemonMoveMethod
)
870 PokemonName
.language
= relation(Language
)
872 PokemonStat
.stat
= relation(Stat
)
874 # This is technically a has-many; Generation.main_region_id -> Region.id
875 Region
.generation
= relation(Generation
, uselist
=False)
876 Region
.version_group_regions
= relation(VersionGroupRegion
, backref
='region',
877 order_by
='VersionGroupRegion.version_group_id')
878 Region
.version_groups
= association_proxy('version_group_regions', 'version_group')
880 SuperContestCombo
.first
= relation(Move
, primaryjoin
=SuperContestCombo
.first_move_id
==Move
.id,
881 backref
='super_contest_combo_first')
882 SuperContestCombo
.second
= relation(Move
, primaryjoin
=SuperContestCombo
.second_move_id
==Move
.id,
883 backref
='super_contest_combo_second')
885 Type
.damage_efficacies
= relation(TypeEfficacy
,
887 ==TypeEfficacy
.damage_type_id
,
888 backref
='damage_type')
889 Type
.target_efficacies
= relation(TypeEfficacy
,
891 ==TypeEfficacy
.target_type_id
,
892 backref
='target_type')
894 Type
.generation
= relation(Generation
, backref
='types')
895 Type
.damage_class
= relation(MoveDamageClass
, backref
='types')
897 Version
.version_group
= relation(VersionGroup
, backref
='versions')
898 Version
.generation
= association_proxy('version_group', 'generation')
900 VersionGroup
.generation
= relation(Generation
, backref
='version_groups')
901 VersionGroup
.version_group_regions
= relation(VersionGroupRegion
, backref
='version_group')
902 VersionGroup
.regions
= association_proxy('version_group_regions', 'region')