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 photos.models import LuxImage from utils.util import parse_image, markdown_to_html from utils.next_prev import next_in_order, prev_in_order def render_images(s): s = re.sub('', parse_image, s) return s def extract_main_image(s): soup = BeautifulSoup(s, 'html.parser') image = soup.find_all('img')[0]['id'] return image.split('image-')[1] 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.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) try: self.image = LuxImage.objects.get(pk=extract_main_image(self.body_markdown)) except TypeError: pass 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) # 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_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.DoesNotExist: raise forms.ValidationError("There is no location associated with that point, add it: %sadmin/locations/location/add/" % (settings.BASE_URL)) super(Sighting, self).save() """ Migration from Birds to abstract: apclass = OLDAPClass.objects.all() for b in apclass: NewAPClass.objects.create( common_name = b.common_name, scientific_name = b.scientific_name, kind = 1 ) ap = OLDAP.objects.all() for b in ap: apnew = NewAPClass.objects.get(scientific_name=b.apclass.scientific_name) print(ap) NewAP.objects.create( common_name = b.common_name, scientific_name = b.scientific_name, code = b.code, apclass = apnew, image = b.image, image_credit = b.image_credit, ) print(t) oldsighting = OLDSighting.objects.all() for bird in oldsighting: ap = NEWAP.objects.get(scientific_name=bird.ap.scientific_name) s = NEWSighting.objects.create( ap = ap, point = bird.point, location = bird.location, date = bird.date, ) for t in bird.images.all(): s.images.add(t) for t in bird.seen_by.all(): s.seen_by.add(t) """