From a4fef4c08d80bafcd2251d116467070fab566210 Mon Sep 17 00:00:00 2001 From: Samy Saad Date: Wed, 20 Sep 2023 14:57:39 +0200 Subject: [PATCH 1/2] [CHG #4942172] Modify firm_info tag - Add address parts as context variables in simple_tag - Rename `address` context variable to `fill_address` --- firm_info/serializers.py | 12 ++++++++++-- .../templatetags/firm_info/test_firm_contact.html | 6 +++++- tests/conftest.py | 6 +++++- tests/templatetags.py | 6 +++++- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/firm_info/serializers.py b/firm_info/serializers.py index ba54130..8d8daa5 100644 --- a/firm_info/serializers.py +++ b/firm_info/serializers.py @@ -34,7 +34,11 @@ def serialize_firm_info(queryset): { "email": "email@mail.com", "phone": "003369856321", - "address": "1 avenue Charles de Gaulle, 99999 Paris" + "full_address": "1 avenue Charles de Gaulle, 99999 Paris France", + "address": "1 avenue Charles de Gaulle", + "postal_code": "99999", + "city": "Paris", + "country": "France", } ``` """ @@ -45,7 +49,11 @@ def serialize_firm_info(queryset): return { "email": firm_info.get("email"), "phone": firm_info.get("phone_number"), - "address": _format_address(firm_info), + "full_address": _format_address(firm_info), + "address": firm_info.get("address"), + "postal_code": firm_info.get("postal_code"), + "city": firm_info.get("city"), + "country": firm_info.get("country"), } except Exception as err: raise SerializeFirmError from err diff --git a/firm_info/templates/tests/templatetags/firm_info/test_firm_contact.html b/firm_info/templates/tests/templatetags/firm_info/test_firm_contact.html index d322159..54c07ea 100644 --- a/firm_info/templates/tests/templatetags/firm_info/test_firm_contact.html +++ b/firm_info/templates/tests/templatetags/firm_info/test_firm_contact.html @@ -1,3 +1,7 @@

Email: {{ email }}

Phone: {{ phone }}

-

Address: {{ address }}

\ No newline at end of file +

Full address: {{ full_address }}

+

Address: {{ address }}

+

city: {{ city }}

+

postal code: {{ postal_code }}

+

country: {{ country }}

\ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index bec6fa3..8df74d7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -29,7 +29,11 @@ def serialized_contact(): return { "email": "contact@example.com", "phone": "1234567890", - "address": "1234 Main St, 12345 Anytown USA" + 'address': '1234 Main St', + 'city': 'Anytown', + 'country': 'USA', + 'full_address': '1234 Main St, 12345 Anytown USA', + 'postal_code': '12345', } diff --git a/tests/templatetags.py b/tests/templatetags.py index 0a918d5..09cf19d 100644 --- a/tests/templatetags.py +++ b/tests/templatetags.py @@ -20,7 +20,11 @@ def test_firm_contact_tag(db, firm_contact_obj, serialized_contact): expected_output = "\n".join([ f"

Email: {serialized_contact['email']}

", f"

Phone: {serialized_contact['phone']}

", - f"

Address: {serialized_contact['address']}

" + f"

Full address: {serialized_contact['full_address']}

", + f"

Address: {serialized_contact['address']}

", + f"

city: {serialized_contact['city']}

", + f"

postal code: {serialized_contact['postal_code']}

", + f"

country: {serialized_contact['country']}

" ]) assert rendered == expected_output From a135558940837bd8ba99a6bb951e4ce2525e7b03 Mon Sep 17 00:00:00 2001 From: Samy Saad Date: Thu, 21 Sep 2023 15:58:18 +0200 Subject: [PATCH 2/2] [DOC] Add models, templatetags and serializers doc --- docs/django_app/models.rst | 13 --- docs/{django_app => firm_info}/index.rst | 8 +- docs/firm_info/models.rst | 9 ++ docs/firm_info/serializers.rst | 9 ++ docs/firm_info/templatetags.rst | 9 ++ docs/index.rst | 2 +- firm_info/models.py | 62 ++++++++++ firm_info/serializers.py | 138 ++++++++++++----------- firm_info/templatetags/firm_info.py | 137 ++++++++++++++-------- 9 files changed, 259 insertions(+), 128 deletions(-) delete mode 100644 docs/django_app/models.rst rename docs/{django_app => firm_info}/index.rst (51%) create mode 100644 docs/firm_info/models.rst create mode 100644 docs/firm_info/serializers.rst create mode 100644 docs/firm_info/templatetags.rst diff --git a/docs/django_app/models.rst b/docs/django_app/models.rst deleted file mode 100644 index bddfceb..0000000 --- a/docs/django_app/models.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _intro_django-app_models: - -====== -Models -====== - -.. automodule:: firm_info.models.blog - :members: Blog - :exclude-members: DoesNotExist, MultipleObjectsReturned - -.. automodule:: firm_info.models.article - :members: Article - :exclude-members: DoesNotExist, MultipleObjectsReturned diff --git a/docs/django_app/index.rst b/docs/firm_info/index.rst similarity index 51% rename from docs/django_app/index.rst rename to docs/firm_info/index.rst index c31cfc0..7746d92 100644 --- a/docs/django_app/index.rst +++ b/docs/firm_info/index.rst @@ -1,10 +1,14 @@ -.. _intro_django-app: +.. _intro_firm-info: ================== -Django application +Django firm info ================== .. toctree:: :maxdepth: 2 models.rst + + serializers.rst + + templatetags.rst diff --git a/docs/firm_info/models.rst b/docs/firm_info/models.rst new file mode 100644 index 0000000..b389c55 --- /dev/null +++ b/docs/firm_info/models.rst @@ -0,0 +1,9 @@ +.. _intro_firm-info_models: + +====== +Models +====== + +.. automodule:: firm_info.models + :members: FirmContact, Link, SocialSharing, Tracking, AppsBanner, + :exclude-members: DoesNotExist, MultipleObjectsReturned diff --git a/docs/firm_info/serializers.rst b/docs/firm_info/serializers.rst new file mode 100644 index 0000000..ab8b98a --- /dev/null +++ b/docs/firm_info/serializers.rst @@ -0,0 +1,9 @@ +.. _intro_firm-info_serializers: + +=========== +Serializers +=========== + +.. automodule:: firm_info.serializers + :members: SerializeFirmError, _format_address, serialize_firm_info, serialize_firm_social, serialize_firm_description, serialize_firm_social_sharing, serialize_firm_apps_banner + :exclude-members: DoesNotExist, MultipleObjectsReturned \ No newline at end of file diff --git a/docs/firm_info/templatetags.rst b/docs/firm_info/templatetags.rst new file mode 100644 index 0000000..eeb7894 --- /dev/null +++ b/docs/firm_info/templatetags.rst @@ -0,0 +1,9 @@ +.. _intro_firm-info_templatetags: + +============ +Templatetags +============ + +.. automodule:: firm_info.templatetags.firm_info + :members: firm_contact, firm_social_links, firm_description, firm_logos, firm_social_shares, firm_tag_analytic, app_banner + :exclude-members: DoesNotExist, MultipleObjectsReturned \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 5c5947c..4e42237 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,7 +8,7 @@ User’s Guide :maxdepth: 2 install.rst - django_app/index.rst + firm_info/index.rst Developer’s Guide diff --git a/firm_info/models.py b/firm_info/models.py index 698d07b..fb4ee00 100644 --- a/firm_info/models.py +++ b/firm_info/models.py @@ -8,6 +8,26 @@ class FirmContact(models.Model): + """ + Represents the contact information for a firm. + + Args: + models.Model: The base model class provided by Django. + + Attributes: + phone_number (CharField): The phone number of the firm. + email (EmailField): The email address of the firm. + address (CharField): The address of the firm. + postal_code (CharField): The postal code of the firm. + city (CharField): The city of the firm. + country (CharField): The country of the firm. + baseline (CharField): The baseline of the firm. + short_description (TextField): The short description of the firm. + logo (SmartMediaField): The logo of the firm. + logo_invert (SmartMediaField): The inverted logo of the firm. + favicon (SmartMediaField): The favicon of the firm. + objects (SingletonManager): The manager for the FirmContact model. + """ phone_number = models.CharField(max_length=20, null=False, blank=True, default="") email = models.EmailField(null=False, blank=True, default="") address = models.CharField(max_length=255, null=False, blank=True, default="") @@ -61,6 +81,17 @@ def __str__(self): class Link(models.Model): + """ + Represents a social network link. + + Attributes: + SOCIAL_NETWORK_NAMES (tuple): Choices for the name field representing + various social network names. + name (CharField): The name of the social network. + url (URLField): The URL of the social network link. + client_contact (ForeignKey): The foreign key to the FirmContact model + representing the client contact. + """ SOCIAL_NETWORK_NAMES = ( ("linkedin", "linkedin"), ("facebook", "facebook"), @@ -93,6 +124,15 @@ class Meta: class SocialSharing(models.Model): + """ + Represents social media sharing information. + + Attributes: + og_image (SmartMediaField): The OG image for social media sharing. + og_description (TextField): The OG description for social media sharing. + og_twitter_site (CharField): The OG Twitter site for social media sharing. + """ + og_image = SmartMediaField( _("OG Image"), null=True, @@ -135,6 +175,13 @@ class Meta: class Tracking(models.Model): + """ + Represents tracking information. + + Attributes: + tag_analytic (CharField): The tag analytic for tracking. + """ + tag_analytic = models.CharField( max_length=100, null=False, @@ -149,6 +196,21 @@ class Meta: class AppsBanner(models.Model): + """ + Represents an app banner in the Django firm_info models. + + Args: + models.Model: The base model class provided by Django. + + Attributes: + APPS_CHOICES (list): A list of tuples representing the available choices for + the application type. + application_type (models.CharField): The type of the application. + image (SmartMediaField): The image associated with the app banner. + title (models.CharField): The title of the app banner. + description (HTMLField): The description of the app banner. + """ + APPS_CHOICES = [ ("application_sent", _("Application sent")), ("free_apply", _("Free apply")), diff --git a/firm_info/serializers.py b/firm_info/serializers.py index 8d8daa5..9e211c2 100644 --- a/firm_info/serializers.py +++ b/firm_info/serializers.py @@ -1,12 +1,23 @@ class SerializeFirmError(Exception): - """ - Custom exception to handle errors during Firm informations serialization. - """ - pass def _format_address(firm_info: dict) -> str: + """ + Formats the address using the firm information. + + Args: + firm_info (dict): The firm information with the following keys: + + - "address": The address of the firm. + - "postal_code": The postal code of the firm. + - "city": The city of the firm. + - "country": The country of the firm. + + Returns: + str: The formatted address string in the format + `"{address}, {postal_code} {city} {country}"`. + """ return "{}, {} {} {}".format( firm_info.get("address"), firm_info.get("postal_code"), @@ -17,31 +28,26 @@ def _format_address(firm_info: dict) -> str: def serialize_firm_info(queryset): """ - Serialize FirmContact unique instance. - + Serializes the firm information from a queryset. Args: - `FirmContact` Queryset - - Raises: - SerializeFirmError + queryset: The queryset containing the firm information. Returns: - (dict): email phone and address of firm as serialized data - - Sample: - ``` - { - "email": "email@mail.com", - "phone": "003369856321", - "full_address": "1 avenue Charles de Gaulle, 99999 Paris France", - "address": "1 avenue Charles de Gaulle", - "postal_code": "99999", - "city": "Paris", - "country": "France", - } - ``` + dict: the serialized firm information with the following keys: + + - "email": The email address of the firm. + - "phone": The phone number of the firm. + - "full_address": The formatted full address of the firm. + - "address": The address of the firm. + - "postal_code": The postal code of the firm. + - "city": The city of the firm. + - "country": The country of the firm. + + Raises: + SerializeFirmError: Raised when an error occurs during serialization. """ + try: firm_info = queryset.values( "phone_number", "email", "address", "postal_code", "city", "country" @@ -61,25 +67,19 @@ def serialize_firm_info(queryset): def serialize_firm_social(queryset): """ - Serialize Firm social networks urls. + Serializes the firm social media information from a queryset. Args: - `Link` Queryset - - Raises: - SerializeFirmError + queryset: The queryset containing the firm social media information. Returns: - (dict): social network name as dict key, url as dict value. + dict: The serialized firm social media information with the social media names + as keys and their corresponding URLs as values. - Sample: - ```python - { - "facebook": "www.site.com", - "instagram": "www.site2.com" - } - ``` + Raises: + SerializeFirmError: Raised when an error occurs during serialization. """ + try: firm_socials = list( queryset.values( @@ -97,25 +97,19 @@ def serialize_firm_social(queryset): def serialize_firm_description(queryset): """ - Serialize FirmContact unique instance. - + Serializes the firm description from a queryset. Args: - `FirmContact` Queryset - - Raises: - SerializeFirmError + queryset: The queryset containing the firm description. Returns: - (dict): baseline and short_description of firm as serialized data + dict: The serialized firm description with the following keys: - Sample: - ``` - { - "baseline": "Non eram nescius, Brute, cum, quae summis ingeniis", - "short_description": "Quamquam, si plane sic verterem Platonem" - } - ``` + - "baseline": The baseline of the firm. + - "short_description": The short description of the firm. + + Raises: + SerializeFirmError: Raised when an error occurs during serialization. """ try: firm_info = queryset.values("baseline", "short_description").first() @@ -129,25 +123,20 @@ def serialize_firm_description(queryset): def serialize_firm_social_sharing(obj): """ - Serialize Firm social networks sharing urls. + Serialize Firm social networks sharing URLs. Args: - `SocialSharing` Queryset - - Raises: - SerializeFirmError + obj (QuerySet): The `SocialSharing` queryset. Returns: - (dict): og_image, og_description and og_twitter_site as serialized data - - Sample: - ```python - { - "og_image": SmartMediaField(), - "og_description": TextField(), - "og_twitter_site": CharField(), - } - ``` + dict: The serialized data with the following keys: + + - og_image (SmartMediaField): The OG image for social media sharing. + - og_description (TextField): The OG description for social media sharing. + - og_twitter_site (CharField): The OG Twitter site for social media sharing. + + Raises: + SerializeFirmError: Raised when an error occurs during serialization. """ try: @@ -162,6 +151,23 @@ def serialize_firm_social_sharing(obj): def serialize_firm_apps_banner(obj): + """ + Serializes an instance of the AppsBanner model into a dictionary. + + Args: + obj: The AppsBanner object to be serialized. + + Returns: + dict: The serialized data with the following keys: + + - "title": The title of the `AppsBanner`. + - "description": The description of the AppsBanner. + - "image": The image associated with the AppsBanner. + + Raises: + SerializeFirmError: Raised when an error occurs during serialization. +""" + try: return { "title": obj.title, diff --git a/firm_info/templatetags/firm_info.py b/firm_info/templatetags/firm_info.py index 1d17755..32eacfa 100644 --- a/firm_info/templatetags/firm_info.py +++ b/firm_info/templatetags/firm_info.py @@ -1,3 +1,4 @@ +import contextlib from django.core.exceptions import ObjectDoesNotExist from django.template import Library, loader from firm_info.models import AppsBanner, FirmContact, Link, SocialSharing, Tracking @@ -18,31 +19,19 @@ def firm_contact(template_path): Renders the template which path is provided as param using FirmContact only instance serialized contact data. - - Usage: + Args: + template_path (str): The path to the template file. - ```html - {% load firm_info %} + Returns: + str: The rendered HTML output of the firm contact informations. - {% firm_contact "path/to/template.html" %} - ``` - - - Improvement: + Usage: - Could use a cached template loader instead of loader.get_template() + .. code-block:: html - ```python - from django.core.cache import cache + {% load firm_info %} + {% firm_contact "path/to/template.html" %} - template_cache_key = f'firm_contact_template_{template_path}' - template = cache.get(template_cache_key) - if template is None: - cache.set(...) - contact_cache_key = f'firm_contact_info' - contact = cache.get(contact_cache_key) - if contact is None: - contact = FirmContact.objects.first() - cache.set(...) - ``` """ qs_firm_info = FirmContact.objects.all() if qs_firm_info.exists(): @@ -61,13 +50,19 @@ def firm_social_links(template_path): using all social network link objects serialized data related the only FirmContact instance. + Args: + template_path (str): The path to the template file. + + Returns: + str: The rendered HTML output of the firm social networks links. + Usage: - ``` - html - {% load firm_info %} - {% firm_social_links "path/to/template.html" %} - ``` + .. code-block:: html + + {% load firm_info %} + {% firm_social_links "path/to/template.html" %} + """ links = Link.objects.all() if links.exists(): @@ -85,13 +80,19 @@ def firm_description(template_path): Renders the template which path is provided as param using FirmContact only instance serialized description data. + Args: + template_path (str): The path to the template file. + + Returns: + str: The rendered HTML output of the firm description. + Usage: - ``` - html - {% load firm_info %} - {% firm_description "path/to/template.html" %} - ``` + .. code-block:: html + + {% load firm_info %} + {% firm_description "path/to/template.html" %} + """ qs_firm_info = FirmContact.objects.all() if qs_firm_info.exists(): @@ -106,16 +107,21 @@ def firm_description(template_path): @register.simple_tag(name="firm_logos") def firm_logos(template_path): """ - Renders the template which path is provided as param - using Firm logos. + Renders the firm logos using the specified template. + + Args: + template_path (str): The path to the template file. + + Returns: + str: The rendered HTML output of the firm logos. Usage: - ``` - html - {% load firm_info %} - {% firm_logos "path/to/template.html" %} - ``` + .. code-block:: html + + {% load firm_info %} + {% firm_logos "path/to/template.html" %} + """ firm_instance = FirmContact.objects.first() if firm_instance: @@ -138,13 +144,19 @@ def firm_social_shares(template_path): using all social network shares link objects serialized data related the only SocialSharing instance. + Args: + template_path (str): The path to the template file. + + Returns: + str: The rendered HTML output of the firm social media shares. + Usage: - ``` - html - {% load firm_info %} - {% firm_social_shares "path/to/template.html" %} - ``` + .. code-block:: html + + {% load firm_info %} + {% firm_social_shares "path/to/template.html" %} + """ social_shares = SocialSharing.objects.first() @@ -160,20 +172,53 @@ def firm_social_shares(template_path): @register.filter("firm_tag_analytic") def firm_tag_analytic(value=None): + """ + Filters the firm tag analytic value. + + Args: + value: The input value (not used). + + Returns: + str: The tag analytic value from the first Tracking object if it exists, + otherwise an empty string. + + Usage: + + .. code-block:: html + + {% load firm_info %} + {% firm_tag_analytic "path/to/template.html" %} + + """ return Tracking.objects.first().tag_analytic if Tracking.objects.exists() else "" @register.simple_tag(name="app_banner") def app_banner(app_type, template_path): + """ + Renders the app banner using the specified template and application type. + + Args: + app_type (str): The application type. + template_path (str): The path to the template file. + + Returns: + str: The rendered HTML output of the app banner. + + Usage: + + .. code-block:: html + + {% load firm_info %} + {% app_banner "path/to/template.html" %} + + """ context = {} template = loader.get_template(template_path) - try: + with contextlib.suppress(ObjectDoesNotExist): app_banner = AppsBanner.objects.get(application_type=app_type) context = serialize_firm_apps_banner(app_banner) - except ObjectDoesNotExist: - pass - rendered = template.render(context) return rendered