Beispiel #1
0
def monster_detail_mobile(request, rulebook_slug, rulebook_id, monster_slug, monster_id):
    monster = get_object_or_404(
        Monster.objects.select_related('rulebook', 'rulebook__dnd_edition', 'size',
                                       'type', ),
        pk=monster_id)

    if (monster.slug != monster_slug or
                unicode(monster.rulebook.id) != rulebook_id or
                monster.rulebook.slug != rulebook_slug):
        return permanent_redirect_object_mobile(request, monster)

    assert isinstance(monster, Monster)

    monster_speeds = monster.monsterspeed_set.select_related('type', ).all()
    monster_subtypes = monster.subtypes.all()
    monster_skills = monster.skills.select_related('skill').all()
    monster_feats = monster.feats.select_related('feat', 'feat__rulebook').all()

    return render_to_response('dnd/mobile/monsters/monster_detail.html',
                              {
                                  'monster': monster,
                                  'rulebook': monster.rulebook,
                                  'request': request,
                                  'monster_speeds': monster_speeds,
                                  'monster_subtypes': monster_subtypes,
                                  'monster_skills': monster_skills,
                                  'monster_feats': monster_feats,
                                  'i_like_it_url': request.build_absolute_uri(),
                                  'inaccurate_url': request.build_absolute_uri(),
                                  'display_3e_warning': is_3e_edition(monster.rulebook.dnd_edition),
                              }, context_instance=RequestContext(request), )
Beispiel #2
0
def item_detail_mobile(request, rulebook_slug, rulebook_id, item_slug,
                       item_id):
    item = get_object_or_404(Item.objects.select_related(
        'rulebook',
        'rulebook__dnd_edition',
        'body_slot',
        'aura',
        'spellschool_set',
        'activation',
        'required_feats',
        'required_spells',
        'property',
        'synergy_prerequisite',
    ),
                             pk=item_id)
    assert isinstance(item, Item)

    if (item.slug != item_slug or unicode(item.rulebook.id) != rulebook_id
            or item.rulebook.slug != rulebook_slug):
        return permanent_redirect_object_mobile(request, item)

    required_feats = item.required_feats.select_related('rulebook').all()
    required_spells = item.required_spells.select_related('rulebook').all()

    cost_to_create = item.cost_to_create
    # calculate CTC
    if not cost_to_create:
        if item.price_gp and not item.price_bonus:
            cost_to_create = "%s gp, %s XP, %d day(s)" % (int_with_commas(
                ceil(item.price_gp /
                     2.0)), int_with_commas(ceil(
                         item.price_gp / 25.0)), ceil(item.price_gp / 1000.0))
        elif not item.price_gp and item.price_bonus:
            cost_to_create = "Varies"

    return render_to_response(
        'dnd/mobile/items/item_detail.html',
        {
            'item': item,
            'aura_schools': item.aura_schools.all(),
            'required_feats': required_feats,
            'required_spells': required_spells,
            'cost_to_create': cost_to_create,
            'rulebook': item.rulebook,
            'request': request,
            # enum
            'ItemType': Item.ItemType,
            'i_like_it_url': request.build_absolute_uri(),
            'inaccurate_url': request.build_absolute_uri(),
            'display_3e_warning': is_3e_edition(item.rulebook.dnd_edition),
        },
        context_instance=RequestContext(request),
    )
