Added move flavor text.
[zzz-pokedex.git] / pokedex / db / tables.py
1 # encoding: utf8
2
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, relation
7 from sqlalchemy.types import *
8 from sqlalchemy.databases.mysql import *
9
10 from pokedex.db import rst
11
12 metadata = MetaData()
13 TableBase = declarative_base(metadata=metadata)
14
15 class Ability(TableBase):
16 __tablename__ = 'abilities'
17 __singlename__ = 'ability'
18 id = Column(Integer, primary_key=True, nullable=False)
19 name = Column(Unicode(24), nullable=False)
20 flavor_text = Column(Unicode(64), nullable=False)
21 effect = Column(Unicode(255), nullable=False)
22
23 class ContestEffect(TableBase):
24 __tablename__ = 'contest_effects'
25 id = Column(Integer, primary_key=True, nullable=False)
26 appeal = Column(SmallInteger, nullable=False)
27 jam = Column(SmallInteger, nullable=False)
28 flavor_text = Column(Unicode(64), nullable=False)
29 effect = Column(Unicode(255), nullable=False)
30
31 class EggGroup(TableBase):
32 __tablename__ = 'egg_groups'
33 id = Column(Integer, primary_key=True, nullable=False)
34 name = Column(Unicode(16), nullable=False)
35
36 class Encounter(TableBase):
37 """Rows in this table represent encounters with wild Pokémon.
38
39 Within a given area in a given game, encounters are differentiated by the
40 slot they are in and a world condition.
41
42 Groups of slots belong to encounter types; these are what the player is
43 doing to get an encounter, such as surfing or walking through tall grass.
44
45 Within an encounter type, slots are defined primarily by rarity. Each slot
46 can also be affected by a world condition; for example, the 20% slot for
47 walking in tall grass is affected by whether a swarm is in effect in the
48 areas. "There is a swarm" and "there is not a swarm" are conditions, and
49 together they make a condition group. However, since "not a swarm" is a
50 base state rather than any sort of new state, it is omitted and instead
51 referred to by a NULL.
52
53 A slot (20% walking in grass) and single world condition (NULL, i.e. no
54 swarm) are thus enough to define a specific encounter.
55
56 Well, okay, almost: each slot actually appears twice.
57 """
58
59 __tablename__ = 'encounters'
60 id = Column(Integer, primary_key=True, nullable=False)
61 version_id = Column(Integer, ForeignKey('versions.id'), nullable=False, autoincrement=False)
62 location_area_id = Column(Integer, ForeignKey('location_areas.id'), nullable=False, autoincrement=False)
63 encounter_type_slot_id = Column(Integer, ForeignKey('encounter_type_slots.id'), nullable=False, autoincrement=False)
64 encounter_condition_id = Column(Integer, ForeignKey('encounter_conditions.id'), nullable=True, autoincrement=False)
65 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), nullable=False, autoincrement=False)
66 min_level = Column(Integer, nullable=False, autoincrement=False)
67 max_level = Column(Integer, nullable=False, autoincrement=False)
68
69 class EncounterCondition(TableBase):
70 """Rows in this table represent something different about the world that
71 can affect what Pokémon are encountered.
72 """
73
74 __tablename__ = 'encounter_conditions'
75 id = Column(Integer, primary_key=True, nullable=False)
76 encounter_condition_group_id = Column(Integer, ForeignKey('encounter_condition_groups.id'), primary_key=False, nullable=False, autoincrement=False)
77 name = Column(Unicode(64), nullable=False)
78
79 class EncounterConditionGroup(TableBase):
80 """Rows in this table represent a group of mutually exclusive conditions,
81 such as morning/day/night. "Conditions" that are part of the default state
82 of the world, such as "not during a swarm" or "not using the PokéRadar",
83 are not included in this table and are referred to by NULLs in other
84 tables.
85 """
86
87 __tablename__ = 'encounter_condition_groups'
88 id = Column(Integer, primary_key=True, nullable=False)
89 name = Column(Unicode(64), nullable=False)
90
91 class EncounterType(TableBase):
92 """Rows in this table represent ways the player can enter a wild encounter;
93 i.e. surfing, fishing, or walking through tall grass.
94 """
95
96 __tablename__ = 'encounter_types'
97 id = Column(Integer, primary_key=True, nullable=False)
98 name = Column(Unicode(64), nullable=False)
99
100 class EncounterTypeSlot(TableBase):
101 """Rows in this table represent an abstract "slot" within an encounter
102 type, associated with both a condition group and a rarity.
103
104 Note that there are two encounters per slot, so the rarities will only add
105 up to 50.
106 """
107
108 __tablename__ = 'encounter_type_slots'
109 id = Column(Integer, primary_key=True, nullable=False)
110 encounter_type_id = Column(Integer, ForeignKey('encounter_types.id'), primary_key=False, nullable=False, autoincrement=False)
111 encounter_condition_group_id = Column(Integer, ForeignKey('encounter_condition_groups.id'), primary_key=False, nullable=True, autoincrement=False)
112 rarity = Column(Integer, nullable=False, autoincrement=False)
113
114 class EvolutionChain(TableBase):
115 __tablename__ = 'evolution_chains'
116 id = Column(Integer, primary_key=True, nullable=False)
117 growth_rate_id = Column(Integer, ForeignKey('growth_rates.id'), nullable=False)
118 steps_to_hatch = Column(Integer, nullable=False)
119 baby_trigger_item = Column(Unicode(12))
120
121 class EvolutionMethod(TableBase):
122 __tablename__ = 'evolution_methods'
123 id = Column(Integer, primary_key=True, nullable=False)
124 name = Column(Unicode(64), nullable=False)
125 description = Column(Unicode(255), nullable=False)
126
127 class Generation(TableBase):
128 __tablename__ = 'generations'
129 id = Column(Integer, primary_key=True, nullable=False)
130 name = Column(Unicode(16), nullable=False)
131 main_region = Column(Unicode(16), nullable=False)
132
133 class GrowthRate(TableBase):
134 """`formula` is written in LaTeX math notation."""
135 __tablename__ = 'growth_rates'
136 id = Column(Integer, primary_key=True, nullable=False)
137 name = Column(Unicode(20), nullable=False)
138 formula = Column(Unicode(500), nullable=False)
139
140 class Item(TableBase):
141 __tablename__ = 'items'
142 __singlename__ = 'item'
143 id = Column(Integer, primary_key=True, nullable=False)
144 name = Column(Unicode(16), nullable=False)
145
146 class Language(TableBase):
147 __tablename__ = 'languages'
148 id = Column(Integer, primary_key=True, nullable=False)
149 name = Column(Unicode(16), nullable=False)
150
151 class Location(TableBase):
152 __tablename__ = 'locations'
153 __singlename__ = 'location'
154 id = Column(Integer, primary_key=True, nullable=False)
155 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False)
156 name = Column(Unicode(64), nullable=False)
157
158 class LocationArea(TableBase):
159 __tablename__ = 'location_areas'
160 id = Column(Integer, primary_key=True, nullable=False)
161 location_id = Column(Integer, ForeignKey('locations.id'), nullable=False)
162 internal_id = Column(Integer, nullable=False)
163 name = Column(Unicode(64), nullable=True)
164
165 class LocationAreaEncounterRate(TableBase):
166 __tablename__ = 'location_area_encounter_rates'
167 location_area_id = Column(Integer, ForeignKey('location_areas.id'), primary_key=True, nullable=False, autoincrement=False)
168 encounter_type_id = Column(Integer, ForeignKey('encounter_types.id'), primary_key=True, nullable=False, autoincrement=False)
169 rate = Column(Integer, nullable=True)
170
171 class Machine(TableBase):
172 __tablename__ = 'machines'
173 machine_number = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
174 generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, nullable=False, autoincrement=False)
175 move_id = Column(Integer, ForeignKey('moves.id'), nullable=False)
176
177 class MoveDamageClass(TableBase):
178 __tablename__ = 'move_damage_classes'
179 id = Column(Integer, primary_key=True, nullable=False)
180 name = Column(Unicode(8), nullable=False)
181 description = Column(Unicode(64), nullable=False)
182
183 class MoveEffect(TableBase):
184 __tablename__ = 'move_effects'
185 id = Column(Integer, primary_key=True, nullable=False)
186 priority = Column(SmallInteger, nullable=False)
187 short_effect = Column(Unicode(256), nullable=False)
188 effect = Column(Unicode(5120), nullable=False)
189
190 class MoveFlag(TableBase):
191 __tablename__ = 'move_flags'
192 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
193 move_flag_type_id = Column(Integer, ForeignKey('move_flag_types.id'), primary_key=True, nullable=False, autoincrement=False)
194
195 class MoveFlagType(TableBase):
196 __tablename__ = 'move_flag_types'
197 id = Column(Integer, primary_key=True, nullable=False)
198 name = Column(Unicode(32), nullable=False)
199 description = Column(rst.RstTextColumn(128), nullable=False)
200
201 class MoveFlavorText(TableBase):
202 __tablename__ = 'move_flavor_text'
203 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
204 generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, nullable=False, autoincrement=False)
205 flavor_text = Column(Unicode(255), nullable=False)
206
207 class MoveName(TableBase):
208 __tablename__ = 'move_names'
209 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False)
210 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False)
211 name = Column(Unicode(16), nullable=False)
212
213 class MoveTarget(TableBase):
214 __tablename__ = 'move_targets'
215 id = Column(Integer, primary_key=True, nullable=False)
216 name = Column(Unicode(32), nullable=False)
217 description = Column(Unicode(128), nullable=False)
218
219 class Move(TableBase):
220 __tablename__ = 'moves'
221 __singlename__ = 'move'
222 id = Column(Integer, primary_key=True, nullable=False)
223 name = Column(Unicode(12), nullable=False)
224 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False)
225 type_id = Column(Integer, ForeignKey('types.id'), nullable=False)
226 power = Column(SmallInteger)
227 pp = Column(SmallInteger, nullable=False)
228 accuracy = Column(SmallInteger)
229 target_id = Column(Integer, ForeignKey('move_targets.id'), nullable=False)
230 damage_class_id = Column(Integer, ForeignKey('move_damage_classes.id'), nullable=False)
231 effect_id = Column(Integer, ForeignKey('move_effects.id'), nullable=False)
232 effect_chance = Column(Integer)
233 contest_type = Column(Unicode(8), nullable=False)
234 contest_effect_id = Column(Integer, ForeignKey('contest_effects.id'), nullable=True)
235 super_contest_effect_id = Column(Integer, ForeignKey('super_contest_effects.id'), nullable=False)
236
237 class Pokemon(TableBase):
238 """The core to this whole mess.
239
240 Note that I use both 'forme' and 'form' in both code and the database. I
241 only use 'forme' when specifically referring to Pokémon that have multiple
242 distinct species as forms—i.e., different stats or movesets. 'Form' is a
243 more general term referring to any variation within a species, including
244 purely cosmetic forms like Unown.
245 """
246 __tablename__ = 'pokemon'
247 __singlename__ = 'pokemon'
248 id = Column(Integer, primary_key=True, nullable=False)
249 name = Column(Unicode(20), nullable=False)
250 forme_name = Column(Unicode(16))
251 forme_base_pokemon_id = Column(Integer, ForeignKey('pokemon.id'))
252 generation_id = Column(Integer, ForeignKey('generations.id'))
253 evolution_chain_id = Column(Integer, ForeignKey('evolution_chains.id'))
254 evolution_parent_pokemon_id = Column(Integer, ForeignKey('pokemon.id'))
255 evolution_method_id = Column(Integer, ForeignKey('evolution_methods.id'))
256 evolution_parameter = Column(Unicode(32))
257 height = Column(Integer, nullable=False)
258 weight = Column(Integer, nullable=False)
259 species = Column(Unicode(16), nullable=False)
260 color = Column(Unicode(6), nullable=False)
261 pokemon_shape_id = Column(Integer, ForeignKey('pokemon_shapes.id'), nullable=False)
262 habitat = Column(Unicode(16), nullable=False)
263 gender_rate = Column(Integer, nullable=False)
264 capture_rate = Column(Integer, nullable=False)
265 base_experience = Column(Integer, nullable=False)
266 base_happiness = Column(Integer, nullable=False)
267 gen1_internal_id = Column(Integer)
268 is_baby = Column(Boolean, nullable=False)
269 has_gen4_fem_sprite = Column(Boolean, nullable=False)
270 has_gen4_fem_back_sprite = Column(Boolean, nullable=False)
271
272 ### Stuff to handle alternate Pokémon forms
273
274 @property
275 def national_id(self):
276 """Returns the National Pokédex number for this Pokémon. Use this
277 instead of the id directly; alternate formes may make the id incorrect.
278 """
279
280 if self.forme_base_pokemon_id:
281 return self.forme_base_pokemon_id
282 return self.id
283
284 @property
285 def full_name(self):
286 """Returns the name of this Pokémon, including its Forme, if any."""
287
288 if self.forme_name:
289 return "%s %s" % (self.forme_name.capitalize(), self.name)
290 return self.name
291
292 @property
293 def normal_form(self):
294 """Returns the normal form for this Pokémon; i.e., this will return
295 regular Deoxys when called on any Deoxys form.
296 """
297
298 if self.forme_base_pokemon:
299 return self.forme_base_pokemon
300
301 return self
302
303 class PokemonAbility(TableBase):
304 __tablename__ = 'pokemon_abilities'
305 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
306 ability_id = Column(Integer, ForeignKey('abilities.id'), nullable=False)
307 slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
308
309 class PokemonDexNumber(TableBase):
310 __tablename__ = 'pokemon_dex_numbers'
311 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
312 generation_id = Column(Integer, ForeignKey('generations.id'), primary_key=True, nullable=False, autoincrement=False)
313 pokedex_number = Column(Integer, nullable=False)
314
315 class PokemonEggGroup(TableBase):
316 __tablename__ = 'pokemon_egg_groups'
317 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
318 egg_group_id = Column(Integer, ForeignKey('egg_groups.id'), primary_key=True, nullable=False, autoincrement=False)
319
320 class PokemonFlavorText(TableBase):
321 __tablename__ = 'pokemon_flavor_text'
322 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
323 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False)
324 flavor_text = Column(Unicode(255), nullable=False)
325
326 class PokemonFormGroup(TableBase):
327 __tablename__ = 'pokemon_form_groups'
328 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
329 description = Column(Unicode(512), nullable=False)
330
331 class PokemonFormSprite(TableBase):
332 __tablename__ = 'pokemon_form_sprites'
333 id = Column(Integer, primary_key=True, nullable=False)
334 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
335 name = Column(Unicode(16), nullable=True)
336
337 class PokemonItem(TableBase):
338 __tablename__ = 'pokemon_items'
339 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
340 version_id = Column(Integer, ForeignKey('versions.id'), primary_key=True, nullable=False, autoincrement=False)
341 item_id = Column(Integer, ForeignKey('items.id'), primary_key=True, nullable=False, autoincrement=False)
342 rarity = Column(Integer, nullable=False)
343
344 class PokemonMove(TableBase):
345 __tablename__ = 'pokemon_moves'
346 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
347 version_group_id = Column(Integer, ForeignKey('version_groups.id'), primary_key=True, nullable=False, autoincrement=False)
348 move_id = Column(Integer, ForeignKey('moves.id'), primary_key=True, nullable=False, autoincrement=False, index=True)
349 pokemon_move_method_id = Column(Integer, ForeignKey('pokemon_move_methods.id'), primary_key=True, nullable=False, autoincrement=False)
350 level = Column(Integer, primary_key=True, nullable=True, autoincrement=False)
351 order = Column(Integer, nullable=True)
352
353 class PokemonMoveMethod(TableBase):
354 __tablename__ = 'pokemon_move_methods'
355 id = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
356 name = Column(Unicode(64), nullable=False)
357 description = Column(Unicode(255), nullable=False)
358
359 class PokemonName(TableBase):
360 __tablename__ = 'pokemon_names'
361 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
362 language_id = Column(Integer, ForeignKey('languages.id'), primary_key=True, nullable=False, autoincrement=False)
363 name = Column(Unicode(16), nullable=False)
364
365 class PokemonShape(TableBase):
366 __tablename__ = 'pokemon_shapes'
367 id = Column(Integer, primary_key=True, nullable=False)
368 name = Column(Unicode(24), nullable=False)
369 awesome_name = Column(Unicode(16), nullable=False)
370
371 class PokemonStat(TableBase):
372 __tablename__ = 'pokemon_stats'
373 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
374 stat_id = Column(Integer, ForeignKey('stats.id'), primary_key=True, nullable=False, autoincrement=False)
375 base_stat = Column(Integer, nullable=False)
376 effort = Column(Integer, nullable=False)
377
378 class PokemonType(TableBase):
379 __tablename__ = 'pokemon_types'
380 pokemon_id = Column(Integer, ForeignKey('pokemon.id'), primary_key=True, nullable=False, autoincrement=False)
381 type_id = Column(Integer, ForeignKey('types.id'), nullable=False)
382 slot = Column(Integer, primary_key=True, nullable=False, autoincrement=False)
383
384 class Stat(TableBase):
385 __tablename__ = 'stats'
386 id = Column(Integer, primary_key=True, nullable=False)
387 name = Column(Unicode(16), nullable=False)
388
389 class SuperContestEffect(TableBase):
390 __tablename__ = 'super_contest_effects'
391 id = Column(Integer, primary_key=True, nullable=False)
392 appeal = Column(SmallInteger, nullable=False)
393 flavor_text = Column(Unicode(64), nullable=False)
394
395 class TypeEfficacy(TableBase):
396 __tablename__ = 'type_efficacy'
397 damage_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False)
398 target_type_id = Column(Integer, ForeignKey('types.id'), primary_key=True, nullable=False, autoincrement=False)
399 damage_factor = Column(Integer, nullable=False)
400
401 class Type(TableBase):
402 __tablename__ = 'types'
403 __singlename__ = 'type'
404 id = Column(Integer, primary_key=True, nullable=False)
405 name = Column(Unicode(8), nullable=False)
406 abbreviation = Column(Unicode(3), nullable=False)
407
408 class VersionGroup(TableBase):
409 __tablename__ = 'version_groups'
410 id = Column(Integer, primary_key=True, nullable=False)
411 generation_id = Column(Integer, ForeignKey('generations.id'), nullable=False)
412
413 class Version(TableBase):
414 __tablename__ = 'versions'
415 id = Column(Integer, primary_key=True, nullable=False)
416 version_group_id = Column(Integer, ForeignKey('version_groups.id'), nullable=False)
417 name = Column(Unicode(32), nullable=False)
418
419
420 ### Relations down here, to avoid ordering problems
421 Encounter.pokemon = relation(Pokemon, backref='encounters')
422 Encounter.version = relation(Version, backref='encounters')
423 Encounter.location_area = relation(LocationArea, backref='encounters')
424 Encounter.slot = relation(EncounterTypeSlot, backref='encounters')
425 Encounter.condition = relation(EncounterCondition, backref='encounters')
426
427 EncounterCondition.group = relation(EncounterConditionGroup,
428 backref='conditions')
429
430 EncounterTypeSlot.type = relation(EncounterType, backref='slots')
431
432 EvolutionChain.growth_rate = relation(GrowthRate, backref='evolution_chains')
433
434 Generation.versions = relation(Version, secondary=VersionGroup.__table__)
435
436 LocationArea.location = relation(Location, backref='areas')
437
438 Machine.generation = relation(Generation)
439
440 Move.contest_effect = relation(ContestEffect, backref='moves')
441 Move.damage_class = relation(MoveDamageClass, backref='moves')
442 Move.flags = association_proxy('move_flags', 'flag')
443 Move.flavor_text = relation(MoveFlavorText, order_by=MoveFlavorText.generation_id, backref='move')
444 Move.foreign_names = relation(MoveName, backref='pokemon')
445 Move.generation = relation(Generation, backref='moves')
446 Move.machines = relation(Machine, backref='move')
447 Move.move_effect = relation(MoveEffect, backref='moves')
448 Move.move_flags = relation(MoveFlag, backref='move')
449 Move.super_contest_effect = relation(SuperContestEffect, backref='moves')
450 Move.target = relation(MoveTarget, backref='moves')
451 Move.type = relation(Type, backref='moves')
452
453 Move.effect = rst.MoveEffectProperty('effect')
454 Move.priority = association_proxy('move_effect', 'priority')
455 Move.short_effect = rst.MoveEffectProperty('short_effect')
456
457 MoveFlag.flag = relation(MoveFlagType)
458
459 MoveFlavorText.generation = relation(Generation)
460
461 MoveName.language = relation(Language)
462
463 Pokemon.abilities = relation(Ability, secondary=PokemonAbility.__table__,
464 order_by=PokemonAbility.slot,
465 backref='pokemon')
466 Pokemon.formes = relation(Pokemon, primaryjoin=Pokemon.id==Pokemon.forme_base_pokemon_id,
467 backref=backref('forme_base_pokemon',
468 remote_side=[Pokemon.id]))
469 Pokemon.dex_numbers = relation(PokemonDexNumber, backref='pokemon')
470 Pokemon.egg_groups = relation(EggGroup, secondary=PokemonEggGroup.__table__,
471 order_by=PokemonEggGroup.egg_group_id,
472 backref='pokemon')
473 Pokemon.evolution_chain = relation(EvolutionChain, backref='pokemon')
474 Pokemon.evolution_method = relation(EvolutionMethod)
475 Pokemon.evolution_children = relation(Pokemon, primaryjoin=Pokemon.id==Pokemon.evolution_parent_pokemon_id,
476 backref=backref('evolution_parent',
477 remote_side=[Pokemon.id]))
478 Pokemon.flavor_text = relation(PokemonFlavorText, order_by=PokemonFlavorText.pokemon_id, backref='pokemon')
479 Pokemon.foreign_names = relation(PokemonName, backref='pokemon')
480 Pokemon.items = relation(PokemonItem)
481 Pokemon.generation = relation(Generation, backref='pokemon')
482 Pokemon.shape = relation(PokemonShape, backref='pokemon')
483 Pokemon.stats = relation(PokemonStat, backref='pokemon')
484 Pokemon.types = relation(Type, secondary=PokemonType.__table__)
485
486 PokemonDexNumber.generation = relation(Generation)
487
488 PokemonFlavorText.version = relation(Version)
489
490 PokemonItem.item = relation(Item, backref='pokemon')
491 PokemonItem.version = relation(Version)
492
493 PokemonFormGroup.pokemon = relation(Pokemon, backref=backref('form_group',
494 uselist=False))
495 PokemonFormSprite.pokemon = relation(Pokemon, backref='form_sprites')
496
497 PokemonMove.pokemon = relation(Pokemon, backref='pokemon_moves')
498 PokemonMove.version_group = relation(VersionGroup)
499 PokemonMove.move = relation(Move, backref='pokemon_moves')
500 PokemonMove.method = relation(PokemonMoveMethod)
501
502 PokemonName.language = relation(Language)
503
504 PokemonStat.stat = relation(Stat)
505
506 Type.damage_efficacies = relation(TypeEfficacy,
507 primaryjoin=Type.id
508 ==TypeEfficacy.damage_type_id,
509 backref='damage_type')
510 Type.target_efficacies = relation(TypeEfficacy,
511 primaryjoin=Type.id
512 ==TypeEfficacy.target_type_id,
513 backref='target_type')
514
515 Version.version_group = relation(VersionGroup, backref='versions')
516 Version.generation = association_proxy('version_group', 'generation')
517
518 VersionGroup.generation = relation(Generation, backref='version_groups')