Optimisations (#174)

* removed all the things causing slow times on data

* fixup look sharp

* use ujson

* bep
This commit is contained in:
Paul Hallett 2016-04-30 13:02:27 +01:00
parent 5b94cff6c8
commit 422d98fff2
7 changed files with 16 additions and 244 deletions

View file

@ -95,6 +95,7 @@ DATABASES = {
'PASSWORD': 'pokeapi',
'HOST': 'localhost',
'PORT': '',
'CONN_MAX_AGE': 30
}
}
@ -103,10 +104,6 @@ CACHES = {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'TIMEOUT': 30
},
'resources': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'TIMEOUT': 360
}
}
SECRET_KEY = os.environ.get(
@ -148,10 +145,10 @@ CORS_URLS_REGEX = r'^/api/.*$'
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
'drf_ujson.renderers.UJSONRenderer',
),
'DEFAULT_PARSER_CLASSES': (
'rest_framework.parsers.JSONParser',
'drf_ujson.renderers.UJSONRenderer',
),
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',

View file

@ -10,224 +10,10 @@ from hits.models import ResourceView
import stripe
from pokemon_v2.models import * # NOQA
def _total_site_data():
"""
Compute the total count of objects on the site
Using count() is drastically cheaper than len(objects.all())
"""
# v2 Sorry for the brute force. Theres probably a better way to do this.
data = dict(
abilities=Ability.objects.count(),
abilitie_names=AbilityName.objects.count(),
abilitie_effect_texts=AbilityEffectText.objects.count(),
abilities_flavor_texts=AbilityFlavorText.objects.count(),
abilities_changes=AbilityChange.objects.count(),
abilities_change_effect_texts=AbilityChangeEffectText.objects.count(),
berries=Berry.objects.count(),
berry_flavors=BerryFlavor.objects.count(),
berry_firmnesses=BerryFirmness.objects.count(),
berry_firmness_names=BerryFirmnessName.objects.count(),
characteristics=Characteristic.objects.count(),
characteristic_descriptions=CharacteristicDescription.objects.count(),
contest_combos=ContestCombo.objects.count(),
contest_types=ContestType.objects.count(),
contest_type_names=ContestTypeName.objects.count(),
contest_effects=ContestEffect.objects.count(),
contest_effect_texts=ContestEffectEffectText.objects.count(),
contest_effect_flavor_texts=ContestEffectFlavorText.objects.count(),
egg_groups=EggGroup.objects.count(),
egg_group_names=EggGroupName.objects.count(),
encounter_methods=EncounterMethod.objects.count(),
encounter_method_names=EncounterMethodName.objects.count(),
encounter_conditions=EncounterCondition.objects.count(),
encounter_condition_names=EncounterConditionName.objects.count(),
encounter_condition_values=EncounterConditionValue.objects.count(),
encounter_condition_value_names=EncounterConditionValueName.objects.count(),
encounter_condition_value_maps=EncounterConditionValueMap.objects.count(),
encounter_slots=EncounterSlot.objects.count(),
encounters=Encounter.objects.count(),
evolution_chains=EvolutionChain.objects.count(),
evolution_triggers=EvolutionTrigger.objects.count(),
evolution_trigger_names=EvolutionTriggerName.objects.count(),
experiences=Experience.objects.count(),
generations=Generation.objects.count(),
generation_names=GenerationName.objects.count(),
genders=Gender.objects.count(),
growth_rates=GrowthRate.objects.count(),
growth_rate_descriptions=GrowthRateDescription.objects.count(),
items=Item.objects.count(),
item_names=ItemName.objects.count(),
item_effect_texts=ItemEffectText.objects.count(),
item_categories=ItemCategory.objects.count(),
item_category_names=ItemCategoryName.objects.count(),
item_attributes=ItemAttribute.objects.count(),
item_attribute_maps=ItemAttributeMap.objects.count(),
item_attribute_descriptions=ItemAttributeDescription.objects.count(),
item_flavor_texts=ItemFlavorText.objects.count(),
item_fling_effects=ItemFlingEffect.objects.count(),
item_fling_effect_effect_texts=ItemFlingEffectEffectText.objects.count(),
item_pockets=ItemPocket.objects.count(),
item_pocket_names=ItemPocketName.objects.count(),
item_game_indexes=ItemGameIndex.objects.count(),
languages=Language.objects.count(),
language_names=LanguageName.objects.count(),
locations=Location.objects.count(),
location_game_indexes=LocationGameIndex.objects.count(),
location_names=LocationName.objects.count(),
location_areas=LocationArea.objects.count(),
location_area_names=LocationAreaName.objects.count(),
location_area_encounter_rates=LocationAreaEncounterRate.objects.count(),
machines=Machine.objects.count(),
moves=Move.objects.count(),
move_names=MoveName.objects.count(),
move_changes=MoveChange.objects.count(),
move_flavor_text=MoveFlavorText.objects.count(),
move_effects=MoveEffect.objects.count(),
move_effect_changes=MoveEffectChange.objects.count(),
move_effect_change_effect_texts=MoveEffectChangeEffectText.objects.count(),
move_effect_effect_texts=MoveEffectEffectText.objects.count(),
move_attributes=MoveAttribute.objects.count(),
move_attribute_names=MoveAttributeName.objects.count(),
move_attribute_maps=MoveAttributeMap.objects.count(),
move_attribute_descriptions=MoveAttributeDescription.objects.count(),
move_metas=MoveMeta.objects.count(),
move_ailments=MoveMetaAilment.objects.count(),
move_ailment_names=MoveMetaAilmentName.objects.count(),
move_battle_styles=MoveBattleStyle.objects.count(),
move_battle_style_names=MoveBattleStyleName.objects.count(),
move_categories=MoveMetaCategory.objects.count(),
move_damage_classes=MoveDamageClass.objects.count(),
move_damage_class_descriptions=MoveDamageClassDescription.objects.count(),
move_learn_methods=MoveLearnMethod.objects.count(),
move_learn_method_names=MoveLearnMethodName.objects.count(),
move_targets=MoveTarget.objects.count(),
move_target_descriptions=MoveTargetDescription.objects.count(),
move_state_changes=MoveMetaStatChange.objects.count(),
natures=Nature.objects.count(),
nature_names=NatureName.objects.count(),
nature_pokeathlon_stats=NaturePokeathlonStat.objects.count(),
nature_battle_style_preference=NatureBattleStylePreference.objects.count(),
pal_park_areas=PalParkArea.objects.count(),
pal_park_area_names=PalParkAreaName.objects.count(),
pal_parks=PalPark.objects.count(),
pokeathlon_stat_names=PokeathlonStatName.objects.count(),
pokeathlon_stats=PokeathlonStat.objects.count(),
pokedexes=PokedexVersionGroup.objects.count(),
pokedex_descriptions=PokedexDescription.objects.count(),
pokedex_version_groups=PokedexVersionGroup.objects.count(),
pokemon=Pokemon.objects.count(),
pokemon_abilities=PokemonAbility.objects.count(),
pokemon_colors=PokemonColor.objects.count(),
pokemon_names=PokemonColorName.objects.count(),
pokemon_dex_numbers=PokemonDexNumber.objects.count(),
pokemon_egg_groups=PokemonEggGroup.objects.count(),
pokemon_evolutions=PokemonEvolution.objects.count(),
pokemon_forms=PokemonForm.objects.count(),
pokemon_form_names=PokemonFormName.objects.count(),
pokemon_form_generations=PokemonFormGeneration.objects.count(),
pokemon_game_indices=PokemonGameIndex.objects.count(),
pokemon_habitats=PokemonHabitat.objects.count(),
pokemon_habitat_names=PokemonHabitatName.objects.count(),
pokemon_items=PokemonItem.objects.count(),
pokemon_moves=PokemonMove.objects.count(),
pokemon_shapes=PokemonShape.objects.count(),
pokemon_shape_names=PokemonShapeName.objects.count(),
pokemon_species=PokemonSpecies.objects.count(),
pokemon_species_names=PokemonSpeciesName.objects.count(),
pokemon_descriptions=PokemonSpeciesDescription.objects.count(),
pokemon_flavor_texts=PokemonSpeciesFlavorText.objects.count(),
pokemon_stat=PokemonStat.objects.count(),
pokemon_type=PokemonType.objects.count(),
regions=Region.objects.count(),
region_names=RegionName.objects.count(),
stats=Stat.objects.count(),
stat_names=StatName.objects.count(),
super_contest_effects=SuperContestEffect.objects.count(),
super_contest_combos=SuperContestCombo.objects.count(),
super_contest_effect_flavor_texts=SuperContestEffectFlavorText.objects.count(),
types=Type.objects.count(),
type_names=TypeName.objects.count(),
type_game_indices=TypeGameIndex.objects.count(),
type_efficacy=TypeEfficacy.objects.count(),
versions=Version.objects.count(),
version_names=VersionName.objects.count(),
version_groups=VersionGroup.objects.count(),
version_group_move_learn_methods=VersionGroupMoveLearnMethod.objects.count(),
version_group_regions=VersionGroupRegion.objects.count(),
)
lines = 0
for i in data.iteritems():
lines += i[1]
resources = 0
resources += data['abilities']
resources += data['berries']
resources += data['berry_flavors']
resources += data['berry_firmnesses']
resources += data['characteristics']
resources += data['contest_types']
resources += data['contest_effects']
resources += data['egg_groups']
resources += data['encounter_methods']
resources += data['encounter_conditions']
resources += data['encounter_condition_values']
resources += data['evolution_chains']
resources += data['evolution_triggers']
resources += data['generations']
resources += data['genders']
resources += data['growth_rates']
resources += data['items']
resources += data['item_attributes']
resources += data['item_categories']
resources += data['item_fling_effects']
resources += data['item_pockets']
resources += data['languages']
resources += data['locations']
resources += data['location_areas']
resources += data['moves']
resources += data['move_ailments']
resources += data['move_categories']
resources += data['move_battle_styles']
resources += data['move_damage_classes']
resources += data['move_learn_methods']
resources += data['move_targets']
resources += data['natures']
resources += data['pal_park_areas']
resources += data['pokedexes']
resources += data['pokemon']
resources += data['pokemon_colors']
resources += data['pokemon_forms']
resources += data['pokemon_habitats']
resources += data['pokemon_shapes']
resources += data['pokemon_species']
resources += data['pokeathlon_stats']
resources += data['regions']
resources += data['stats']
resources += data['super_contest_effects']
resources += data['types']
resources += data['versions']
resources += data['version_groups']
data['total_lines'] = lines
data['total_resources'] = resources
return data
def about(request):
site_data = _total_site_data()
total_views = ResourceView.objects.total_count()
total_v1_views = ResourceView.objects.total_count(version=1)
total_v2_views = ResourceView.objects.total_count(version=2)
average_day = int(round(total_views / ResourceView.objects.count()))
@ -235,10 +21,7 @@ def about(request):
'pages/about.html',
{
'total': total_views,
'total_v1': total_v1_views,
'total_v2': total_v2_views,
'average_day': average_day,
'site_data': site_data,
},
context_instance=RequestContext(request)
)