Beispiel #3
0
def spell_detail_mobile(request, rulebook_slug, rulebook_id, spell_slug,
                        spell_id):
    spell = get_object_or_404(Spell.objects.select_related(
        'rulebook', 'rulebook__dnd_edition', 'school', 'sub_school',
        'class_levels'),
                              pk=spell_id)

    if (spell.slug != spell_slug or unicode(spell.rulebook.id) != rulebook_id
            or spell.rulebook.slug != rulebook_slug):
        return permanent_redirect_object_mobile(request, spell)

    spell_class_level_set = spell.spellclasslevel_set.select_related(
        'rulebook',
        'character_class',
    ).all()
    spell_domain_level_set = spell.spelldomainlevel_set.select_related(
        'rulebook',
        'domain',
    ).all()

    # related spells
    related_spells = Spell.objects.filter(slug=spell.slug).exclude(
        rulebook__id=spell.rulebook.id).select_related('rulebook').all()

    # corrupt component -- will be linked to corrupt rule
    if spell.corrupt_component:
        corrupt_rule = Rule.objects.filter(slug='corrupt-magic').all()[0]
    else:
        corrupt_rule = None

    return render_to_response(
        'dnd/mobile/spells/spell_detail.html',
        {
            'spell': spell,
            'spellclasslevel_set': spell_class_level_set,
            'spelldomainlevel_set': spell_domain_level_set,
            'corrupt_rule': corrupt_rule,
            'rulebook': spell.rulebook,
            'request': request,
            'i_like_it_url': request.build_absolute_uri(),
            'inaccurate_url': request.build_absolute_uri(),
            'display_3e_warning': is_3e_edition(spell.rulebook.dnd_edition),
            'related_spells': related_spells,
        },
        context_instance=RequestContext(request),
    )
Beispiel #4
0
def rulebook_detail_mobile(request, edition_slug, edition_id, rulebook_slug,
                           rulebook_id):
    rulebook = get_object_or_404(Rulebook, id=rulebook_id)
    if (rulebook.slug != rulebook_slug or
                unicode(rulebook.dnd_edition.id) != edition_id or
                rulebook.dnd_edition.slug != edition_slug):
        return permanent_redirect_object_mobile(request, rulebook)

    return render_to_response('dnd/mobile/rulebooks/rulebook_detail.html',
                              {
                                  'rulebook': rulebook,
                                  'dnd_edition': rulebook.dnd_edition,
                                  'request': request,
                                  'i_like_it_url': request.build_absolute_uri(),
                                  'inaccurate_url': request.build_absolute_uri(),
                                  'display_3e_warning': is_3e_edition(rulebook.dnd_edition),
                              }, context_instance=RequestContext(request), )
Beispiel #5
0
def edition_detail_mobile(request, edition_slug, edition_id):
    dnd_edition = get_object_or_404(DndEdition, id=edition_id)
    if dnd_edition.slug != edition_slug:
        return permanent_redirect_object_mobile(request, dnd_edition)

    rulebook_list = dnd_edition.rulebook_set.select_related('dnd_edition').all()

    paginator = DndMobilePaginator(rulebook_list, request)

    return render_to_response('dnd/mobile/rulebooks/edition_detail.html',
                              {
                                  'dnd_edition': dnd_edition,
                                  'request': request,
                                  'rulebook_list': paginator.items(),
                                  'paginator': paginator,
                                  'i_like_it_url': request.build_absolute_uri(),
                                  'inaccurate_url': request.build_absolute_uri(),
                                  'display_3e_warning': is_3e_edition(dnd_edition),
                              }, context_instance=RequestContext(request), )
Beispiel #6
0
def spell_detail_mobile(request, rulebook_slug, rulebook_id, spell_slug, spell_id):
    spell = get_object_or_404(Spell.objects.select_related(
        'rulebook', 'rulebook__dnd_edition', 'school', 'sub_school',
        'class_levels'
    ), pk=spell_id)

    if (spell.slug != spell_slug or
                unicode(spell.rulebook.id) != rulebook_id or
                spell.rulebook.slug != rulebook_slug):
        return permanent_redirect_object_mobile(request, spell)

    spell_class_level_set = spell.spellclasslevel_set.select_related(
        'rulebook', 'character_class',
    ).all()
    spell_domain_level_set = spell.spelldomainlevel_set.select_related(
        'rulebook', 'domain',
    ).all()

    # related spells
    related_spells = Spell.objects.filter(slug=spell.slug).exclude(rulebook__id=spell.rulebook.id).select_related(
        'rulebook').all()

    # corrupt component -- will be linked to corrupt rule
    if spell.corrupt_component:
        corrupt_rule = Rule.objects.filter(slug='corrupt-magic').all()[0]
    else:
        corrupt_rule = None

    return render_to_response('dnd/mobile/spells/spell_detail.html',
                              {
                                  'spell': spell,
                                  'spellclasslevel_set': spell_class_level_set,
                                  'spelldomainlevel_set': spell_domain_level_set,
                                  'corrupt_rule': corrupt_rule,
                                  'rulebook': spell.rulebook,
                                  'request': request,
                                  'i_like_it_url': request.build_absolute_uri(),
                                  'inaccurate_url': request.build_absolute_uri(),
                                  'display_3e_warning': is_3e_edition(spell.rulebook.dnd_edition),
                                  'related_spells': related_spells,
                              },
                              context_instance=RequestContext(request), )
