Skip to content

Commit 0c74bb4

Browse files
committed
style: Separating the models into base and system defined
1 parent 8ca16ea commit 0c74bb4

File tree

5 files changed

+530
-498
lines changed

5 files changed

+530
-498
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from .base import (
2+
Tag,
3+
Taxonomy,
4+
ObjectTag,
5+
)
6+
7+
from .system_defined import (
8+
UserSystemDefinedTaxonomy,
9+
LanguageTaxonomy
10+
)

openedx_tagging/core/tagging/models.py renamed to openedx_tagging/core/tagging/models/base.py

Lines changed: 2 additions & 241 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
""" Tagging app data models """
1+
""" Tagging app base data models """
22
import logging
3-
from typing import Any, List, Type, Union
3+
from typing import List, Type, Union
44

5-
from django.conf import settings
6-
from django.contrib.auth import get_user_model
75
from django.db import models
86
from django.utils.module_loading import import_string
97
from django.utils.translation import gettext_lazy as _
@@ -653,240 +651,3 @@ def copy(self, object_tag: "ObjectTag") -> "ObjectTag":
653651
self._value = object_tag._value
654652
self._name = object_tag._name
655653
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

Comments
 (0)