View file

@ -3,7 +3,7 @@ from django.db import models
from datetime import date
class ViewManager(models.Manager):
class ResourceViewManager(models.Manager):
def increment_view_count(self, version):
@ -14,30 +14,21 @@ class ViewManager(models.Manager):
view.count = view.count + 1
print view
view.save()
def total_count(self, version=0):
if version:
objects = ResourceView.objects.filter(version=version)
else:
objects = ResourceView.objects.all()
all_hits = ResourceView.objects.all().values_list('count', flat=True)
t = 0
for v in objects:
t += v.count
return t
return sum(all_hits)
class ResourceView(models.Model):
objects = ViewManager()
objects = ResourceViewManager()
def __unicode__(self):
return str(self.date) + ' - ' + str(self.count)
return '{} - {}'.format(str(self.date), str(self.count))
count = models.IntegerField(max_length=1000, default=0)
version = models.IntegerField(max_length=1, default=1)

View file

@ -9,7 +9,7 @@ from hits.models import ResourceView
###########################
# BEHAVOIR ABSTRACTIONS #
# BEHAVIOR ABSTRACTIONS #
###########################
class ListOrDetailSerialRelation():

View file

@ -2974,7 +2974,7 @@ class PokedexDetailSerializer(serializers.ModelSerializer):
def get_pokedex_entries(self, obj):
results = PokemonDexNumber.objects.order_by('pokedex_number').filter(pokedex=obj)
results = PokemonDexNumber.objects.filter(pokedex=obj).order_by('pokedex_number')
serializer = PokemonDexNumberSerializer(results, many=True, context=self.context)
data = serializer.data

