|
1 | | -""" Tagging app data models """ |
| 1 | +""" Tagging app base data models """ |
2 | 2 | import logging |
3 | | -from typing import Any, List, Type, Union |
| 3 | +from typing import List, Type, Union |
4 | 4 |
|
5 | | -from django.conf import settings |
6 | | -from django.contrib.auth import get_user_model |
7 | 5 | from django.db import models |
8 | 6 | from django.utils.module_loading import import_string |
9 | 7 | from django.utils.translation import gettext_lazy as _ |
@@ -653,240 +651,3 @@ def copy(self, object_tag: "ObjectTag") -> "ObjectTag": |
653 | 651 | self._value = object_tag._value |
654 | 652 | self._name = object_tag._name |
655 | 653 | return self |
656 | | - |
657 | | - |
658 | | -class SystemDefinedTaxonomy(Taxonomy): |
659 | | - """ |
660 | | - Simple subclass of Taxonomy which requires the system_defined flag to be set. |
661 | | - """ |
662 | | - |
663 | | - class Meta: |
664 | | - proxy = True |
665 | | - |
666 | | - def _check_taxonomy(self, object_tag: ObjectTag) -> bool: |
667 | | - """ |
668 | | - Returns True if this is a system defined taxonomy |
669 | | - """ |
670 | | - return super()._check_taxonomy(object_tag) and self.system_defined |
671 | | - |
672 | | - |
673 | | -class ModelObjectTag(ObjectTag): |
674 | | - """ |
675 | | - Model-based ObjectTag, abstract class. |
676 | | -
|
677 | | - Used by ModelSystemDefinedTaxonomy to maintain dynamic Tags which are associated with a configured Model instance. |
678 | | - """ |
679 | | - |
680 | | - class Meta: |
681 | | - proxy = True |
682 | | - |
683 | | - def __init__(self, *args: Any, **kwargs: Any) -> None: |
684 | | - """ |
685 | | - Checks if the `tag_class_model` is correct |
686 | | - """ |
687 | | - assert issubclass(self.tag_class_model, models.Model) |
688 | | - super().__init__(*args, **kwargs) |
689 | | - |
690 | | - @property |
691 | | - def tag_class_model(self) -> Type: |
692 | | - """ |
693 | | - Subclasses must implement this method to return the Django.model |
694 | | - class referenced by these object tags. |
695 | | - """ |
696 | | - raise NotImplementedError |
697 | | - |
698 | | - @property |
699 | | - def tag_class_value(self) -> str: |
700 | | - """ |
701 | | - Returns the name of the tag_class_model field to use as the Tag.value when creating Tags for this taxonomy. |
702 | | -
|
703 | | - Subclasses may override this method to use different fields. |
704 | | - """ |
705 | | - return "pk" |
706 | | - |
707 | | - def get_instance(self) -> Union[models.Model, None]: |
708 | | - """ |
709 | | - Returns the instance of tag_class_model associated with this object tag, or None if not found. |
710 | | - """ |
711 | | - instance_id = self.tag.external_id if self.tag else None |
712 | | - if instance_id: |
713 | | - try: |
714 | | - return self.tag_class_model.objects.get(pk=instance_id) |
715 | | - except self.tag_class_model.DoesNotExist: |
716 | | - log.exception( |
717 | | - f"{self}: {self.tag_class_model.__name__} pk={instance_id} does not exist." |
718 | | - ) |
719 | | - |
720 | | - return None |
721 | | - |
722 | | - def _resync_tag(self) -> bool: |
723 | | - """ |
724 | | - Resync our tag's value with the value from the instance. |
725 | | -
|
726 | | - If the instance associated with the tag no longer exists, we unset our tag, because it's no longer valid. |
727 | | -
|
728 | | - Returns True if the given tag was changed, False otherwise. |
729 | | - """ |
730 | | - instance = self.get_instance() |
731 | | - if instance: |
732 | | - value = getattr(instance, self.tag_class_value) |
733 | | - self.value = value |
734 | | - if self.tag and self.tag.value != value: |
735 | | - self.tag.value = value |
736 | | - self.tag.save() |
737 | | - return True |
738 | | - else: |
739 | | - self.tag = None |
740 | | - |
741 | | - return False |
742 | | - |
743 | | - @property |
744 | | - def tag_ref(self) -> str: |
745 | | - return (self.tag.external_id or self.tag.id) if self.tag_id else self._value |
746 | | - |
747 | | - @tag_ref.setter |
748 | | - def tag_ref(self, tag_ref: str): |
749 | | - """ |
750 | | - Sets the ObjectTag's Tag and/or value, depending on whether a valid Tag is found, or can be created. |
751 | | -
|
752 | | - Creates a Tag for the given tag_ref value, if one containing that external_id not already exist. |
753 | | - """ |
754 | | - self.value = tag_ref |
755 | | - |
756 | | - if self.taxonomy_id: |
757 | | - try: |
758 | | - self.tag = self.taxonomy.tag_set.get( |
759 | | - external_id=tag_ref, |
760 | | - ) |
761 | | - except (ValueError, Tag.DoesNotExist): |
762 | | - # Creates a new Tag for this instance |
763 | | - self.tag = Tag( |
764 | | - taxonomy=self.taxonomy, |
765 | | - external_id=tag_ref, |
766 | | - ) |
767 | | - |
768 | | - self._resync_tag() |
769 | | - |
770 | | - |
771 | | -class ModelSystemDefinedTaxonomy(SystemDefinedTaxonomy): |
772 | | - """ |
773 | | - Model based system taxonomy abstract class. |
774 | | -
|
775 | | - This type of taxonomy has an associated Django model in `tag_class_model()`. |
776 | | - They are designed to create Tags when required for new ObjectTags, to maintain |
777 | | - their status as "closed" taxonomies. |
778 | | - The Tags are representations of the instances of the associated model. |
779 | | -
|
780 | | - Tag.external_id stores an identifier from the instance (`pk` as default) |
781 | | - and Tag.value stores a human readable representation of the instance |
782 | | - (e.g. `username`). |
783 | | - The subclasses can override this behavior, to choose the right field. |
784 | | -
|
785 | | - When an ObjectTag is created with an existing Tag, |
786 | | - the Tag is re-synchronized with its instance. |
787 | | - """ |
788 | | - |
789 | | - class Meta: |
790 | | - proxy = True |
791 | | - |
792 | | - def __init__(self, *args: Any, **kwargs: Any) -> None: |
793 | | - """ |
794 | | - Checks if the `object_tag_class` is a subclass of ModelObjectTag. |
795 | | - """ |
796 | | - assert issubclass(self.object_tag_class, ModelObjectTag) |
797 | | - super().__init__(*args, **kwargs) |
798 | | - |
799 | | - @property |
800 | | - def object_tag_class(self) -> Type: |
801 | | - """ |
802 | | - Returns the ObjectTag subclass associated with this taxonomy. |
803 | | -
|
804 | | - Model Taxonomy subclasses must implement this to provide a ModelObjectTag subclass. |
805 | | - """ |
806 | | - raise NotImplementedError |
807 | | - |
808 | | - |
809 | | -class UserModelObjectTag(ModelObjectTag): |
810 | | - """ |
811 | | - ObjectTags for the UserSystemDefinedTaxonomy. |
812 | | - """ |
813 | | - |
814 | | - class Meta: |
815 | | - proxy = True |
816 | | - |
817 | | - @property |
818 | | - def tag_class_model(self) -> Type: |
819 | | - """ |
820 | | - Associate the user model |
821 | | - """ |
822 | | - return get_user_model() |
823 | | - |
824 | | - @property |
825 | | - def tag_class_value(self) -> str: |
826 | | - """ |
827 | | - Returns the name of the tag_class_model field to use as the Tag.value when creating Tags for this taxonomy. |
828 | | -
|
829 | | - Subclasses may override this method to use different fields. |
830 | | - """ |
831 | | - return "username" |
832 | | - |
833 | | - |
834 | | -class UserSystemDefinedTaxonomy(ModelSystemDefinedTaxonomy): |
835 | | - """ |
836 | | - User based system taxonomy class. |
837 | | - """ |
838 | | - |
839 | | - class Meta: |
840 | | - proxy = True |
841 | | - |
842 | | - @property |
843 | | - def object_tag_class(self) -> Type: |
844 | | - """ |
845 | | - Returns the ObjectTag subclass associated with this taxonomy, which is ModelObjectTag by default. |
846 | | -
|
847 | | - Model Taxonomy subclasses must implement this to provide a ModelObjectTag subclass. |
848 | | - """ |
849 | | - return UserModelObjectTag |
850 | | - |
851 | | - |
852 | | -class LanguageTaxonomy(SystemDefinedTaxonomy): |
853 | | - """ |
854 | | - Language System-defined taxonomy |
855 | | -
|
856 | | - The tags are filtered and validated taking into account the |
857 | | - languages available in Django LANGUAGES settings var |
858 | | - """ |
859 | | - |
860 | | - class Meta: |
861 | | - proxy = True |
862 | | - |
863 | | - def get_tags(self, tag_set: models.QuerySet = None) -> List[Tag]: |
864 | | - """ |
865 | | - Returns a list of all the available Language Tags, annotated with ``depth`` = 0. |
866 | | - """ |
867 | | - available_langs = self._get_available_languages() |
868 | | - tag_set = self.tag_set.filter(external_id__in=available_langs) |
869 | | - return super().get_tags(tag_set=tag_set) |
870 | | - |
871 | | - def _get_available_languages(cls) -> List[str]: |
872 | | - """ |
873 | | - Get available languages from Django LANGUAGE. |
874 | | - """ |
875 | | - langs = set() |
876 | | - for django_lang in settings.LANGUAGES: |
877 | | - # Split to get the language part |
878 | | - langs.add(django_lang[0].split("-")[0]) |
879 | | - return langs |
880 | | - |
881 | | - def _check_valid_language(self, object_tag: ObjectTag) -> bool: |
882 | | - """ |
883 | | - Returns True if the tag is on the available languages |
884 | | - """ |
885 | | - available_langs = self._get_available_languages() |
886 | | - return object_tag.tag.external_id in available_langs |
887 | | - |
888 | | - def _check_tag(self, object_tag: ObjectTag) -> bool: |
889 | | - """ |
890 | | - Returns True if the tag is on the available languages |
891 | | - """ |
892 | | - return super()._check_tag(object_tag) and self._check_valid_language(object_tag) |
0 commit comments