Commit 77cce1b1 authored by Florent Chehab's avatar Florent Chehab
Browse files

feat(backend): refactor/cleaned/ infer get_serializer

* Cleaned all init files
* Infer the serializer from the model instead of having it in the models
* Updated the doc accordingly
* Fixed typos

Fixes #93
Fixes #85
parent cb86531b
...@@ -2,20 +2,12 @@ from django.contrib import admin ...@@ -2,20 +2,12 @@ from django.contrib import admin
from reversion_compare.admin import CompareVersionAdmin from reversion_compare.admin import CompareVersionAdmin
from backend_app.config.models import get_models from backend_app.config.models import get_models
from backend_app.checks import check_classic_models, check_versionned_models
# We need to register testing models, otherwise we won't be able to test properly, # We need to register testing models, otherwise we won't be able to test properly,
# Since no migrations would privide those models. # Since no migrations would privide those models.
# So don't put requires_testing=True # So don't put requires_testing=True
VERSIONED_MODELS = get_models(versionned=True) # , requires_testing=False) VERSIONED_MODELS = get_models(versioned=True) # , requires_testing=False)
CLASSIC_MODELS = get_models(versionned=False) # , requires_testing=False) CLASSIC_MODELS = get_models(versioned=False) # , requires_testing=False)
#######
# Perform some dynamic checks
#######
check_classic_models(CLASSIC_MODELS)
check_versionned_models(VERSIONED_MODELS)
####### #######
# Register the models # Register the models
......
def check_classic_models(classic_models): from collections import Counter
def check_viewsets(viewsets):
""" """
Check that all "classic" models don't have a `get_serializer` method: Check that if 2 serializers are registered for the same model. Then that model
they don't need it. has a get_serializer method to point to the serializer to use to deserialize it.
See doc for more information: There should be only one of serializer being used per model. Otherwise extra
configuration is required.
http://localhost:5000/#/Application/Backend/models_serializers_viewsets http://localhost:5000/#/Application/Backend/models_serializers_viewsets
""" """
for Model in classic_models: # Prevent cyclic imports
try: from backend_app.models.abstract.versionedEssentialModule import (
# Check that it doesn't have the get_serializer method VersionedEssentialModule,
Model.get_serializer()
raise Exception(
"A 'CLASSIC MODEL' SHOULDN'T have the "
"get_serializer method, {}".format(Model)
) )
except AttributeError:
pass
serializers = list()
models = []
for viewset in viewsets:
serializer = viewset().get_serializer_class()
model = serializer.Meta.model
def check_versionned_models(versionned_models): if issubclass(model, VersionedEssentialModule):
""" if serializer not in serializers:
Check that all "versionned" models have a `get_serializer` method. serializers.append(serializer)
See doc for more information: models.append(model)
http://localhost:5000/#/Application/Backend/models_serializers_viewsets
""" models = dict(Counter(models))
for Model in versionned_models: for model, n in models.items():
if n > 1:
try:
# Check that the model has a get_serializer method
model.get_serializer()
# Check that it has a get_serializer method except AttributeError:
if Model.get_serializer().Meta.model != Model: raise Exception(
raise Exception("Get_serializer configuration incorrect in", str(Model)) "The model {} has multiple serializers pointing to it. "
"In such case, you must define the get_serializer method inside the model. "
"Have a look at the documentation.".format(model)
)
...@@ -10,7 +10,7 @@ from .utils import load_viewsets_config ...@@ -10,7 +10,7 @@ from .utils import load_viewsets_config
def get_models( def get_models(
versionned: Optional[bool] = None, versioned: Optional[bool] = None,
requires_testing: Union[None, bool, "smart"] = None, requires_testing: Union[None, bool, "smart"] = None,
) -> List[object]: ) -> List[object]:
""" """
...@@ -51,10 +51,10 @@ def get_models( ...@@ -51,10 +51,10 @@ def get_models(
continue continue
Model = Viewset.serializer_class.Meta.model Model = Viewset.serializer_class.Meta.model
if versionned is not None: if versioned is not None:
if versionned and not issubclass(Model, VersionedEssentialModule): if versioned and not issubclass(Model, VersionedEssentialModule):
continue continue
if not versionned and issubclass(Model, VersionedEssentialModule): if not versioned and issubclass(Model, VersionedEssentialModule):
continue continue
out.append(Model) out.append(Model)
......
# We firest need to define ASSETS_PATH to prevent cyclic imports
from os import path
ASSETS_PATH = path.join(path.realpath(__file__), "../assets/") # noqa: E402
from .load_all import load_all # noqa: E402
__all__ = ["load_all", "ASSETS_PATH"]
import reversion import reversion
from .loading_scripts import ( from backend_app.load_data.loading_scripts.loadAdminUser import LoadAdminUser
LoadAdminUser, from backend_app.load_data.loading_scripts.loadCountries import LoadCountries
LoadCountries, from backend_app.load_data.loading_scripts.loadCurrencies import LoadCurrencies
LoadCurrencies, from backend_app.load_data.loading_scripts.loadGroups import LoadGroups
LoadGroups, from backend_app.load_data.loading_scripts.loadTags import LoadTags
LoadTags, from backend_app.load_data.loading_scripts.loadUniversities import LoadUniversities
LoadUniversities, from backend_app.load_data.loading_scripts.loadUniversityEx import LoadUniversityEx
LoadUniversityEx,
)
def load_all(): def load_all():
"""Function to load all the initial data in the app """
Function to load all the initial data in the app
""" """
with reversion.create_revision(): with reversion.create_revision():
......
from .loadGroups import LoadGroups
from .loadAdminUser import LoadAdminUser
from .loadCountries import LoadCountries
from .loadUniversities import LoadUniversities
from .loadTags import LoadTags
from .loadCurrencies import LoadCurrencies
from .loadUniversityEx import LoadUniversityEx
__all__ = [
"LoadGroups",
"LoadAdminUser",
"LoadCountries",
"LoadUniversities",
"LoadTags",
"LoadCurrencies",
"LoadUniversityEx",
]
from os.path import abspath, join from os.path import abspath, join
import pandas as pd import pandas as pd
from backend_app.load_data import ASSETS_PATH from backend_app.load_data.shared import ASSETS_PATH
from backend_app.models.country import Country from backend_app.models.country import Country
from base_app.models import User from base_app.models import User
......
...@@ -2,7 +2,7 @@ import csv ...@@ -2,7 +2,7 @@ import csv
from decimal import Decimal from decimal import Decimal
from os.path import abspath, join from os.path import abspath, join
from backend_app.load_data import ASSETS_PATH from backend_app.load_data.shared import ASSETS_PATH
from backend_app.models.currency import Currency from backend_app.models.currency import Currency
from base_app.models import User from base_app.models import User
......
from os.path import abspath, join from os.path import abspath, join
import pandas as pd import pandas as pd
from backend_app.load_data import ASSETS_PATH from backend_app.load_data.shared import ASSETS_PATH
from backend_app.models.campus import Campus from backend_app.models.campus import Campus
from backend_app.models.city import City from backend_app.models.city import City
from backend_app.models.country import Country from backend_app.models.country import Country
......
from os import path
ASSETS_PATH = path.join(path.realpath(__file__), "../assets/") # noqa: E402
SEMESTER_OPTIONS = (("a", "autumn"), ("p", "spring"))
__all__ = ["SEMESTER_OPTIONS"]
...@@ -6,8 +6,8 @@ from backend_app.models.abstract.versionedEssentialModule import ( ...@@ -6,8 +6,8 @@ from backend_app.models.abstract.versionedEssentialModule import (
VersionedEssentialModuleSerializer, VersionedEssentialModuleSerializer,
VersionedEssentialModuleViewSet, VersionedEssentialModuleViewSet,
) )
from backend_app.validators.tag import validate_content_against_config from backend_app.validators.tags import validate_content_against_config
from backend_app.validators.tag.tags_config import USEFULL_LINKS_CONFIG from backend_app.validators.tags_config.useful_links import USEFULL_LINKS_CONFIG
IMPORTANCE_LEVEL = (("-", "normal"), ("+", "important"), ("++", "IMPORTANT")) IMPORTANCE_LEVEL = (("-", "normal"), ("+", "important"), ("++", "IMPORTANT"))
...@@ -19,7 +19,7 @@ class Module(VersionedEssentialModule): ...@@ -19,7 +19,7 @@ class Module(VersionedEssentialModule):
Those field will be inherited. Those field will be inherited.
All Basic modules are also "versionned" modules All Basic modules are also "versioned" modules
""" """
title = models.CharField(default="", blank=True, max_length=150) title = models.CharField(default="", blank=True, max_length=150)
......
...@@ -3,7 +3,7 @@ from django.db import models ...@@ -3,7 +3,7 @@ from django.db import models
from backend_app.fields import JSONField from backend_app.fields import JSONField
from backend_app.models.abstract.module import Module, ModuleSerializer, ModuleViewSet from backend_app.models.abstract.module import Module, ModuleSerializer, ModuleViewSet
from backend_app.models.tag import Tag from backend_app.models.tag import Tag
from backend_app.validators.tag import tagged_item_validation from backend_app.validators.tags import tagged_item_validation
class TaggedItem(Module): class TaggedItem(Module):
......
...@@ -13,21 +13,12 @@ from reversion.models import Version ...@@ -13,21 +13,12 @@ from reversion.models import Version
class VersionedEssentialModule(EssentialModule): class VersionedEssentialModule(EssentialModule):
""" """
Custom EssentialModule that will be versionned in the app Custom EssentialModule that will be versioned in the app
""" """
# We store the current number of versions for better performance # We store the current number of versions for better performance
nb_versions = models.PositiveIntegerField(default=0) nb_versions = models.PositiveIntegerField(default=0)
@classmethod
def get_serializer(cls):
"""
This function is required for handling
versioning easily.
You have to put the correct value in each subclass
"""
raise Exception("Get_serializer must be redefined in subclass")
def delete(self, using=None, keep_parents=False): def delete(self, using=None, keep_parents=False):
""" """
Override the default delete behavior to make sure Override the default delete behavior to make sure
...@@ -44,7 +35,7 @@ class VersionedEssentialModule(EssentialModule): ...@@ -44,7 +35,7 @@ class VersionedEssentialModule(EssentialModule):
class VersionedEssentialModuleSerializer(EssentialModuleSerializer): class VersionedEssentialModuleSerializer(EssentialModuleSerializer):
""" """
Serializer for versionned models Serializer for versioned models
""" """
# Add a nb_versions field # Add a nb_versions field
...@@ -64,7 +55,7 @@ class VersionedEssentialModuleSerializer(EssentialModuleSerializer): ...@@ -64,7 +55,7 @@ class VersionedEssentialModuleSerializer(EssentialModuleSerializer):
class VersionedEssentialModuleViewSet(EssentialModuleViewSet): class VersionedEssentialModuleViewSet(EssentialModuleViewSet):
""" """
Viewset for the versionned models Viewset for the versioned models
""" """
serializer_class = VersionedEssentialModuleSerializer serializer_class = VersionedEssentialModuleSerializer
...@@ -32,10 +32,6 @@ class Campus(Module): ...@@ -32,10 +32,6 @@ class Campus(Module):
def location(self): def location(self):
return {"lat": self.lat, "lon": self.lon} return {"lat": self.lat, "lon": self.lon}
@classmethod
def get_serializer(cls):
return CampusSerializer
class Meta: class Meta:
unique_together = ("is_main_campus", "university") unique_together = ("is_main_campus", "university")
......
...@@ -13,10 +13,6 @@ class CampusTaggedItem(TaggedItem): ...@@ -13,10 +13,6 @@ class CampusTaggedItem(TaggedItem):
Campus, on_delete=models.PROTECT, related_name="campus_tagged_items" Campus, on_delete=models.PROTECT, related_name="campus_tagged_items"
) )
@classmethod
def get_serializer(cls):
return CampusTaggedItemSerializer
class Meta: class Meta:
unique_together = ("campus", "tag", "importance_level") unique_together = ("campus", "tag", "importance_level")
......
...@@ -13,10 +13,6 @@ class CityTaggedItem(TaggedItem): ...@@ -13,10 +13,6 @@ class CityTaggedItem(TaggedItem):
City, on_delete=models.PROTECT, related_name="city_tagged_items" City, on_delete=models.PROTECT, related_name="city_tagged_items"
) )
@classmethod
def get_serializer(cls):
return CityTaggedItemSerializer
class Meta: class Meta:
unique_together = ("city", "tag", "importance_level") unique_together = ("city", "tag", "importance_level")
......
...@@ -7,10 +7,6 @@ class CountryDri(Module): ...@@ -7,10 +7,6 @@ class CountryDri(Module):
countries = models.ManyToManyField(Country, related_name="country_dri") countries = models.ManyToManyField(Country, related_name="country_dri")
@classmethod
def get_serializer(cls):
return CountryDriSerializer
class CountryDriSerializer(ModuleSerializer): class CountryDriSerializer(ModuleSerializer):
class Meta: class Meta:
......
...@@ -11,10 +11,6 @@ class CountryScholarship(Scholarship): ...@@ -11,10 +11,6 @@ class CountryScholarship(Scholarship):
countries = models.ManyToManyField(Country, related_name="country_scholarships") countries = models.ManyToManyField(Country, related_name="country_scholarships")
@classmethod
def get_serializer(cls):
return CountryScholarshipSerializer
class CountryScholarshipSerializer(ScholarshipSerializer): class CountryScholarshipSerializer(ScholarshipSerializer):
class Meta: class Meta:
......
...@@ -13,10 +13,6 @@ class CountryTaggedItem(TaggedItem): ...@@ -13,10 +13,6 @@ class CountryTaggedItem(TaggedItem):
Country, on_delete=models.PROTECT, related_name="country_tagged_items" Country, on_delete=models.PROTECT, related_name="country_tagged_items"
) )
@classmethod
def get_serializer(cls):
return CountryTaggedItemSerializer
class Meta: class Meta:
unique_together = ("country", "tag", "importance_level") unique_together = ("country", "tag", "importance_level")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment