{"id":929,"date":"2024-03-25T13:44:17","date_gmt":"2024-03-25T13:44:17","guid":{"rendered":"https:\/\/codenerix.com\/?p=929\/"},"modified":"2025-02-10T05:16:37","modified_gmt":"2025-02-10T05:16:37","slug":"unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide","status":"publish","type":"post","link":"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/","title":{"rendered":"Unlocking Advanced Data Transformation in Django CODENERIX: A Complete Guide"},"content":{"rendered":"\n<p>In this guide, we will cover how to transform data or produce new data by calculating existing data, and we will go through the process of building our widgets using AngularJS for a ModelForm. Some of the ways explained here will follow the standard <strong>Django<\/strong> way of doing things, while others will follow the <strong><a href=\"https:\/\/github.com\/codenerix\/django-codenerix\"><span style=\"color: #343433;\">CODE<\/span><span style=\"color: #70a8e0;\">NERIX<\/span><\/a><\/strong>\u00a0way.<\/p>\n\n\n\n<p>When the software grows and matures, we usually need to customize some things better and add newer features over the existing ones. One of the most basic needs is data generation from other fields or data transformation while saving the information in the database.<\/p>\n\n\n\n<p>Producing new data over existing ones is usually a straightforward step. Let&#8217;s explore it travelling from the server (backed) to the user (frontend):<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Overloading the save() method in your model<\/h2>\n\n\n\n<p>This is a pretty straightforward <strong>backend solution<\/strong> solution. In your model, you create a new save() method that calls to super().save(). This can be done in two ways:<\/p>\n\n\n\n<p>The first one is by modifying data before it gets written to the database:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"3\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">self save(self):\n  # Use existing data to setup the custom field\n  self.custom_field = modifier(self.existing_fields)\n  # Save and return returned data to keep consistency\n  return super().save()<\/pre>\n\n\n\n<p>The second one is by modifying data and saving it again; in this way, you can pick up the PK from the object after calling <strong>super().save()<\/strong> and use it to recalculate it. (<strong><span style=\"text-decoration: underline;\">NOTE:<\/span><\/strong> if you have to save twice in your <strong>save()<\/strong> method, it usually means what you are doing is not a good idea)<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"5\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">self save(self):\n  # Save existing data\n  super().save()\n  # Calculate seed based on the regiter's PK\n  self.seed = create_seed_based_on_register_pk(self.pk)\n  # Save it again and return returned data to keep consistency\n  return super().save()<\/pre>\n\n\n\n<p>The third method extends the second one by modifying other models&#8217; data after this one is written to the database. This way, we can pick up the <strong>PK<\/strong> from the object after calling super().save() and use it with the other model. A common example of this could be to add the just created object into an existing <strong>ManyToMany<\/strong> relationship:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"7\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">self save(self):\n  # Save existing data\n  answer = super().save()\n  # Lookup for the other object\n  other = OtherModel.objects.filter(...).first()\n  # Add our selves into the relationship\n  other.custom_related_field.add(self)\n  # Answer back keeping consistency between calls\n  return answer<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">2. Using Django signals<\/h2>\n\n\n\n<p>This is a <strong>backend solution<\/strong> based on something that Django implements called <strong>signals<\/strong>. They are a great tool in complex scenarios, but keep in mind that they make the code harder to maintain, and those should be used only in situations where the other methods wouldn&#8217;t work. Read directly from <strong>Django&#8217;s<\/strong> documentation how to use <strong>signals<\/strong>.\u00a0<a href=\"https:\/\/docs.djangoproject.com\/en\/5.0\/ref\/signals\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/docs.djangoproject.com\/en\/5.0\/ref\/signals\/<\/a><\/p>\n\n\n\n<p><strong>Signals<\/strong> can be incredibly useful in complex scenarios where different components need to react to events or actions in a decoupled manner. For example, you might want to trigger specific actions whenever a new user registers, a post is created, or an order is placed.<\/p>\n\n\n\n<p><strong>Signals<\/strong> introduce an element of indirection in your code, making it harder to follow the control flow. Since signals allow disparate parts of your application to interact, tracing the logic executed when a signal is triggered can sometimes be challenging. This can lead to difficulties in debugging and maintaining the codebase, especially as the application grows in complexity.<\/p>\n\n\n\n<p>Example of <strong>pre_save<\/strong> signal:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"1,2,5\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from django.dispatch import receiver\nfrom django.db.models.signals import pre_save\nfrom django.template.defaultfilters import slugify\n\n@receiver(pre_save)\ndef my_callback(sender, instance, *args, **kwargs):\n    instance.slug = slugify(instance.title)<\/pre>\n\n\n\n<p>Example of <strong>post_save<\/strong> signal:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"1,2,5\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from django.dispatch import receiver\nfrom django.db.models.signals import post_save\nfrom django.contrib.auth.models import User\n\n@receiver(post_save, sender=User)\ndef create_profile(sender, **kwargs):\n    # write you functionality\n    pass<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">3. The clean_&lt;field>() methods at Forms classes<\/h2>\n\n\n\n<p>This is a <strong>backend solution<\/strong> based on <strong>Django<\/strong> <strong>clean_()<\/strong> methods.<\/p>\n\n\n\n<p>Django <strong>clean_&lt;field>()<\/strong> methods are special methods used within <strong>Django<\/strong> form classes to clean and validate individual form fields. They are automatically called during form validation after the respective field&#8217;s default validation has been performed.<\/p>\n\n\n\n<p>Here&#8217;s how <strong>clean_&lt;field>()<\/strong> methods work:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong><span style=\"text-decoration: underline;\">Validation and Cleaning:<\/span><\/strong> When you define a form class in Django, each form field gets its method for validation and cleaning. These methods are named <strong>clean_&lt;field_name>(), <\/strong>in which<strong> &lt;field_name><\/strong> is replaced by the name of the field.<\/li>\n\n\n\n<li><strong><span style=\"text-decoration: underline;\">Execution Order:<\/span><\/strong> These methods are executed after the default field validation. Django first checks the field&#8217;s built-in validators, and then if there are any <strong>clean_&lt;field>()<\/strong> methods, it calls them one by one.<\/li>\n\n\n\n<li><strong><span style=\"text-decoration: underline;\">Customized Cleaning Logic:<\/span><\/strong> In your form class, you can define these methods to implement custom validation and cleaning logic for individual fields. This is particularly useful when you need to perform complex validation or when the validation depends on the values of multiple fields.<\/li>\n\n\n\n<li><strong><span style=\"text-decoration: underline;\">Error Handling:<\/span><\/strong> Inside these methods, you can raise a <strong>ValidationError<\/strong> if the field&#8217;s value doesn&#8217;t pass your custom validation criteria. This error can contain a message explaining the reason for the validation failure, which will be displayed to the user.<\/li>\n<\/ol>\n\n\n\n<p>Here&#8217;s a simple example demonstrating the usage of <strong>clean_&lt;field>()<\/strong> methods in a <strong>Django<\/strong> form:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"6,7\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from django import forms\n\nclass MyForm(forms.Form):\n    age = forms.IntegerField()\n\n    def clean_age(self):\n        age = self.cleaned_data.get('age')\n        if age is not None and age &lt; 18:\n            raise forms.ValidationError(\"You must be 18 or older to use this service.\")\n        return age\n<\/pre>\n\n\n\n<p>In this example, the <strong>clean_age()<\/strong> method checks if the provided age is under 18. If it is, it raises a <strong>ValidationError<\/strong> with a corresponding error message. Otherwise, it <strong>returns the cleaned (validated) value<\/strong>.<\/p>\n\n\n\n<p>Now let&#8217;s see how we can use the <strong>clean_&lt;field>()<\/strong> methods to rewrite data in another field:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"7-15\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from django import forms\n\nclass MyForm(forms.Form):\n    start_date = forms.DateField()\n    end_date = forms.DateField()\n\n    def clean_start_date(self):\n        start_date = self.cleaned_data.get('start_date')\n        end_date = self.cleaned_data.get('end_date')\n\n        # Check if start_date is after end_date\n        if start_date and end_date and start_date > end_date:\n            # If start_date is after end_date, swap the values\n            self.cleaned_data['start_date'] = end_date\n            self.cleaned_data['end_date'] = start_date\n\n        return start_date\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">4. Create a custom widget<\/h2>\n\n\n\n<p>This is one of the most beautiful approaches because it lets you work with the form from the Angular JS point of view without messing with custom controllers (which is the last point of this manual). This is a <strong>frontend solution<\/strong> designed from the backend.<\/p>\n\n\n\n<p>This is usually the best approach when you post-process data in the form (straight inside the browser). You need to know Angular JS\u00a0programming to go with this solution if you want to make big things, but for simple changes, it is perfectly fine.<\/p>\n\n\n\n<p><strong><span style=\"text-decoration: underline;\">Process:<\/span><\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create a <strong>widget.py<\/strong> file in your app folder with your <strong>CustomWidget<\/strong>:<\/li>\n\n\n\n<li>Example of a new Custom field in the frontend (you can inherit from any other Django Field at your convenience) and overload the render() method to replace the HTML created by the original Widget, then you just replace the HTML returned by the original widget. Just print it out while designing to understand what the server is rendering and rewrite it at your convencience.<\/li>\n\n\n\n<li>In your\u00a0<strong>forms.py<\/strong>, import your <strong>CustomWidget<\/strong> and inside your\u00a0form class, add a &#8220;<strong>widgets<\/strong>&#8221; attribute which should be a dictionary with the field name as a key and your custom widget as the value. Example:\u00a0<strong>widgets = { &#8220;myfield&#8221;: MyCustomWidget() }<\/strong><\/li>\n<\/ul>\n\n\n\n<p><strong><span style=\"text-decoration: underline;\">Example 1:<\/span><\/strong> in this example the field will be disabled if some other field is not filled or its value evaluates to <strong>False<\/strong>.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"3,5,8-11\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class MyCustomWidget(forms.widgets.TextInput):\n\n\u00a0 \u00a0 def render(self, name, value, attrs=None, renderer=None):\n\u00a0 \u00a0 \u00a0 \u00a0 # Get html\n\u00a0 \u00a0 \u00a0 \u00a0 html = super().render(name, value, attrs, renderer)\n\n\u00a0 \u00a0 \u00a0 \u00a0 # Transform html to make sure this field is disabled if some other field is not filled\n\u00a0 \u00a0 \u00a0 \u00a0 html = html.replace(\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'type=\"text\"',\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'type=\"text\" min=\"1\" ng-disabled=\"!some_other_field\"',\n\u00a0 \u00a0 \u00a0 \u00a0 )<\/pre>\n\n\n\n<p><strong><span style=\"text-decoration: underline;\">Example 2:<\/span><\/strong> Here is another example that brings a new field (visible only) that will show the maximum points that the program will give when a max number of minutes is defined together with a cost of points_per_minutes:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"601\" height=\"273\" src=\"https:\/\/codenerix.com\/wp-content\/uploads\/2024\/03\/image.png\" alt=\"\" class=\"wp-image-937\" style=\"width:375px;height:auto\" srcset=\"https:\/\/codenerix.com\/wp-content\/uploads\/2024\/03\/image.png 601w, https:\/\/codenerix.com\/wp-content\/uploads\/2024\/03\/image-480x218.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 601px, 100vw\" \/><\/figure>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"3,5,8-11,16-27\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class MaxMinutes(forms.widgets.NumberInput):\n\n    def render(self, name, value, attrs=None, renderer=None):\n        # Get html\n        html = super().render(name, value, attrs, renderer)\n\n        # Transform html to configure the field to a fixed minimum value\n        html = html.replace(\n            'ng-readonly=\"readonly_max_minutes\" ',\n            'ng-readonly=\"readonly_max_minutes\" min=\"0\"',\n        )\n\n        # Put all together with an extra piece of HTML code that will summarize\n        # the maximum points the program will give with those \"max_minutes\"\n        # using \"points_per_minute\" field configured somewhere else\n        html = (\n            html\n            + \"\"\"\n            &lt;label for=\"points\">Max Points&lt;\/label>\n                &lt;input\n                    type=\"number\"\n                    class=\"form-control\"\n                    ng-readonly=\"true\"\n                    min=\"0\"\n                    ng-value=\"max_minutes * points_per_minute\">\n            \"\"\"\n        )\n\n        # Return result\n        return html\n<\/pre>\n\n\n\n<p>If you field is a SelectField there are some specific structure to help you inspect data in it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. Overwrite the $scope.submit()<\/h2>\n\n\n\n<p>This is a frontend solution and it is actually one of the most difficult approaches because it requires incorporing a custom controller to your form to allow you overwrite methods. This solution happily will give you full control of the system from the AngularJS point of view but you will pay back in complexity.<\/p>\n\n\n\n<p><strong>DISCLAIMER: you need advance knowledge about Angular JS programming to go with this solution.<\/strong><\/p>\n\n\n\n<p>Basically this solutions is based on overwritting the method submit() in side the $scope of your controller with your one. Please check submit() method inside the desired controller at <strong>codenerix.js<\/strong> for more information.<\/p>\n\n\n\n<p>To override the default <strong><a href=\"https:\/\/github.com\/codenerix\/django-codenerix\"><span style=\"color: #343433;\">CODE<\/span><span style=\"color: #70a8e0;\">NERIX<\/span><\/a><\/strong>\u00a0controllers you have to make use of the following attributed inside your GenList class to override the default ones:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>ws_entry_point:<\/strong> set ws_entry_point variable to a fixed value<\/li>\n\n\n\n<li><strong>static_partial_row:<\/strong> set static_partial_row to a fixed value<\/li>\n\n\n\n<li><strong>static_partial_header:<\/strong> set static_partial_header to a fixed value<\/li>\n\n\n\n<li><strong>static_partial_summary:<\/strong> set static_partial_summary to a fixed value<\/li>\n\n\n\n<li><strong>static_app_row:<\/strong> set static_app_row to a fixed value<\/li>\n\n\n\n<li><mark style=\"background-color:#7bdcb5\" class=\"has-inline-color\"><strong>static_controllers_row:<\/strong> set static_controllers_row to a fixed value<\/mark><\/li>\n\n\n\n<li><strong>static_filters_row:<\/strong> set static_filters_row to a fixed value<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusions<\/h2>\n\n\n\n<p>In conclusion, this guide comprehensively explores techniques for transforming and generating data within <strong>Django<\/strong> applications, encompassing both <strong>backend and frontend solutions<\/strong>. It outlines methods such as <strong>overloading the save() <\/strong>method, utilizing <strong>Django signals<\/strong>, and <strong>leveraging clean_&lt;field>() methods<\/strong> for backend data manipulation. Additionally, it highlights <strong>frontend approaches<\/strong>, emphasizing the creation of<strong> custom widgets and AngularJS integration<\/strong>. While each method offers unique advantages, developers must carefully consider factors like complexity, maintainability, and project requirements when choosing the most suitable approach. Overall, this guide equips developers with the knowledge and tools necessary to enhance data management and customization in <strong><a href=\"https:\/\/github.com\/codenerix\/django-codenerix\"><span style=\"color: #343433;\">CODE<\/span><span style=\"color: #70a8e0;\">NERIX<\/span><\/a><\/strong>\u00a0<strong>Django<\/strong> applications.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this guide, we will cover how to transform data or produce new data by calculating existing data, and we will go through the process of building our widgets using AngularJS for a ModelForm. Some of the ways explained here will follow the standard Django way of doing things, while others will follow the CODENERIX\u00a0way. [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":930,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[20],"tags":[],"class_list":["post-929","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-howto"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.0 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Unlocking Advanced Data Transformation in Django CODENERIX: A Complete Guide - Codenerix<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Unlocking Advanced Data Transformation in Django CODENERIX: A Complete Guide - Codenerix\" \/>\n<meta property=\"og:description\" content=\"In this guide, we will cover how to transform data or produce new data by calculating existing data, and we will go through the process of building our widgets using AngularJS for a ModelForm. Some of the ways explained here will follow the standard Django way of doing things, while others will follow the CODENERIX\u00a0way. [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/\" \/>\n<meta property=\"og:site_name\" content=\"Codenerix\" \/>\n<meta property=\"article:published_time\" content=\"2024-03-25T13:44:17+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-02-10T05:16:37+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/codenerix.com\/wp-content\/uploads\/2024\/03\/data_transform.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"626\" \/>\n\t<meta property=\"og:image:height\" content=\"417\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Codenerix\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Codenerix\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/\"},\"author\":{\"name\":\"Codenerix\",\"@id\":\"https:\/\/codenerix.com\/#\/schema\/person\/c1dce0f30541a2be119ee8adc332a9af\"},\"headline\":\"Unlocking Advanced Data Transformation in Django CODENERIX: A Complete Guide\",\"datePublished\":\"2024-03-25T13:44:17+00:00\",\"dateModified\":\"2025-02-10T05:16:37+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/\"},\"wordCount\":1377,\"commentCount\":0,\"image\":{\"@id\":\"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/codenerix.com\/wp-content\/uploads\/2024\/03\/data_transform.jpg\",\"articleSection\":[\"Howto\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/\",\"url\":\"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/\",\"name\":\"Unlocking Advanced Data Transformation in Django CODENERIX: A Complete Guide - Codenerix\",\"isPartOf\":{\"@id\":\"https:\/\/codenerix.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/codenerix.com\/wp-content\/uploads\/2024\/03\/data_transform.jpg\",\"datePublished\":\"2024-03-25T13:44:17+00:00\",\"dateModified\":\"2025-02-10T05:16:37+00:00\",\"author\":{\"@id\":\"https:\/\/codenerix.com\/#\/schema\/person\/c1dce0f30541a2be119ee8adc332a9af\"},\"breadcrumb\":{\"@id\":\"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#primaryimage\",\"url\":\"https:\/\/codenerix.com\/wp-content\/uploads\/2024\/03\/data_transform.jpg\",\"contentUrl\":\"https:\/\/codenerix.com\/wp-content\/uploads\/2024\/03\/data_transform.jpg\",\"width\":626,\"height\":417},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/codenerix.com\/en\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Unlocking Advanced Data Transformation in Django CODENERIX: A Complete Guide\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/codenerix.com\/#website\",\"url\":\"https:\/\/codenerix.com\/\",\"name\":\"Codenerix\",\"description\":\"Framework libre Open Source\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/codenerix.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/codenerix.com\/#\/schema\/person\/c1dce0f30541a2be119ee8adc332a9af\",\"name\":\"Codenerix\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/codenerix.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/dee2772994eb5d89e57afac281bca674800da15c6c32fba528dea162570d644d?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/dee2772994eb5d89e57afac281bca674800da15c6c32fba528dea162570d644d?s=96&d=mm&r=g\",\"caption\":\"Codenerix\"},\"url\":\"https:\/\/codenerix.com\/en\/author\/codenerix\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Unlocking Advanced Data Transformation in Django CODENERIX: A Complete Guide - Codenerix","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/","og_locale":"en_US","og_type":"article","og_title":"Unlocking Advanced Data Transformation in Django CODENERIX: A Complete Guide - Codenerix","og_description":"In this guide, we will cover how to transform data or produce new data by calculating existing data, and we will go through the process of building our widgets using AngularJS for a ModelForm. Some of the ways explained here will follow the standard Django way of doing things, while others will follow the CODENERIX\u00a0way. [&hellip;]","og_url":"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/","og_site_name":"Codenerix","article_published_time":"2024-03-25T13:44:17+00:00","article_modified_time":"2025-02-10T05:16:37+00:00","og_image":[{"width":626,"height":417,"url":"https:\/\/codenerix.com\/wp-content\/uploads\/2024\/03\/data_transform.jpg","type":"image\/jpeg"}],"author":"Codenerix","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Codenerix","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#article","isPartOf":{"@id":"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/"},"author":{"name":"Codenerix","@id":"https:\/\/codenerix.com\/#\/schema\/person\/c1dce0f30541a2be119ee8adc332a9af"},"headline":"Unlocking Advanced Data Transformation in Django CODENERIX: A Complete Guide","datePublished":"2024-03-25T13:44:17+00:00","dateModified":"2025-02-10T05:16:37+00:00","mainEntityOfPage":{"@id":"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/"},"wordCount":1377,"commentCount":0,"image":{"@id":"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#primaryimage"},"thumbnailUrl":"https:\/\/codenerix.com\/wp-content\/uploads\/2024\/03\/data_transform.jpg","articleSection":["Howto"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/","url":"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/","name":"Unlocking Advanced Data Transformation in Django CODENERIX: A Complete Guide - Codenerix","isPartOf":{"@id":"https:\/\/codenerix.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#primaryimage"},"image":{"@id":"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#primaryimage"},"thumbnailUrl":"https:\/\/codenerix.com\/wp-content\/uploads\/2024\/03\/data_transform.jpg","datePublished":"2024-03-25T13:44:17+00:00","dateModified":"2025-02-10T05:16:37+00:00","author":{"@id":"https:\/\/codenerix.com\/#\/schema\/person\/c1dce0f30541a2be119ee8adc332a9af"},"breadcrumb":{"@id":"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#primaryimage","url":"https:\/\/codenerix.com\/wp-content\/uploads\/2024\/03\/data_transform.jpg","contentUrl":"https:\/\/codenerix.com\/wp-content\/uploads\/2024\/03\/data_transform.jpg","width":626,"height":417},{"@type":"BreadcrumbList","@id":"https:\/\/codenerix.com\/en\/unlocking-advanced-data-transformation-in-django-codenerix-a-complete-guide\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/codenerix.com\/en\/"},{"@type":"ListItem","position":2,"name":"Unlocking Advanced Data Transformation in Django CODENERIX: A Complete Guide"}]},{"@type":"WebSite","@id":"https:\/\/codenerix.com\/#website","url":"https:\/\/codenerix.com\/","name":"Codenerix","description":"Framework libre Open Source","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/codenerix.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/codenerix.com\/#\/schema\/person\/c1dce0f30541a2be119ee8adc332a9af","name":"Codenerix","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/codenerix.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/dee2772994eb5d89e57afac281bca674800da15c6c32fba528dea162570d644d?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/dee2772994eb5d89e57afac281bca674800da15c6c32fba528dea162570d644d?s=96&d=mm&r=g","caption":"Codenerix"},"url":"https:\/\/codenerix.com\/en\/author\/codenerix\/"}]}},"_links":{"self":[{"href":"https:\/\/codenerix.com\/en\/wp-json\/wp\/v2\/posts\/929","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codenerix.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codenerix.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codenerix.com\/en\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/codenerix.com\/en\/wp-json\/wp\/v2\/comments?post=929"}],"version-history":[{"count":10,"href":"https:\/\/codenerix.com\/en\/wp-json\/wp\/v2\/posts\/929\/revisions"}],"predecessor-version":[{"id":941,"href":"https:\/\/codenerix.com\/en\/wp-json\/wp\/v2\/posts\/929\/revisions\/941"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/codenerix.com\/en\/wp-json\/wp\/v2\/media\/930"}],"wp:attachment":[{"href":"https:\/\/codenerix.com\/en\/wp-json\/wp\/v2\/media?parent=929"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codenerix.com\/en\/wp-json\/wp\/v2\/categories?post=929"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codenerix.com\/en\/wp-json\/wp\/v2\/tags?post=929"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}