diff --git a/src/django_stockfin_db/admin.py b/src/django_stockfin_db/admin.py index 2f83493..e38406f 100644 --- a/src/django_stockfin_db/admin.py +++ b/src/django_stockfin_db/admin.py @@ -1,8 +1,32 @@ from django.contrib import admin -from django_stockfin_db.models import FinancialPosition +from django_stockfin_db.models import FinancialPosition, ReportingPeriod, Company, CompanyName, Figure @admin.register(FinancialPosition) class FinancialPositionAdmin(admin.ModelAdmin): + list_display = ('name', 'financial_statement', 'parent_name') + + @admin.display(description='Parent Position Name') + def parent_name(self, obj: FinancialPosition) -> str: + return obj.parent.name if obj.parent else '-' + + +@admin.register(ReportingPeriod) +class ReportingPeriodAdmin(admin.ModelAdmin): + list_display = ('__str__', 'date_end', 'date_start') + + +@admin.register(Company) +class CompanyAdmin(admin.ModelAdmin): + list_display = ('__str__', 'symbol') + + +@admin.register(CompanyName) +class CompanyNameAdmin(admin.ModelAdmin): pass + + +@admin.register(Figure) +class FigureAdmin(admin.ModelAdmin): + list_display = ('position', 'period', 'company', 'value') diff --git a/src/django_stockfin_db/models.py b/src/django_stockfin_db/models.py index bbc1fc3..2f723a0 100644 --- a/src/django_stockfin_db/models.py +++ b/src/django_stockfin_db/models.py @@ -1,8 +1,12 @@ +from datetime import date +from typing import Optional + from django.db.models import Model from django.db.models.fields import CharField, FloatField, BooleanField, DateField, DateTimeField from django.db.models.fields.related import ForeignKey from django.db.models.deletion import PROTECT, CASCADE from django.db.models.enums import TextChoices +from django.core.exceptions import ObjectDoesNotExist from django.utils.translation import gettext_lazy as _ @@ -48,6 +52,9 @@ class FinancialPosition(AbstractBaseModel): verbose_name=_("Parent position") ) + def __str__(self) -> str: + return f"{self.financial_statement} - {self.name}" + class ReportingPeriod(AbstractBaseModel): @@ -64,6 +71,21 @@ class ReportingPeriod(AbstractBaseModel): verbose_name=_("Exact dates verified") ) + def __str__(self) -> str: + date_fmt = '%b %Y' + assert isinstance(self.date_end, date) and isinstance(self.date_start, date) + return f"{'Quarter' if self.is_quarter else 'Year'}: " \ + f"{self.date_start.strftime(date_fmt)} - {self.date_end.strftime(date_fmt)}" + + @property + def is_quarter(self) -> bool: + assert isinstance(self.date_end, date) and isinstance(self.date_start, date) + delta = self.date_end - self.date_start + return delta.days < 100 + + class Meta: + ordering = ['-date_end', 'date_start'] + class Company(AbstractBaseModel): @@ -73,6 +95,21 @@ class Company(AbstractBaseModel): verbose_name=_("Stock ticker symbol") ) + def __str__(self) -> str: + return f"{self.name if self.name else '[~~~ NO NAME ~~~]'} ({self.symbol})" + + @property + def name(self) -> Optional[str]: + if self.current_name_obj is not None: + return self.current_name_obj.name + + @property + def current_name_obj(self) -> Optional['CompanyName']: + try: + return self.company_names.latest() + except ObjectDoesNotExist: + return None + class Meta: verbose_name_plural = _("Companies") @@ -81,7 +118,9 @@ class CompanyName(AbstractBaseModel): company = ForeignKey( to=Company, - on_delete=CASCADE + on_delete=CASCADE, + related_name='company_names', + related_query_name='company_name', ) name = CharField( max_length=1024, @@ -90,9 +129,17 @@ class CompanyName(AbstractBaseModel): ) name_since = DateField( db_index=True, + null=True, + blank=True, verbose_name=_("Has this name since") ) + def __str__(self) -> str: + return self.name + + class Meta: + get_latest_by = ['name_since', 'date_modified'] + class Figure(AbstractBaseModel): @@ -111,3 +158,6 @@ class Figure(AbstractBaseModel): value = FloatField( verbose_name=_("Figure on financial statement") ) + + class Meta: + ordering = ['company', 'period', 'position']