Beispiel #7
0
def rulebook_detail_mobile(request, edition_slug, edition_id, rulebook_slug,
                           rulebook_id):
    rulebook = get_object_or_404(Rulebook, id=rulebook_id)
    if (rulebook.slug != rulebook_slug
            or unicode(rulebook.dnd_edition.id) != edition_id
            or rulebook.dnd_edition.slug != edition_slug):
        return permanent_redirect_object_mobile(request, rulebook)

    return render_to_response(
        'dnd/mobile/rulebooks/rulebook_detail.html',
        {
            'rulebook': rulebook,
            'dnd_edition': rulebook.dnd_edition,
            'request': request,
            'i_like_it_url': request.build_absolute_uri(),
            'inaccurate_url': request.build_absolute_uri(),
            'display_3e_warning': is_3e_edition(rulebook.dnd_edition),
        },
        context_instance=RequestContext(request),
    )
Beispiel #8
0
def item_detail_mobile(request, rulebook_slug, rulebook_id, item_slug, item_id):
    item = get_object_or_404(Item.objects.select_related(
        'rulebook', 'rulebook__dnd_edition', 'body_slot', 'aura', 'spellschool_set',
        'activation', 'required_feats', 'required_spells', 'property', 'synergy_prerequisite',
    ), pk=item_id)
    assert isinstance(item, Item)

    if (item.slug != item_slug or
                unicode(item.rulebook.id) != rulebook_id or
                item.rulebook.slug != rulebook_slug):
        return permanent_redirect_object_mobile(request, item)

    required_feats = item.required_feats.select_related('rulebook').all()
    required_spells = item.required_spells.select_related('rulebook').all()

    cost_to_create = item.cost_to_create
    # calculate CTC
    if not cost_to_create:
        if item.price_gp and not item.price_bonus:
            cost_to_create = "%s gp, %s XP, %d day(s)" % (
                int_with_commas(ceil(item.price_gp / 2.0)), int_with_commas(ceil(item.price_gp / 25.0)),
                ceil(item.price_gp / 1000.0))
        elif not item.price_gp and item.price_bonus:
            cost_to_create = "Varies"

    return render_to_response('dnd/mobile/items/item_detail.html',
                              {
                                  'item': item,
                                  'aura_schools': item.aura_schools.all(),
                                  'required_feats': required_feats,
                                  'required_spells': required_spells,
                                  'cost_to_create': cost_to_create,
                                  'rulebook': item.rulebook,
                                  'request': request,
                                  # enum
                                  'ItemType': Item.ItemType,
                                  'i_like_it_url': request.build_absolute_uri(),
                                  'inaccurate_url': request.build_absolute_uri(),
                                  'display_3e_warning': is_3e_edition(item.rulebook.dnd_edition),
                              },
                              context_instance=RequestContext(request), )
