diff options
-rw-r--r-- | app/birds/admin.py | 8 | ||||
-rw-r--r-- | app/birds/models.py | 62 | ||||
-rw-r--r-- | app/birds/urls.py | 8 | ||||
-rw-r--r-- | app/birds/views.py | 27 | ||||
-rw-r--r-- | config/base_urls.py | 1 | ||||
-rw-r--r-- | design/sass/_birds.scss | 22 | ||||
-rw-r--r-- | design/templates/archives/birds.html | 48 | ||||
-rw-r--r-- | design/templates/details/bird.html | 13 |
8 files changed, 184 insertions, 5 deletions
diff --git a/app/birds/admin.py b/app/birds/admin.py index 01a6f4c..8c09b7b 100644 --- a/app/birds/admin.py +++ b/app/birds/admin.py @@ -1,14 +1,17 @@ from django.contrib import admin from django.contrib.gis.admin import OSMGeoAdmin -from birds.models import BirdSighting, BirdClass, Bird +from birds.models import BirdSighting, BirdAudio, BirdClass, Bird class BirdClassAdmin(admin.ModelAdmin): list_display = ('common_name', 'scientific_name',) +class BirdAudioAdmin(admin.ModelAdmin): + list_display = ('bird', 'recorder',) class BirdAdmin(admin.ModelAdmin): list_display = ('pk', 'common_name', 'scientific_name', 'code', 'bird_class') + list_filter = ('bird_class',) class BirdSightingAdmin(OSMGeoAdmin): @@ -17,7 +20,7 @@ class BirdSightingAdmin(OSMGeoAdmin): # options for OSM map Using custom ESRI topo map default_lon = -9285175 default_lat = 4025046 - default_zoom = 6 + default_zoom = 10 units = True scrollable = False map_width = 700 @@ -27,4 +30,5 @@ class BirdSightingAdmin(OSMGeoAdmin): admin.site.register(BirdSighting, BirdSightingAdmin) admin.site.register(BirdClass, BirdClassAdmin) +admin.site.register(BirdAudio, BirdAudioAdmin) admin.site.register(Bird, BirdAdmin) diff --git a/app/birds/models.py b/app/birds/models.py index 3fb0c0f..2ba9451 100644 --- a/app/birds/models.py +++ b/app/birds/models.py @@ -1,11 +1,15 @@ import datetime +from django.template.defaultfilters import slugify from django.contrib.gis.db import models +from django.contrib.auth.models import User +from django.utils import timezone from locations.models import Location def get_upload_path(self, filename): return "images/bird-images/%s/%s" % (datetime.datetime.today().strftime("%Y"), filename) + # from http://aba.org/checklist/codes.html ABA_CODES = ( (1, 'regular occurring - common'), @@ -23,6 +27,7 @@ class BirdClass(models.Model): class Meta: verbose_name_plural = 'Bird Class' + ordering = ["common_name",] def __str__(self): return self.common_name @@ -30,17 +35,72 @@ class BirdClass(models.Model): class Bird(models.Model): common_name = models.CharField(max_length=200) + slug = models.SlugField() scientific_name = models.CharField(max_length=200) code = models.IntegerField(choices=ABA_CODES, default=0) bird_class = models.ForeignKey(BirdClass) + image = models.FileField(upload_to=get_upload_path, null=True, blank=True) def __str__(self): return self.common_name + def get_absolute_url(self): + return "/birds/%s" %(self.slug) + + class Meta: + ordering = ["common_name",] + + def save(self): + self.slug = slugify(self.common_name[:50]) + super(Bird, self).save() + +class BirdAudio(models.Model): + bird = models.ForeignKey(Bird, related_name='recordings') + audio = models.FileField(upload_to='audio/birds/') + recorder = models.CharField(max_length=200, null=True, blank=True) + pub_date = models.DateTimeField() + location = models.CharField(max_length=200, null=True, blank=True) + link = models.CharField(max_length=450, null=True, blank=True) + copyright = models.CharField(max_length=250, null=True, blank=True) + + class Meta: + verbose_name_plural = 'Bird Audio' + ordering = ["bird",] + + def __str__(self): + return self.bird.common_name class BirdSighting(models.Model): bird = models.ForeignKey(Bird) point = models.PointField() location = models.ForeignKey(Location) - date = models.DateTimeField('Date') + date = models.DateTimeField('Date', default=timezone.now) image = models.FileField(upload_to=get_upload_path, null=True, blank=True) + seen_by = models.ManyToManyField(User) + + class Meta: + verbose_name_plural = 'Bird Sighting' + + @property + def state(self): + return self.location.state + + @property + def country(self): + return self.location.state.country + + @property + def region(self): + return self.location.state.country.lux_region + + @property + def longitude(self): + '''Get the site's longitude.''' + return self.point.x + + @property + def latitude(self): + '''Get the site's latitude.''' + return self.point.y + def __str__(self): + return self.bird.common_name diff --git a/app/birds/urls.py b/app/birds/urls.py new file mode 100644 index 0000000..6a219f1 --- /dev/null +++ b/app/birds/urls.py @@ -0,0 +1,8 @@ +from django.conf.urls import * +from django.views.generic.base import RedirectView +from django.views.generic.detail import DetailView + +urlpatterns = patterns('', + url(r'^list/(?P<user>[\w]+)', 'birds.views.bird_list'), + url(r'^(?P<slug>[-_\w]+)$', 'birds.views.bird_detail'), +) diff --git a/app/birds/views.py b/app/birds/views.py new file mode 100644 index 0000000..bd2f79e --- /dev/null +++ b/app/birds/views.py @@ -0,0 +1,27 @@ +from django.shortcuts import render_to_response, get_object_or_404 +from django.template import RequestContext +from django.http import Http404 +from django.conf import settings +# from django.views.generic import ListView + +from birds.models import Bird, BirdAudio, BirdSighting +from locations.models import Region, Country + + +def bird_list(request, user): + #request.page_url = '/birds/seen/%d/' + #request.page = int(page) + context = { + 'object_list': BirdSighting.objects.filter(seen_by__username=user), + 'user': user, + } + return render_to_response("archives/birds.html", context, context_instance=RequestContext(request)) + + +def bird_detail(request, slug): + context = { + 'object': Bird.objects.get(slug=slug), + 'recording': BirdAudio.objects.get(bird__slug=slug) + } + return render_to_response("details/bird.html", context, context_instance=RequestContext(request)) + diff --git a/config/base_urls.py b/config/base_urls.py index c606171..4585d21 100644 --- a/config/base_urls.py +++ b/config/base_urls.py @@ -56,6 +56,7 @@ urlpatterns += patterns('', (r'^photos/', include('photos.urls')), (r'^field-notes/', include('notes.urls')), (r'^photo/', include('photos.detail_urls')), + (r'^birds/', include('birds.urls')), (r'^travel-guide/', include('guide.urls')), # map (r'^map/', include('locations.urls')), diff --git a/design/sass/_birds.scss b/design/sass/_birds.scss index 7c841c4..8e82411 100644 --- a/design/sass/_birds.scss +++ b/design/sass/_birds.scss @@ -1,3 +1,21 @@ -.taxon, .left2:nth-child(2) { - display: none; +.iframe-wrapper { + @include constrain_wide() +} + +.taxon { + display: none !important; +} + +#birds { + .post--title { + @include fontsize(18); + a { + font-style: normal; + @include fontsize(22); + } + } + .sci { + font-style: italic; + } + .audio small { display: block;} } diff --git a/design/templates/archives/birds.html b/design/templates/archives/birds.html new file mode 100644 index 0000000..17cdb79 --- /dev/null +++ b/design/templates/archives/birds.html @@ -0,0 +1,48 @@ +{% extends 'base.html' %} +{% load typogrify_tags %} +{% load pagination_tags %} + +{% block pagetitle %}Luxagraf | Birds seen {% if region %}in {{region.name|title|smartypants|safe}}{%else%}by {{user}}{%endif%}{% if page != "1" %} -- Page {{page}}{%endif%}{% endblock %} +{% block metadescription %}Birds seen {% if region %} in {{region.name|title|smartypants|safe}}{%else%}by {{user}}{%endif%} Page {{page}}{% endblock %} +{%block bodyid%}id="birds"{%endblock%} + + +{% block primary %}<ul class="bl" id="breadcrumbs" itemscope itemtype="http://data-vocabulary.org/Breadcrumb"> + <li><a href="/" title="luxagraf homepage" itemprop="url"><span itemprop="title">Home</span></a> → </li> + {% if region %}{%if region.name == 'United States'%} <li><a href="/birds/" title="See all Journal Entries" itemprop="url"><span itemprop="title">Birds</span></a> →</li> + <li itemprop="title">the United States</li>{%else%}<li><a href="/jrnl/" title="See all Journal Entries" itemprop="url"><span>Birds</span></a> →</li> + <li>{{region.name|title|smartypants|safe}}</li>{%endif%}{%else%}<li>Journal</li>{%endif%} + </ul> + <main role="main" class="archive"> + <h1 class="hide">Birds seen {% if region %}in {%if region.name == 'United States'%}the United States{%else%}{{region.name|title|smartypants|safe}}{%endif%}{%else%} by {{user}}{%endif%}</h1> {% for object in object_list %} + <article class="{% cycle 'odd' 'even' %} {% cycle 'first' 'second' 'third' %}"> + <div class="post--image"> + <a href="{{object.bird.get_absolute_url}}" title="{{object.bird}}"><img src="{{object.get_image_url}}" alt="{{ object.title }}" class="post-image" /></a> + </div> + <h3 class="post--title"><a href="{{object.bird.get_absolute_url}}" title="{%if object.title_keywords%}{{object.title_keywords}}{%else%}{{object.bird}}{%endif%}">{{object.bird|safe|smartypants|widont}}</a> (<span class="sci">{{object.bird.scientific_name}}</span>)</h3> + <time class="post--date" datetime="{{object.date|date:'c'}}">Seen: {{object.date|date:"F"}} <span>{{object.date|date:"j, Y"}}</span></time> + <p> + <span class="sighting location place post--location" itemscope itemtype="http://schema.org/Place">Loc: + {% if object.country.name == "United States" %}<span class="p-locality locality">{{object.location.name|smartypants|safe}}</span>, {{object.state.name}}, <span class="p-country-name">U.S.</span>{%else%}<span class="p-region">{{object.location.name|smartypants|safe}}</span>, {{object.country.name}}</a>{%endif%} + <span style="display: none;" itemprop="geo" itemscope itemtype="http://schema.org/GeoCoordinates"> + <data itemprop="latitude" class="p-latitude" value="{{object.latitude}}">{{object.latitude}}</data> + <data itemprop="longitude" class="p-longitude" value="{{object.longitude}}">{{object.longitude}}</data> + </span> + </span> + </p> + <p class="audio">{% for recording in object.bird.recordings.all %} + <audio controls="controls"> + <source src="/media/{{recording.audio}}" /> + </audio> + <small>Audio recorded by {{recording.recorder}} on {{recording.pub_date|date:"F j, Y"}} in {{recording.location}}. <a href="{{recording.link}}">© {{recording.copyright}}</a></small> + </p>{% endfor %} + </article> {% endfor %} + </main> + <nav class="pagination"> + {% paginate %} + </nav> +{% endblock %} + + + +{% block js %}<script src="/media/js/hyphenate.min.js" type="text/javascript"></script>{% endblock%} diff --git a/design/templates/details/bird.html b/design/templates/details/bird.html new file mode 100644 index 0000000..0a91317 --- /dev/null +++ b/design/templates/details/bird.html @@ -0,0 +1,13 @@ +{% extends 'base.html' %} +{% block extrahead %} +{% endblock %} +{% block primary %} +<main> +{{object.common_name}} +<audio autoplay="autoplay" controls="controls"> + <source src="/media/{{recording.audio}}" /> +</audio> + +</main> +{% endblock %} + |