View file

@ -10,6 +10,7 @@ django-imagekit==3.2.4
django-tastypie==0.12.1
django-markdown-deux==1.0.5
djangorestframework>=3.1.0
drf-ujson==1.2.0
gunicorn==0.17.0
markdown2==2.3.0
mimeparse==0.1.3

View file

@ -29,7 +29,7 @@
<section id="about">
<div class="header">
<h1>The RESTful Pokémon Data API</h1>
</div>
@ -37,7 +37,7 @@
<div class="container">
<div class="row pad_top">
<div class="col-md-10 center-block">
<p class="lead">
@ -45,7 +45,7 @@
</p>
<div class="well">
<p>
This website provides a RESTful API interface to <b>{{ site_data.total_resources|intcomma }}</b> highly detailed objects built from <b>{{ site_data.total_lines|intcomma }}</b> lines of data
This website provides a RESTful API interface to highly detailed objects built from thousands of lines of data
related to <a href="https://en.wikipedia.org/wiki/Pokemon">Pokémon</a>. We specifically cover the video game franchise, though we'd like to cover the card game too. Using this website you can consume information on Pokémon, their moves, abilities, types, egg groups and much much more.
</p>
</div>
@ -57,7 +57,7 @@
This is probably worth clearing up very quickly for those who don't know.<br />
An API (Application Programming Interface) is a set of interfaces (in this case, url links)
that are publicly available, that allow developers to interact with an application.<br />
In this instance; the application is a database of <b>{{ site_data.total_items|intcomma }}</b> pokemon-related objects.
In this instance; the application is a database of thousands oc pokemon-related objects.
</p>
</div>
<p class="lead">
@ -126,7 +126,7 @@
<div class="well">
<p>
Pokémon V1 was created by <a href="http://github.com/phalt">Paul Hallett</a> as a weekend project but it quickly became more than a weekend's
worth of work. In <a href="http://phalt.co/if-you-have-data-they-will-consume-it/" target="none">December of 2014</a> Paul deprecated V1 in favor of working on V2.
worth of work. In <a href="http://phalt.co/if-you-have-data-they-will-consume-it/" target="none">December of 2014</a> Paul deprecated V1 in favor of working on V2.
This is where <a href="http://github.com/zaneadix">Zane Adickes</a> jumped in. Zane thought the original project was a fantastic idea and wanted to help it grow.
With direction from Paul, Zane created the V2 api using an exact mirror of <a href="http://github.com/eevee">Veekun's</a> data related to the main series of games.
</p>