import datetime import re from django.urls import reverse from django.apps import apps 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 django import forms from django.conf import settings from bs4 import BeautifulSoup from locations.models import Location from media.models import LuxImage, LuxImageSize from utils.next_prev import next_in_order, prev_in_order from utils.util import render_images, extract_main_image, markdown_to_html def get_upload_path(self, filename): return "images/sightings-images/%s/%s" % (datetime.datetime.today().strftime("%Y"), filename) # from http://aba.org/checklist/codes.html ABA_CODES = ( (0, 'unknown'), (1, 'regular occurring - common'), (2, 'regular occurring - less common'), (3, 'rare'), (4, 'casual'), (5, 'accidental'), (6, 'Cannot be found'), ) KIND_LIST = ( (1, 'Birds'), (2, 'Mammals'), (3, 'Reptiles'), (4, 'Amphibians'), (5, 'Plants'), ) class APClass(models.Model): common_name = models.CharField(max_length=200) scientific_name = models.CharField(max_length=200) kind = models.IntegerField(choices=KIND_LIST, default=1) class Meta: verbose_name_plural = 'Animal/Plant Class' ordering = ["kind", "common_name"] def __str__(self): return self.common_name class AP(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) apclass = models.ForeignKey(APClass, on_delete=models.CASCADE) body_html = models.TextField(null=True, blank=True) body_markdown = models.TextField(null=True, blank=True) image = models.ForeignKey(LuxImage, on_delete=models.CASCADE, 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) class Meta: verbose_name_plural = 'Animal/Plant' verbose_name = 'Animal/Plant' ordering = ["common_name", ] def __str__(self): return self.common_name def get_image_url(self): return "%s%s" % (settings.IMAGES_URL, self.image.image.url.split("media")[1][8:]) def get_absolute_url(self): return reverse("sightings:detail", kwargs={"slug": self.slug}) @property def seen(self): if self.sighting_set.all(): return True else: return False def kind(self): return self.apclass.kind def get_prev(self): model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name) return prev_in_order(self, model.objects.all()) def get_next(self): model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name) return next_in_order(self, model.objects.all()) @property def get_previous_admin_url(self): model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name) try: return reverse('admin:%s_%s_change' % (self._meta.app_label, self._meta.model_name), args=[self.get_prev().pk]) except model.DoesNotExist: return '' @property def get_next_admin_url(self): model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name) try: return reverse('admin:%s_%s_change' % (self._meta.app_label, self._meta.model_name), args=[self.get_next().pk]) except model.DoesNotExist: return '' def save(self, *args, **kwargs): if self.pk: md = render_images(self.body_markdown) self.body_html = markdown_to_html(md) main_image = extract_main_image(self.body_markdown) if main_image: self.image = main_image s = LuxImageSize.objects.get(name="featured_jrnl") self.image.sizes.add(s) self.image.save() self.slug = slugify(self.common_name[:50]) super(AP, self).save(*args, **kwargs) class Sighting(models.Model): ap = models.ForeignKey(AP, on_delete=models.CASCADE) point = models.PointField(blank=True) location = models.ForeignKey(Location, on_delete=models.CASCADE, blank=True) pub_date = models.DateTimeField('Date', default=timezone.now) location_name = models.CharField(max_length=200, blank=True) state_name = models.CharField(max_length=200, blank=True) country_name = models.CharField(max_length=200, blank=True) country_slug = models.CharField(max_length=200, blank=True) region_name = models.CharField(max_length=200, blank=True) ap_common_name = models.CharField(max_length=200, blank=True) # seen_by = models.ManyToManyField(User) # images = models.ManyToManyField(LuxImage, blank=True) # audio = models.ManyToManyField(BirdAudio, blank=True) class Meta: ordering = ["-pub_date", ] get_latest_by = "pub_date" @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 @property def get_previous_admin_url(self): n = self.get_previous_by_pub_date() return reverse('admin:%s_%s_change' % (self._meta.app_label, self._meta.model_name), args=[n.id]) @property def get_next_admin_url(self): model = apps.get_model(app_label=self._meta.app_label, model_name=self._meta.model_name) try: return reverse('admin:%s_%s_change' % (self._meta.app_label, self._meta.model_name), args=[self.get_next_by_pub_date().pk]) except model.DoesNotExist: return '' def get_small_image(self): for img in self.images.all(): for size in img.sizes.all(): if size.width > 360 and size.width < 700: return img.get_image_url_by_size(size) def get_absolute_url(self): return reverse("sightings:detail", kwargs={"slug": self.ap.slug}) def __str__(self): return self.ap_common_name def save(self, *args, **kwargs): if not self.point: self.point = Sighting.objects.latest().point try: self.location = Location.objects.filter(geometry__contains=self.point).get() except Location.MultipleObjectsReturned: for l in Location.objects.filter(geometry__contains=self.point): print(l) print(l.parent) if l.parent: self.location = l break except Location.DoesNotExist: raise forms.ValidationError("There is no location associated with that point, add it: %sadmin/locations/location/add/" % (settings.BASE_URL)) self.ap_common_name = self.ap.common_name self.location_name = self.location.name self.state_name = self.location.state.name self.country_name = self.location.state.country.name self.country_slug = self.location.state.country.slug self.region_name = self.location.state.country.lux_region.name super(Sighting, self).save() class FieldNote(models.Model): sighting = models.ForeignKey(Sighting, on_delete=models.CASCADE) body_html = models.TextField(blank=True) body_markdown = models.TextField(blank=True) # these are only used to speed up admin sighting_pub_date = models.DateTimeField('Date', blank=True) sighting_location = models.CharField(max_length=200, blank=True) ap_common_name = models.CharField(max_length=200, blank=True) class Meta: ordering = ["sighting_pub_date", ] def __str__(self): return '%s %s' % (self.ap_common_name, self.pk) def save(self, *args, **kwargs): self.sighting_pub_date = self.sighting.pub_date self.ap_common_name = self.sighting.ap.common_name self.sighting_location = self.sighting.location_name md = render_images(self.body_markdown) self.body_html = markdown_to_html(md) super(FieldNote, self).save()