def page(request, slug=u'key-to-the-families'): if slug != slug.lower(): raise Http404 title = models.slug_to_title(slug) if title.startswith('Section '): title = title.title() page = get_object_or_404(models.Page, title=title) if page.rank == 'species': raise Http404 proxy = _Proxy(page) return render(request, 'dkey/page.html', { 'partner_site': partner_short_name(request), 'groups': get_groups, 'leads': (lambda: proxy.leads), 'lead_hierarchy': (lambda: proxy.lead_hierarchy), 'page': (lambda: proxy.page), 'rank_beneath': (lambda: proxy.rank_beneath), 'taxa_beneath': (lambda: proxy.taxa_beneath), 'next_page': (lambda: proxy.next() or proxy.page), })
def page(request, slug='key-to-the-families'): if slug != slug.lower(): raise Http404 title = models.slug_to_title(slug) if title.startswith('Section '): title = title.title() page = get_object_or_404(models.Page, title=title) if page.rank == 'species': raise Http404 proxy = _Proxy(page) return render( request, 'dkey/page.html', { 'partner_site': partner_short_name(request), 'groups': get_groups, 'leads': (lambda: proxy.leads), 'lead_hierarchy': (lambda: proxy.lead_hierarchy), 'page': (lambda: proxy.page), 'rank_beneath': (lambda: proxy.rank_beneath), 'taxa_beneath': (lambda: proxy.taxa_beneath), 'next_page': (lambda: next(proxy) or proxy.page), })
def dkey_images(request, slug): if slug == 'key-to-the-families': return jsonify({}) # Whether a dkey page displays groups of families, genera, or taxa, # we need to pull exactly one species to stand as the representative # for each taxon, and then grab all of the rank=1 content images for # those species. title = dkey_models.slug_to_title(slug) page = get_object_or_404(dkey_models.Page, title=title) taxa = None rank = None taxa_names = [] for lead in page.leads.all(): if lead.taxa_cache: rank, comma_list = lead.taxa_cache.split(':') taxa_names.extend(comma_list.split(',')) if rank is None: return jsonify({}) group_title = None if page.rank == 'group': group_title = page.title else: for ancestor in page.breadcrumb_cache.all(): if ancestor.rank == 'group': group_title = ancestor.title image_types_allowed = ['plant form'] image_types_allowed.extend(extra_image_types.get(group_title, ())) if rank == u'family': # See https://github.com/newfs/gobotany-app/issues/302 # and https://github.com/newfs/gobotany-app/issues/304 group_number = title.split()[-1] if page.rank == u'group' else u'' cursor = connection.cursor() cursor.execute( """ SELECT f.name, t.id, (SELECT id FROM core_taxon WHERE family_id = f.id LIMIT 1) FROM core_family f LEFT JOIN dkey_illustrativespecies i ON (i.group_number = %s AND f.name = i.family_name) LEFT JOIN core_taxon t ON (i.species_name = t.scientific_name) WHERE f.name IN %s""", ( group_number, tuple(taxa_names), )) rows = cursor.fetchall() family_map = {} for family_name, illustrative_taxon_id, random_taxon_id in rows: taxon_id = illustrative_taxon_id if taxon_id is None: taxon_id = random_taxon_id family_map[taxon_id] = family_name taxon_ids = family_map.keys() elif rank == u'genus': cursor = connection.cursor() cursor.execute( """ SELECT (SELECT id FROM core_taxon WHERE genus_id = g.id LIMIT 1) FROM core_genus g WHERE g.name IN %s""", (tuple(taxa_names), )) taxon_ids = [id for (id, ) in cursor.fetchall()] elif rank == u'species': taxa = Taxon.objects.filter(scientific_name__in=taxa_names) taxon_ids = [taxon.id for taxon in taxa] else: return jsonify({}) if taxa is None: taxa = Taxon.objects.filter(id__in=taxon_ids) ctype = ContentType.objects.get_for_model(Taxon) query = (ContentImage.objects.filter( content_type=ctype, object_id__in=taxon_ids, rank=1).filter( image_type__name__in=image_types_allowed).select_related( 'image_type')) image_map = {(image.object_id, image.image_type.name): image.thumb_small() for image in query} image_types = sorted(set(key[1] for key in image_map)) image_lists = [] for taxon in taxa: if rank == u'family': name = family_map[taxon.id] title = u'{}<br><i>({})</i>'.format(name, taxon.scientific_name) else: if rank == u'genus': name = taxon.genus_name() else: name = taxon.scientific_name title = u'<i>{}</i>'.format(taxon.scientific_name) image_list = [] for image_type in image_types: image = image_map.get((taxon.id, image_type)) if image is not None: image_list.append({ 'image_type': image_type, 'image_url': secure_url(image_map.get((taxon.id, image_type))), }) image_lists.append({ 'name': name, 'scientific_name': taxon.scientific_name, 'title': title, 'image_list': image_list, }) image_lists.sort(key=itemgetter('title')) return jsonify({ 'image_types': image_types, 'image_lists': image_lists, })
def dkey(request, slug=u'key-to-the-families'): if request.method == 'GET': # For showing the D. Key Editor page if slug != slug.lower(): raise Http404 title = dkey_models.slug_to_title(slug) if title.startswith('Section '): title = title.title() page = get_object_or_404(dkey_models.Page, title=title) if page.rank == 'species': raise Http404 proxy = _Proxy(page) families = models.Family.objects.all() genera = models.Genus.objects.all() sections = list(dkey_models.Page.objects.filter( rank='section').order_by('title').values_list('title', flat=True)) carex_sections = [(section.replace('Section ', ''), section.lower().replace(' ', '-')) for section in sections] return render(request, 'gobotany/edit_dkey.html', { 'families': families, 'genera': genera, 'carex_sections': carex_sections, 'groups': get_groups, 'leads': (lambda: proxy.leads), 'lead_hierarchy': (lambda: proxy.lead_hierarchy), 'page': (lambda: proxy.page), 'rank_beneath': (lambda: proxy.rank_beneath), 'taxa_beneath': (lambda: proxy.taxa_beneath), 'next_page': (lambda: proxy.next() or proxy.page), 'messages': get_messages(request), }) elif request.method == 'POST': # Add or delete a couplet. command = request.POST['command'] lead_id = request.POST['lead-id'] added_leads = [] deleted_leads = [] last_number = 0 this_lead = dkey_models.Lead.objects.get(id=lead_id) if command == 'add': # Add a couplet. # Create a temporary sequence number for the new leads far above # the likely highest on the page, to be renumbered later. temp_seq_number = this_lead.letter.replace('a', '').replace( 'b', '') + '500' a_lead = dkey_models.Lead() a_lead.page = this_lead.page a_lead.parent = this_lead a_lead.letter = temp_seq_number + 'a' a_lead.text = 'NEW A LEAD UNDER ' + this_lead.letter.upper() a_lead.save() b_lead = dkey_models.Lead() b_lead.page = this_lead.page b_lead.parent = this_lead b_lead.letter = temp_seq_number + 'b' b_lead.text = 'NEW B LEAD UNDER ' + this_lead.letter.upper() b_lead.save() added_leads = dkey_models.Lead.objects.filter(parent=lead_id) elif command == 'delete': # Delete a couplet. leads_to_delete = dkey_models.Lead.objects.filter(parent=lead_id) # Be careful about deleting lead records: # verify that there are two, and delete no more than two. if leads_to_delete.count() == 2: deleted_leads.append(leads_to_delete[0].id) deleted_leads.append(leads_to_delete[1].id) leads_to_delete.delete() elif command == 'promote': print('command: promote') # Determine the new parent of the leads that will be promoted. promoted_leads_parent = this_lead.parent print('promoted_leads_parent:', promoted_leads_parent) # Disconnect the leads that are being replaced rather than fully # delete them. This way the records stay around for future use. # # Query the leads whose parent equals the promoted_leads_parent. # This should return just the two leads to be disconnected. leads_to_disconnect = dkey_models.Lead.objects.filter( parent=this_lead.parent) print('leads to disconnect:', leads_to_disconnect) # Be careful about disconnecting old leads: verify there are two. if leads_to_disconnect.count() == 2: print('leads_to_disconnect[0].parent (set to None):', leads_to_disconnect[0].parent) leads_to_disconnect[0].parent = None leads_to_disconnect[0].save() print('leads_to_disconnect[0].parent:', leads_to_disconnect[0].parent) print('leads_to_disconnect[1].parent (set to None):', leads_to_disconnect[1].parent) leads_to_disconnect[1].parent = None leads_to_disconnect[1].save() print('leads_to_disconnect[1].parent:', leads_to_disconnect[1].parent) # Query the leads that are to be promoted. leads_to_promote = dkey_models.Lead.objects.filter(parent=lead_id) # Be careful about promoting lead records: verify there are two. if leads_to_promote.count() == 2: print('leads_to_promote[0]: %s - current parent is %s, set to %s' % ( leads_to_promote[0], leads_to_promote[0].parent, promoted_leads_parent)) leads_to_promote[0].parent = promoted_leads_parent leads_to_promote[0].save() print('leads_to_promote[0].parent:', leads_to_promote[0].parent) print('leads_to_promote[1]: %s - current parent is %s, set to %s' % ( leads_to_promote[1], leads_to_promote[1].parent, promoted_leads_parent)) leads_to_promote[1].parent = promoted_leads_parent leads_to_promote[1].save() print('leads_to_promote[1].parent:', leads_to_promote[1].parent) last_number = _renumber_page(this_lead.page) if slug != slug.lower(): raise Http404 title = dkey_models.slug_to_title(slug) if title.startswith('Section '): title = title.title() page = get_object_or_404(dkey_models.Page, title=title) if page.rank == 'species': raise Http404 proxy = _Proxy(page) return redirect(request.path)
def dkey_images(request, slug): if slug == 'key-to-the-families': return jsonify({}) # Whether a dkey page displays groups of families, genera, or taxa, # we need to pull exactly one species to stand as the representative # for each taxon, and then grab all of the rank=1 content images for # those species. title = dkey_models.slug_to_title(slug) page = get_object_or_404(dkey_models.Page, title=title) taxa = None rank = None taxa_names = [] for lead in page.leads.all(): if lead.taxa_cache: rank, comma_list = lead.taxa_cache.split(':') taxa_names.extend(comma_list.split(',')) if rank is None: return jsonify({}) group_title = None if page.rank == 'group': group_title = page.title else: for ancestor in page.breadcrumb_cache.all(): if ancestor.rank == 'group': group_title = ancestor.title image_types_allowed = ['plant form'] image_types_allowed.extend(extra_image_types.get(group_title, ())) if rank == u'family': # See https://github.com/newfs/gobotany-app/issues/302 # and https://github.com/newfs/gobotany-app/issues/304 group_number = title.split()[-1] if page.rank == u'group' else u'' cursor = connection.cursor() cursor.execute(""" SELECT f.name, t.id, (SELECT id FROM core_taxon WHERE family_id = f.id LIMIT 1) FROM core_family f LEFT JOIN dkey_illustrativespecies i ON (i.group_number = %s AND f.name = i.family_name) LEFT JOIN core_taxon t ON (i.species_name = t.scientific_name) WHERE f.name IN %s""", (group_number, tuple(taxa_names),)) rows = cursor.fetchall() family_map = {} for family_name, illustrative_taxon_id, random_taxon_id in rows: taxon_id = illustrative_taxon_id if taxon_id is None: taxon_id = random_taxon_id family_map[taxon_id] = family_name taxon_ids = family_map.keys() elif rank == u'genus': cursor = connection.cursor() cursor.execute(""" SELECT (SELECT id FROM core_taxon WHERE genus_id = g.id LIMIT 1) FROM core_genus g WHERE g.name IN %s""", (tuple(taxa_names),)) taxon_ids = [ id for (id,) in cursor.fetchall() ] elif rank == u'species': taxa = Taxon.objects.filter(scientific_name__in=taxa_names) taxon_ids = [ taxon.id for taxon in taxa ] else: return jsonify({}) if taxa is None: taxa = Taxon.objects.filter(id__in=taxon_ids) ctype = ContentType.objects.get_for_model(Taxon) query = (ContentImage.objects .filter(content_type=ctype, object_id__in=taxon_ids, rank=1) .filter(image_type__name__in=image_types_allowed) .select_related('image_type') ) image_map = { (image.object_id, image.image_type.name): image.thumb_small() for image in query } image_types = sorted(set(key[1] for key in image_map)) image_lists = [] for taxon in taxa: if rank == u'family': name = family_map[taxon.id] title = u'{}<br><i>({})</i>'.format(name, taxon.scientific_name) else: if rank == u'genus': name = taxon.genus_name() else: name = taxon.scientific_name title = u'<i>{}</i>'.format(taxon.scientific_name) image_list = [] for image_type in image_types: image = image_map.get((taxon.id, image_type)) if image is not None: image_list.append({ 'image_type': image_type, 'image_url': image_map.get((taxon.id, image_type)), }) image_lists.append({ 'name': name, 'scientific_name': taxon.scientific_name, 'title': title, 'image_list': image_list, }) image_lists.sort(key=itemgetter('title')) return jsonify({ 'image_types': image_types, 'image_lists': image_lists, })
def dkey(request, slug='key-to-the-families'): if request.method == 'GET': # For showing the D. Key Editor page if slug != slug.lower(): raise Http404 title = dkey_models.slug_to_title(slug) if title.startswith('Section '): title = title.title() page = get_object_or_404(dkey_models.Page, title=title) if page.rank == 'species': raise Http404 proxy = _Proxy(page) families = models.Family.objects.all() genera = models.Genus.objects.all() sections = list( dkey_models.Page.objects.filter( rank='section').order_by('title').values_list('title', flat=True)) carex_sections = [(section.replace('Section ', ''), section.lower().replace(' ', '-')) for section in sections] return render( request, 'gobotany/edit_dkey.html', { 'families': families, 'genera': genera, 'carex_sections': carex_sections, 'groups': get_groups, 'leads': (lambda: proxy.leads), 'lead_hierarchy': (lambda: proxy.lead_hierarchy), 'page': (lambda: proxy.page), 'rank_beneath': (lambda: proxy.rank_beneath), 'taxa_beneath': (lambda: proxy.taxa_beneath), 'next_page': (lambda: next(proxy) or proxy.page), 'messages': get_messages(request), }) elif request.method == 'POST': # Add or delete a couplet. command = request.POST['command'] lead_id = request.POST['lead-id'] added_leads = [] deleted_leads = [] last_number = 0 this_lead = dkey_models.Lead.objects.get(id=lead_id) if command == 'add': # Add a couplet. # Create a temporary sequence number for the new leads far above # the likely highest on the page, to be renumbered later. temp_seq_number = this_lead.letter.replace('a', '').replace( 'b', '') + '500' a_lead = dkey_models.Lead() a_lead.page = this_lead.page a_lead.parent = this_lead a_lead.letter = temp_seq_number + 'a' a_lead.text = 'NEW A LEAD UNDER ' + this_lead.letter.upper() a_lead.save() b_lead = dkey_models.Lead() b_lead.page = this_lead.page b_lead.parent = this_lead b_lead.letter = temp_seq_number + 'b' b_lead.text = 'NEW B LEAD UNDER ' + this_lead.letter.upper() b_lead.save() added_leads = dkey_models.Lead.objects.filter(parent=lead_id) elif command == 'delete': # Delete a couplet. leads_to_delete = dkey_models.Lead.objects.filter(parent=lead_id) # Be careful about deleting lead records: # verify that there are two, and delete no more than two. if leads_to_delete.count() == 2: deleted_leads.append(leads_to_delete[0].id) deleted_leads.append(leads_to_delete[1].id) leads_to_delete.delete() elif command == 'promote': # Determine the new parent of the leads that will be promoted. promoted_leads_parent = this_lead.parent # Disconnect the leads that are being replaced. # Query the leads whose parent equals the promoted_leads_parent. # This should return just the two leads to be disconnected. leads_to_disconnect = dkey_models.Lead.objects.filter( parent=this_lead.parent).order_by('letter') # Be careful about disconnecting leads: verify there are two. if leads_to_disconnect.count() == 2: first_removed_lead = leads_to_disconnect[0] second_removed_lead = leads_to_disconnect[1] # Disconnect the first lead. first_removed_lead.parent = None try: first_removed_lead.save() except ValidationError as e: print(('ValidationError when disconnecting first lead:', e.message_dict)) # Disconnect the second lead. second_removed_lead.parent = None try: second_removed_lead.save() except ValidationError as e: print(('ValidationError when disconnecting second lead:', e.message_dict)) # Query the leads that are to be promoted, i.e. moved up, # to replace the leads that have just been removed. leads_to_promote = dkey_models.Lead.objects.filter( parent=lead_id).order_by('letter') # Be careful about promoting lead records: verify there are two. if leads_to_promote.count() == 2: first_lead = leads_to_promote[0] second_lead = leads_to_promote[1] # Set a new parent for the first lead. first_lead.parent = promoted_leads_parent try: first_lead.save() except ValidationError as e: print(('ValidationError:', e.message_dict)) # Set a new parent for the second lead. second_lead.parent = promoted_leads_parent try: second_lead.save() except ValidationError as e: print(('ValidationError:', e.message_dict)) # Delete the two disconnected leads, which should also # delete any child leads that one of them may have had. # This deletion was mentioned to the user in a confirmation # message to let them know that this would happen. try: first_removed_lead.delete() except ValidationError as e: print(('ValidationError when deleting first lead:', e.message_dict)) try: second_removed_lead.delete() except ValidationError as e: print(('ValidationError when deleting second lead:', e.message_dict)) last_number = _renumber_page(this_lead.page) if slug != slug.lower(): raise Http404 title = dkey_models.slug_to_title(slug) if title.startswith('Section '): title = title.title() page = get_object_or_404(dkey_models.Page, title=title) if page.rank == 'species': raise Http404 proxy = _Proxy(page) return redirect(request.path)
def dkey(request, slug=u'key-to-the-families'): if request.method == 'GET': # For showing the D. Key Editor page if slug != slug.lower(): raise Http404 title = dkey_models.slug_to_title(slug) if title.startswith('Section '): title = title.title() page = get_object_or_404(dkey_models.Page, title=title) if page.rank == 'species': raise Http404 proxy = _Proxy(page) return render( request, 'gobotany/edit_dkey.html', { 'groups': get_groups, 'leads': (lambda: proxy.leads), 'lead_hierarchy': (lambda: proxy.lead_hierarchy), 'page': (lambda: proxy.page), 'rank_beneath': (lambda: proxy.rank_beneath), 'taxa_beneath': (lambda: proxy.taxa_beneath), 'next_page': (lambda: proxy.next() or proxy.page), }) elif request.method == 'POST': # Add or delete a couplet. command = request.POST['command'] lead_id = request.POST['lead-id'] added_leads = [] deleted_leads = [] last_number = 0 this_lead = dkey_models.Lead.objects.get(id=lead_id) if command == 'add': # Add a couplet. # Create a temporary sequence number for the new leads far above # the likely highest on the page, to be renumbered later. temp_seq_number = this_lead.letter.replace('a', '').replace( 'b', '') + '500' a_lead = dkey_models.Lead() a_lead.page = this_lead.page a_lead.parent = this_lead a_lead.letter = temp_seq_number + 'a' a_lead.text = 'NEW A LEAD UNDER ' + this_lead.letter.upper() a_lead.save() b_lead = dkey_models.Lead() b_lead.page = this_lead.page b_lead.parent = this_lead b_lead.letter = temp_seq_number + 'b' b_lead.text = 'NEW B LEAD UNDER ' + this_lead.letter.upper() b_lead.save() added_leads = dkey_models.Lead.objects.filter(parent=lead_id) elif command == 'delete': # Delete a couplet. leads_to_delete = dkey_models.Lead.objects.filter(parent=lead_id) # Be careful about deleting lead records: # verify that there are two, and delete no more than two. if leads_to_delete.count() == 2: deleted_leads.append(leads_to_delete[0].id) deleted_leads.append(leads_to_delete[1].id) leads_to_delete.delete() last_number = _renumber_page(this_lead.page) if slug != slug.lower(): raise Http404 title = dkey_models.slug_to_title(slug) if title.startswith('Section '): title = title.title() page = get_object_or_404(dkey_models.Page, title=title) if page.rank == 'species': raise Http404 proxy = _Proxy(page) return redirect(request.path)