Beispiel #9
0
def feat_detail_mobile(request, rulebook_slug, rulebook_id, feat_slug,
                       feat_id):
    feat = get_object_or_404(Feat.objects.select_related(
        'rulebook', 'rulebook__dnd_edition'),
                             pk=feat_id)
    if (feat.slug != feat_slug or unicode(feat.rulebook.id) != rulebook_id
            or feat.rulebook.slug != rulebook_slug):
        return permanent_redirect_object_mobile(request, feat)

    feat_category_list = feat.feat_categories.select_related().all()
    required_feats = feat.required_feats.select_related(
        'required_feat', 'required_feat__rulebook').all()
    required_by_feats = feat.required_by_feats.select_related(
        'source_feat', 'source_feat__rulebook').all()
    required_skills = feat.required_skills.select_related('skill').all()
    special_prerequisities = feat.featspecialfeatprerequisite_set.select_related(
        'special_feat_prerequisite').all()
    # related feats
    related_feats = Feat.objects.filter(
        slug=feat.slug).exclude(rulebook__id=feat.rulebook.id).select_related(
            'rulebook', 'rulebook__dnd_edition').all()

    return render_to_response(
        'dnd/mobile/feats/feat_detail.html',
        {
            'feat': feat,
            'rulebook': feat.rulebook,
            'feat_category_list': feat_category_list,
            'required_feats': required_feats,
            'required_by_feats': required_by_feats,
            'required_skills': required_skills,
            'special_prerequisities': special_prerequisities,
            'request': request,
            'i_like_it_url': request.build_absolute_uri(),
            'inaccurate_url': request.build_absolute_uri(),
            'display_3e_warning': is_3e_edition(feat.rulebook.dnd_edition),
            'related_feats': related_feats,
        },
        context_instance=RequestContext(request),
    )
Beispiel #10
0
def monster_detail_mobile(request, rulebook_slug, rulebook_id, monster_slug,
                          monster_id):
    monster = get_object_or_404(Monster.objects.select_related(
        'rulebook',
        'rulebook__dnd_edition',
        'size',
        'type',
    ),
                                pk=monster_id)

    if (monster.slug != monster_slug
            or unicode(monster.rulebook.id) != rulebook_id
            or monster.rulebook.slug != rulebook_slug):
        return permanent_redirect_object_mobile(request, monster)

    assert isinstance(monster, Monster)

    monster_speeds = monster.monsterspeed_set.select_related('type', ).all()
    monster_subtypes = monster.subtypes.all()
    monster_skills = monster.skills.select_related('skill').all()
    monster_feats = monster.feats.select_related('feat',
                                                 'feat__rulebook').all()

    return render_to_response(
        'dnd/mobile/monsters/monster_detail.html',
        {
            'monster': monster,
            'rulebook': monster.rulebook,
            'request': request,
            'monster_speeds': monster_speeds,
            'monster_subtypes': monster_subtypes,
            'monster_skills': monster_skills,
            'monster_feats': monster_feats,
            'i_like_it_url': request.build_absolute_uri(),
            'inaccurate_url': request.build_absolute_uri(),
            'display_3e_warning': is_3e_edition(monster.rulebook.dnd_edition),
        },
        context_instance=RequestContext(request),
    )
Beispiel #11
0
def edition_detail_mobile(request, edition_slug, edition_id):
    dnd_edition = get_object_or_404(DndEdition, id=edition_id)
    if dnd_edition.slug != edition_slug:
        return permanent_redirect_object_mobile(request, dnd_edition)

    rulebook_list = dnd_edition.rulebook_set.select_related(
        'dnd_edition').all()

    paginator = DndMobilePaginator(rulebook_list, request)

    return render_to_response(
        'dnd/mobile/rulebooks/edition_detail.html',
        {
            'dnd_edition': dnd_edition,
            'request': request,
            'rulebook_list': paginator.items(),
            'paginator': paginator,
            'i_like_it_url': request.build_absolute_uri(),
            'inaccurate_url': request.build_absolute_uri(),
            'display_3e_warning': is_3e_edition(dnd_edition),
        },
        context_instance=RequestContext(request),
    )
