diff options
-rw-r--r-- | app/birds/admin.py | 3 | ||||
-rw-r--r-- | app/birds/migrations/0001_initial.py | 86 | ||||
-rw-r--r-- | app/birds/migrations/0002_auto_20160313_0953.py | 26 | ||||
-rw-r--r-- | app/birds/migrations/0003_birdsighting_images.py | 21 | ||||
-rw-r--r-- | app/birds/migrations/__init__.py | 0 | ||||
-rw-r--r-- | app/birds/models.py | 14 | ||||
-rw-r--r-- | app/locations/models.py | 6 | ||||
-rw-r--r-- | design/sass/_birds.scss | 12 | ||||
-rw-r--r-- | design/templates/details/bird.html | 16 |
9 files changed, 177 insertions, 7 deletions
diff --git a/app/birds/admin.py b/app/birds/admin.py index ff2db93..09b511a 100644 --- a/app/birds/admin.py +++ b/app/birds/admin.py @@ -39,7 +39,8 @@ class BirdSightingAdmin(OSMGeoAdmin): 'point', 'date', 'image', - 'seen_by' + 'seen_by', + 'images', ), 'classes': ( 'show', diff --git a/app/birds/migrations/0001_initial.py b/app/birds/migrations/0001_initial.py new file mode 100644 index 0000000..0e18574 --- /dev/null +++ b/app/birds/migrations/0001_initial.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2016-03-13 09:49 +from __future__ import unicode_literals + +import birds.models +from django.conf import settings +import django.contrib.gis.db.models.fields +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('locations', '__first__'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Bird', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('common_name', models.CharField(max_length=200)), + ('slug', models.SlugField()), + ('scientific_name', models.CharField(max_length=200)), + ('code', models.IntegerField(choices=[(1, 'regular occurring - common'), (2, 'regular occurring - less common'), (3, 'rare'), (4, 'casual'), (5, 'accidental'), (6, 'Cannot be found')], default=0)), + ('image', models.FileField(blank=True, null=True, upload_to=birds.models.get_upload_path)), + ], + options={ + 'ordering': ['common_name'], + }, + ), + migrations.CreateModel( + name='BirdAudio', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('audio', models.FileField(upload_to='audio/birds/')), + ('recorder', models.CharField(blank=True, max_length=200, null=True)), + ('pub_date', models.DateTimeField()), + ('location', models.CharField(blank=True, max_length=200, null=True)), + ('link', models.CharField(blank=True, max_length=450, null=True)), + ('copyright', models.CharField(blank=True, max_length=250, null=True)), + ('bird', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='recordings', to='birds.Bird')), + ], + options={ + 'ordering': ['bird'], + 'verbose_name_plural': 'Bird Audio', + }, + ), + migrations.CreateModel( + name='BirdClass', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('common_name', models.CharField(max_length=200)), + ('scientific_name', models.CharField(max_length=200)), + ], + options={ + 'ordering': ['common_name'], + 'verbose_name_plural': 'Bird Class', + }, + ), + migrations.CreateModel( + name='BirdSighting', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('point', django.contrib.gis.db.models.fields.PointField(srid=4326)), + ('date', models.DateTimeField(default=django.utils.timezone.now, verbose_name='Date')), + ('image', models.FileField(blank=True, null=True, upload_to=birds.models.get_upload_path)), + ('bird', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='birds.Bird')), + ('location', models.ForeignKey(blank=True, on_delete=django.db.models.deletion.CASCADE, to='locations.Location')), + ('seen_by', models.ManyToManyField(to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name_plural': 'Bird Sighting', + }, + ), + migrations.AddField( + model_name='bird', + name='bird_class', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='birds.BirdClass'), + ), + ] diff --git a/app/birds/migrations/0002_auto_20160313_0953.py b/app/birds/migrations/0002_auto_20160313_0953.py new file mode 100644 index 0000000..a2085ea --- /dev/null +++ b/app/birds/migrations/0002_auto_20160313_0953.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2016-03-13 09:53 +from __future__ import unicode_literals + +import birds.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('birds', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='bird', + name='image_credit', + field=models.CharField(blank=True, max_length=200, null=True), + ), + migrations.AlterField( + model_name='bird', + name='image', + field=models.FileField(blank=True, help_text='width of high res is 1360px', null=True, upload_to=birds.models.get_upload_path), + ), + ] diff --git a/app/birds/migrations/0003_birdsighting_images.py b/app/birds/migrations/0003_birdsighting_images.py new file mode 100644 index 0000000..d20e8b7 --- /dev/null +++ b/app/birds/migrations/0003_birdsighting_images.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9 on 2016-03-20 08:02 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('photos', '0007_auto_20160320_0802'), + ('birds', '0002_auto_20160313_0953'), + ] + + operations = [ + migrations.AddField( + model_name='birdsighting', + name='images', + field=models.ManyToManyField(to='photos.LuxImage'), + ), + ] diff --git a/app/birds/migrations/__init__.py b/app/birds/migrations/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/birds/migrations/__init__.py diff --git a/app/birds/models.py b/app/birds/models.py index dc2aa19..05a1159 100644 --- a/app/birds/models.py +++ b/app/birds/models.py @@ -8,6 +8,7 @@ from locations.models import Location from django import forms from django.conf import settings +from photos.models import LuxImage def get_upload_path(self, filename): return "images/bird-images/%s/%s" % (datetime.datetime.today().strftime("%Y"), filename) @@ -42,11 +43,21 @@ class Bird(models.Model): 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) + image = models.FileField(upload_to=get_upload_path, null=True, blank=True, help_text="width of high res is 1360px") + image_credit = models.CharField(max_length=200, blank=True, null=True) def __str__(self): return self.common_name + # function to resize large image to 680px wide and use as normal image + # the question is, should this happen here, or with some universale image + # model that can be attached to other models, loaded in entries and + # displayed in galleries. I suppose the answer is yes then isn't it? + # the problem is that I still can't see exactly what that looks like... + + def get_image_url(self): + return "%s%s" % (settings.IMAGES_URL, self.image.url.split("media")[1][8:]) + def get_absolute_url(self): return reverse("birds:detail", kwargs={"slug": self.slug}) @@ -82,6 +93,7 @@ class BirdSighting(models.Model): date = models.DateTimeField('Date', default=timezone.now) image = models.FileField(upload_to=get_upload_path, null=True, blank=True) seen_by = models.ManyToManyField(User) + images = models.ManyToManyField(LuxImage) class Meta: verbose_name_plural = 'Bird Sighting' diff --git a/app/locations/models.py b/app/locations/models.py index a56299e..b4ee2af 100644 --- a/app/locations/models.py +++ b/app/locations/models.py @@ -129,6 +129,12 @@ class Location(models.Model): def __str__(self): return self.name + def comma_name(self): + if self.state.country.name == "United States": + return self.state + else: + return self.state.country + def get_absolute_url(self): return "/locations/%s/%s/%s/" % (self.state.country.slug, self.state.slug, self.slug) diff --git a/design/sass/_birds.scss b/design/sass/_birds.scss index 36b6114..9b712cc 100644 --- a/design/sass/_birds.scss +++ b/design/sass/_birds.scss @@ -21,8 +21,16 @@ font-style: italic; } .birds { - h2, h3 { font-weight: 400;} - h2 { margin-bottom: 0;} + article { + @include constrain_narrow; + } + audio { width: 100%;} + .audio-figure { + margin-top: 2em; + margin-bottom: 2em; + } + article h2, h3 { font-weight: 400;} + article h2 { margin-bottom: 0;} h3 { margin-top: 0; } diff --git a/design/templates/details/bird.html b/design/templates/details/bird.html index 070a921..5140c96 100644 --- a/design/templates/details/bird.html +++ b/design/templates/details/bird.html @@ -1,4 +1,5 @@ {% extends 'base.html' %} +{% load get_image_by_size %} {% block extrahead %} <style> #detail-map-canvas { height: 100%;} @@ -10,13 +11,22 @@ <article> <h1>{{object.common_name}}</h1> <h2 class="sci">{{object.scientific_name}}</h2> -<h3 class="sci">Class {{object.bird_class.scientific_name}} ({{object.bird_class}})</h3> -<p id="endnode">Seen by {% for person in sighting.seen_by.all %}<a href="/birds/{{person}}/">{{person}}</a>{%if forloop.last %}{%else%}{% if forloop.revcounter == 2 %}, and {%else%}, {%endif%}{%endif%}{%endfor%}</p> -{% if recording.audio %} +<h3 class="sci">Family {{object.bird_class.scientific_name}} ({{object.bird_class}})</h3> +{% for image in sighting.images.all %} +<img class="picfull" sizes="(max-width: 680px) 100vw, (min-width: 681) 680px" + srcset="{% for size in image.sizes.all%}{% get_image_by_size image size %} {{size}}w{% if forloop.last%},"{%else%}, {%endif%}{%if forloop.last%} + src="{% get_image_by_size image size %}"{%endif%}{%endfor%} alt="{{image.alt}} ({{sighting.bird.scientific_name}}) photographed by {% if image.photo_credit_source %}{{image.photo_credit_source}}{%else%}Scott Gilbertson{%endif%}"> +{%endfor%} + +<div class="audio-figure"> <audio autoplay="autoplay" 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> +</div> + +<p id="endnode">Seen at {{sighting.location}}, {{sighting.location.comma_name}} in {{sighting.date|date:"M Y"}} by {% for person in sighting.seen_by.all %}<a href="/birds/{{person}}/">{{person}}</a>{%if forloop.last %}{%else%}{% if forloop.revcounter == 2 %}, and {%else%}, {%endif%}{%endif%}{%endfor%}</p> +{% if recording.audio %} {%endif%} </article> </main> |