コード例 #1
0
ファイル: views.py プロジェクト: devfort/wildlifenearyou
def autocomplete_species(request, place_id):
    place = get_object_or_404(Place, pk = place_id)
    q = request.GET.get('q', '')
    results = list(search_species(q, 30))
    # We're going to build three groups - species that have been sighted at 
    # this place, species that have been sighted somewhere else, and species 
    # that have not been sighted at all.
    seen_here_group = []
    seen_elsewhere_group = []
    not_seen_group = []
    for result in results:
        # If it's in our Species database, annotate with a bunch of stuff
        species = None
        try:
            species = Species.objects.get(freebase_id = result['freebase_id'])
        except Species.DoesNotExist:
            pass
        if not species:
            result['select_id'] = 'x_%s' % result['search_id']
            not_seen_group.append(result)
            continue
        # Matches a known species
        result['select_id'] = 's_%s' % species.id
        # Annotate with photo
        photos = Photo.objects.filter(
            sightings__species = species,
            is_visible = True
        ).distinct()
        result['photo'] = photos and unicode(photos[0].photo.thumbnail) or ''
        # Assign to a group and annotate with number of previous sightings
        num_sightings_here = Sighting.objects.filter(
            species = species,
            place = place
        ).count()
        if num_sightings_here:
            result['num_sightings'] = num_sightings_here
            seen_here_group.append(result)
            continue
        num_sightings = Sighting.objects.filter(
            species__freebase_id = result['freebase_id']
        ).count()
        if num_sightings:
            result['num_sightings'] = num_sightings
            seen_elsewhere_group.append(result)
            continue
        # Not seen anywhere before
        not_seen_group.append(result)
    
    # Order each group by number of sightings, with most at the top
    seen_here_group.sort(key = lambda r: r['num_sightings'], reverse=True)
    seen_elsewhere_group.sort(
        key = lambda r: r['num_sightings'], reverse=True
    )
    return render(request, 'trips/autocomplete_species.html', {
        'seen_here': seen_here_group,
        'seen_elsewhere': seen_elsewhere_group,
        'not_seen': not_seen_group,
        'q': q,
    })
コード例 #2
0
ファイル: views.py プロジェクト: devfort/wildlifenearyou
def pick_sightings(request, redirect_to):
    """
    A replacement for the old add_sightings view. This one is designed to 
    sit in between two different parts of the interface. It narrows down
    the list of entered text to concrete species as before, then forwards 
    the user on to the redirect_to URL with concrete species IDs attached.
    
    For example, the resulting redirect may look like this:
    
    /gb/london-zoo/add-trip/?saw=x:2ab1&saw=s:123&saw=A+baby+tiger
    
    Note that there are now three types of saw IDs:
    
       x:* = a Xapian search ID
       s:* = an animals_species table ID
       *   = free text not matched in our database
    
    Our sightings recording mechanism is now expected to be able to deal with 
    free text, which will be recorded using species_inexact on a Sighting.
    
    The INPUT to this view should start off as something like this:
    
    ../pick-sightings/?saw.1.s=tiger&saw.2.s=pony
    
    If there are any ?saw= items, the view redirects straight away turning
    them in to that format. So, the easiest way to get started with the 
    process is to send someone to:
    
    ../pick-sightings/?saw=tiger&saw=pony
    
    If called with no arguments, starts off with an empty "I saw" form
    
    Additionally, if you include a `trip` parameter in the query string, that's
    the id of the trip we'll add to directly; this just gets passed through to
    
    (This is an ugly implementation in terms of URLs, but was the easiest.)
    
    """
    if request.GET.getlist('saw'):
        # Convert ?saw= arguments to ?saw.1.s= type things
        return Redirect(request.path + '?' + urllib.urlencode([
            ('saw.%d.s' % i, saw.strip())
            for i, saw in enumerate(request.GET.getlist('saw'))
            if saw.strip()
        ]))
    
    saw = DotExpandedDict(request.GET).get('saw')
    if request.GET and not saw:
        # Clear out the invalid query string
        return Redirect(request.path)
    
    if not saw:
        assert False, "Jump straight to showing the empty form"
    
    # saw should now of format {'0': {'s': 'tiger', 'o': 'x:ba3'}...}
    # Essentially a dictionary of key/dict pairs. The key doesn't actually 
    # matter, it's just used to group values. The dict looks like this:
    #     s = The text the user entered (required)
    #     o = The option they picked to fulfill it (optional)
    #     r = The replacement search they want to run (defaults to same as s)
    # The 'o' value comes from a radio select and can be of these formats:
    #     x_*    = a Xapian search ID they have selected
    #     s_*    = a Species ID they have selected
    #     cancel = don't save this at all (e.g. "I made a mistake")
    #     as-is  = save it using species_inexact
    #     search-again = run the replacement search instead
    
    # Are we done yet? The aim is for every key to have a valid option 
    # provided that isn't 'search-again'.
    if saw and is_valid_saw_list(saw.values()):
        next_vars = [
            urllib.urlencode({
                'saw': d['o'] == 'as-is' and d.get('s') or d['o']
            })
            for d in saw.values()
            if d.get('s') and (d['o'] != 'cancel')
        ]
        if request.GET.get('trip', None):
            next_vars.append(
                urllib.urlencode({
                    'trip': request.GET['trip']
                })
            )
        return Redirect(redirect_to + '?' + '&'.join(next_vars))
    
    # We aren't done, so we need to build up all of the information required
    # to construct our big form full of options, search results etc
    sections = []
    
    section_id = 0
    label_id = 0
    if saw:
        for key in sorted(saw.keys(), key = lambda k: int(k)):
            d = saw[key]
            search = d.get('r', d['s']).strip()
            if not search:
                continue
            results = list(search_species(search, 20))
            db_matches = list(Species.objects.filter(freebase_id__in = [
                r['freebase_id'] for r in results
            ]))
            choices = []
            is_first = True
            for row in results:
                try:
                    id = 's_%s' % [
                        s for s in db_matches 
                        if s.freebase_id == row['freebase_id']
                    ][0].id
                except IndexError:
                    id = 'x_%s' % row['search_id']
                choices.append({
                    'id': id,
                    'common_name': row['common_name'],
                    'scientific_name': row['scientific_name'],
                    'label_id': label_id,
                    'checked': (d.get('o') == id or (
                        is_first and d.get('o') != 'cancel'
                    )),
                })
                label_id += 1
                is_first = False
            
            sections.append({
                'id': section_id,
                'search': d.get('r', d['s']), # Pick up replacement search
                'options': choices,
                'o': d.get('o'),
            })
            section_id += 1
    
    return render(request, 'trips/pick_sightings.html', {
        'sections': sections,
        'redirect_to': redirect_to,
        'bonus_label_id': section_id,
        'trip_id': request.GET.get('trip', None),
    })