Beispiel #12
0
def feat_detail_mobile(request, rulebook_slug, rulebook_id, feat_slug, feat_id):
    feat = get_object_or_404(
        Feat.objects.select_related('rulebook', 'rulebook__dnd_edition'),
        pk=feat_id)
    if (feat.slug != feat_slug or
                unicode(feat.rulebook.id) != rulebook_id or
                feat.rulebook.slug != rulebook_slug):
        return permanent_redirect_object_mobile(request, feat)

    feat_category_list = feat.feat_categories.select_related().all()
    required_feats = feat.required_feats.select_related('required_feat',
                                                        'required_feat__rulebook').all()
    required_by_feats = feat.required_by_feats.select_related('source_feat',
                                                              'source_feat__rulebook').all()
    required_skills = feat.required_skills.select_related('skill').all()
    special_prerequisities = feat.featspecialfeatprerequisite_set.select_related(
        'special_feat_prerequisite').all()
    # related feats
    related_feats = Feat.objects.filter(slug=feat.slug).exclude(rulebook__id=feat.rulebook.id).select_related(
        'rulebook', 'rulebook__dnd_edition').all()

    return render_to_response('dnd/mobile/feats/feat_detail.html',
                              {
                                  'feat': feat,
                                  'rulebook': feat.rulebook,
                                  'feat_category_list': feat_category_list,
                                  'required_feats': required_feats,
                                  'required_by_feats': required_by_feats,
                                  'required_skills': required_skills,
                                  'special_prerequisities': special_prerequisities,
                                  'request': request,
                                  'i_like_it_url': request.build_absolute_uri(),
                                  'inaccurate_url': request.build_absolute_uri(),
                                  'display_3e_warning': is_3e_edition(feat.rulebook.dnd_edition),
                                  'related_feats': related_feats,
                              }, context_instance=RequestContext(request), )
Beispiel #13
0
def skill_detail_mobile(request, skill_slug, rulebook_slug=None,
                        rulebook_id=None):
    # fetch the class
    skill = get_object_or_404(Skill.objects.select_related(
        'skill_variant', 'skill_variant__rulebook'), slug=skill_slug)

    # fetch primary variant, this is independent of rulebook selected
    try:
        primary_variant = SkillVariant.objects.select_related(
            'rulebook', 'rulebook__dnd_edition',
        ).filter(
            skill=skill,
        ).order_by('-rulebook__dnd_edition__core', '-rulebook__published')[0]
    except Exception:
        primary_variant = None

    # if rulebook is supplied, select find this variant
    if rulebook_slug and rulebook_id:
        # use canonical link in head as this is more or less duplicated content
        use_canonical_link = True
        selected_variant = get_object_or_404(
            SkillVariant.objects.select_related(
                'rulebook', 'skill', 'rulebook__dnd_edition'),
            skill__slug=skill_slug,
            rulebook__pk=rulebook_id)

        # possible malformed/changed slug
        if rulebook_slug != selected_variant.rulebook.slug:
            return permanent_redirect_object_mobile(request, selected_variant)

        # selected variant is primary! Redirect to canonical url
        if selected_variant == primary_variant:
            return permanent_redirect_view(
                request, skill_detail_mobile, kwargs={
                    'skill_slug': skill_slug}
            )
    else:
        # this is canonical, no need to specify it
        use_canonical_link = False
        selected_variant = primary_variant

    other_variants = [
        variant
        for variant
        in skill.skillvariant_set.select_related(
            'rulebook', 'rulebook__dnd_edition', 'skill').all()
        if variant != selected_variant
    ]

    if selected_variant:
        display_3e_warning = is_3e_edition(selected_variant.rulebook.dnd_edition)
    else:
        display_3e_warning = False

    feat_list = skill.required_by_feats.select_related('rulebook').all()
    feat_paginator = DndMobilePaginator(feat_list, request)

    return render_to_response('dnd/mobile/skills/skill_detail.html',
                              {
                                  'skill': skill,
                                  'feat_list': feat_paginator.items(),
                                  'feat_paginator': feat_paginator,
                                  'request': request,
                                  'i_like_it_url': request.build_absolute_uri(),
                                  'inaccurate_url': request.build_absolute_uri(),
                                  'selected_variant': selected_variant,
                                  'other_variants': other_variants,
                                  'use_canonical_link': use_canonical_link,
                                  'display_3e_warning': display_3e_warning,
                              }, context_instance=RequestContext(request), )
Beispiel #14
0
def skill_detail_mobile(request,
                        skill_slug,
                        rulebook_slug=None,
                        rulebook_id=None):
    # fetch the class
    skill = get_object_or_404(Skill.objects.select_related(
        'skill_variant', 'skill_variant__rulebook'),
                              slug=skill_slug)

    # fetch primary variant, this is independent of rulebook selected
    try:
        primary_variant = SkillVariant.objects.select_related(
            'rulebook',
            'rulebook__dnd_edition',
        ).filter(skill=skill, ).order_by('-rulebook__dnd_edition__core',
                                         '-rulebook__published')[0]
    except Exception:
        primary_variant = None

    # if rulebook is supplied, select find this variant
    if rulebook_slug and rulebook_id:
        # use canonical link in head as this is more or less duplicated content
        use_canonical_link = True
        selected_variant = get_object_or_404(
            SkillVariant.objects.select_related('rulebook', 'skill',
                                                'rulebook__dnd_edition'),
            skill__slug=skill_slug,
            rulebook__pk=rulebook_id)

        # possible malformed/changed slug
        if rulebook_slug != selected_variant.rulebook.slug:
            return permanent_redirect_object_mobile(request, selected_variant)

        # selected variant is primary! Redirect to canonical url
        if selected_variant == primary_variant:
            return permanent_redirect_view(request,
                                           skill_detail_mobile,
                                           kwargs={'skill_slug': skill_slug})
    else:
        # this is canonical, no need to specify it
        use_canonical_link = False
        selected_variant = primary_variant

    other_variants = [
        variant for variant in skill.skillvariant_set.select_related(
            'rulebook', 'rulebook__dnd_edition', 'skill').all()
        if variant != selected_variant
    ]

    if selected_variant:
        display_3e_warning = is_3e_edition(
            selected_variant.rulebook.dnd_edition)
    else:
        display_3e_warning = False

    feat_list = skill.required_by_feats.select_related('rulebook').all()
    feat_paginator = DndMobilePaginator(feat_list, request)

    return render_to_response(
        'dnd/mobile/skills/skill_detail.html',
        {
            'skill': skill,
            'feat_list': feat_paginator.items(),
            'feat_paginator': feat_paginator,
            'request': request,
            'i_like_it_url': request.build_absolute_uri(),
            'inaccurate_url': request.build_absolute_uri(),
            'selected_variant': selected_variant,
            'other_variants': other_variants,
            'use_canonical_link': use_canonical_link,
            'display_3e_warning': display_3e_warning,
        },
        context_instance=RequestContext(request),
    )
Beispiel #15
0
def character_class_detail_mobile(request, character_class_slug, rulebook_slug=None, rulebook_id=None):
    # fetch the class
    character_class = get_object_or_404(
        CharacterClass.objects.select_related("character_class_variant", "character_class_variant__rulebook"),
        slug=character_class_slug,
    )

    assert isinstance(character_class, CharacterClass)

    # fetch primary variant, this is independent of rulebook selected
    try:
        primary_variant = (
            CharacterClassVariant.objects.select_related("rulebook", "rulebook__dnd_edition")
            .filter(character_class=character_class)
            .order_by("-rulebook__dnd_edition__core", "-rulebook__published")[0]
        )
    except Exception:
        primary_variant = None

    # if rulebook is supplied, select find this variant
    if rulebook_slug and rulebook_id:
        # use canonical link in head as this is more or less duplicated content
        use_canonical_link = True
        selected_variant = get_object_or_404(
            CharacterClassVariant.objects.select_related("rulebook", "character_class", "rulebook__dnd_edition"),
            character_class__slug=character_class_slug,
            rulebook__pk=rulebook_id,
        )

        # possible malformed/changed slug
        if rulebook_slug != selected_variant.rulebook.slug:
            return permanent_redirect_object_mobile(request, selected_variant)

        # selected variant is primary! Redirect to canonical url
        if selected_variant == primary_variant:
            return permanent_redirect_view(
                request, character_class_detail_mobile, kwargs={"character_class_slug": character_class_slug}
            )
    else:
        # this is canonical, no need to specify it
        use_canonical_link = False
        selected_variant = primary_variant

    other_variants = [
        variant
        for variant in character_class.characterclassvariant_set.select_related(
            "rulebook", "rulebook__dnd_edition", "character_class"
        ).all()
        if variant != selected_variant
    ]

    if selected_variant:
        required_races = selected_variant.required_races.select_related("race", "race__rulebook").all()
        required_skills = selected_variant.required_skills.select_related("skill").all()
        required_feats = selected_variant.required_feats.select_related("feat", "feat__rulebook").all()
        display_3e_warning = is_3e_edition(selected_variant.rulebook.dnd_edition)
    else:
        required_races = ()
        required_skills = ()
        required_feats = ()
        display_3e_warning = False

    return render_to_response(
        "dnd/mobile/character_classes/character_class_detail.html",
        {
            "character_class": character_class,
            "request": request,
            "i_like_it_url": request.build_absolute_uri(),
            "inaccurate_url": request.build_absolute_uri(),
            "selected_variant": selected_variant,
            "required_races": required_races,
            "required_skills": required_skills,
            "required_feats": required_feats,
            "other_variants": other_variants,
            "use_canonical_link": use_canonical_link,
            "display_3e_warning": display_3e_warning,
        },
        context_instance=RequestContext(request),
    )
Beispiel #16
0
def character_class_detail_mobile(request, character_class_slug, rulebook_slug=None, rulebook_id=None):
    # fetch the class
    character_class = get_object_or_404(
        CharacterClass.objects.select_related('character_class_variant', 'character_class_variant__rulebook'),
        slug=character_class_slug)

    assert isinstance(character_class, CharacterClass)

    # fetch primary variant, this is independent of rulebook selected
    try:
        primary_variant = CharacterClassVariant.objects.select_related(
            'rulebook', 'rulebook__dnd_edition',
        ).filter(
            character_class=character_class,
        ).order_by('-rulebook__dnd_edition__core', '-rulebook__published')[0]
    except Exception:
        primary_variant = None

    # if rulebook is supplied, select find this variant
    if rulebook_slug and rulebook_id:
        # use canonical link in head as this is more or less duplicated content
        use_canonical_link = True
        selected_variant = get_object_or_404(
            CharacterClassVariant.objects.select_related(
                'rulebook', 'character_class', 'rulebook__dnd_edition'),
            character_class__slug=character_class_slug,
            rulebook__pk=rulebook_id)

        # possible malformed/changed slug
        if rulebook_slug != selected_variant.rulebook.slug:
            return permanent_redirect_object_mobile(request, selected_variant)

        # selected variant is primary! Redirect to canonical url
        if selected_variant == primary_variant:
            return permanent_redirect_view(
                request, character_class_detail_mobile, kwargs={
                    'character_class_slug': character_class_slug}
            )
    else:
        # this is canonical, no need to specify it
        use_canonical_link = False
        selected_variant = primary_variant

    other_variants = [
        variant
        for variant
        in character_class.characterclassvariant_set.select_related(
            'rulebook', 'rulebook__dnd_edition', 'character_class').all()
        if variant != selected_variant
    ]

    if selected_variant:
        required_races = selected_variant.required_races.select_related('race', 'race__rulebook').all()
        required_skills = selected_variant.required_skills.select_related('skill').all()
        required_feats = selected_variant.required_feats.select_related('feat', 'feat__rulebook').all()
        display_3e_warning = is_3e_edition(selected_variant.rulebook.dnd_edition)
    else:
        required_races = ()
        required_skills = ()
        required_feats = ()
        display_3e_warning = False

    return render_to_response('dnd/mobile/character_classes/character_class_detail.html',
                              {
                                  'character_class': character_class,
                                  'request': request,
                                  'i_like_it_url': request.build_absolute_uri(),
                                  'inaccurate_url': request.build_absolute_uri(),
                                  'selected_variant': selected_variant,
                                  'required_races': required_races,
                                  'required_skills': required_skills,
                                  'required_feats': required_feats,
                                  'other_variants': other_variants,
                                  'use_canonical_link': use_canonical_link,
                                  'display_3e_warning': display_3e_warning,
                              }, context_instance=RequestContext(request), )