From e11230315901362d0b1bfc78a58aaaea47b6d1b5 Mon Sep 17 00:00:00 2001
From: Bossanyi Tibor <sw@andio.biz>
Date: Fri, 29 Jan 2021 15:56:18 +0100
Subject: [PATCH] ExerciseTree parent optional fix, django 3.1.5 upgrade

---
 .../aitrainer_backoffice/admin.py             | 121 ++++++-----
 .../aitrainer_backoffice/models.py            | 200 ++++++++++--------
 requirements.txt                              |   2 +-
 3 files changed, 180 insertions(+), 143 deletions(-)

diff --git a/aitrainer_backoffice/aitrainer_backoffice/admin.py b/aitrainer_backoffice/aitrainer_backoffice/admin.py
index 5b935d6..8e30445 100644
--- a/aitrainer_backoffice/aitrainer_backoffice/admin.py
+++ b/aitrainer_backoffice/aitrainer_backoffice/admin.py
@@ -12,6 +12,65 @@ from .models import ExercisePlanTranslation
 from .models import ExercisePlanDetail
 from .models import ExercisePlan
 
+''' 
+    ExerciseTree
+    ------------ 
+'''
+
+
+class TranslationTreeInline(admin.TabularInline):
+    model = ExerciseTreeTranslation
+    fields = ('language_code', 'name',)
+    extra = 0
+
+
+class ExerciseTreeParentsInline(admin.TabularInline):
+    model = ExerciseTreeParents
+    fk_name = 'exercise_tree_child'
+    fields = ('exercise_tree_parent',)
+    extra = 0
+
+
+class ExerciseTreeAdmin(admin.ModelAdmin):
+    list_display = ('tree_id', 'name_colored', 'active')
+    search_fields = ['name']
+
+    fields = ["name", "image_url", "active", "get_image_preview"]
+    readonly_fields = ("get_image_preview",)
+
+    def get_image_preview(self, obj):
+        image_url = '/media/' + str(obj.image_url)
+        if obj.pk:
+            return format_html('<img src="{url}" title="{url}" width="30%" height="30%"/> '
+                               .format(url=image_url))
+
+    get_image_preview.short_description = _("Image Preview")
+
+    def name_colored(self, obj):
+        if obj.active:
+            if obj.image_url != "":
+                color_code = '7bc863'
+            else:
+                color_code = 'f2cdb3'
+        else:
+            color_code = 'C20000'
+        html = '<span style="color: #{};">{}</span>˓→'.format(color_code, obj.name)
+        return format_html(html)
+
+    name_colored.admin_order_field = 'name'
+    name_colored.short_description = 'name'
+
+    inlines = [
+        TranslationTreeInline,
+        ExerciseTreeParentsInline
+    ]
+
+
+''' 
+    ExerciseTYPE
+    ------------ 
+'''
+
 
 class ExerciseTypeDeviceInline(admin.StackedInline):
     model = ExerciseTypeDevice
@@ -82,57 +141,15 @@ class ExerciseTypeAdmin(admin.ModelAdmin):
     exclude = ('exercise_tree',)
 
 
-class TranslationTreeInline(admin.TabularInline):
-    model = ExerciseTreeTranslation
-    fields = ('language_code', 'name',)
-    extra = 0
-
-
-class ExerciseTreeParentsInline(admin.TabularInline):
-    model = ExerciseTreeParents
-    fk_name = 'exercise_tree_child'
-    fields = ('exercise_tree_parent',)
-    extra = 0
-
-
-class ExerciseTreeAdmin(admin.ModelAdmin):
-    list_display = ('tree_id', 'name_colored', 'active')
-    search_fields = ['name']
-
-    fields = ["name", "parent_id", "image_url", "active", "get_image_preview"]
-    readonly_fields = ("get_image_preview",)
-
-    def get_image_preview(self, obj):
-        image_url = '/media/' + str(obj.image_url)
-        if obj.pk:
-            return format_html('<img src="{url}" title="{url}" width="30%" height="30%"/> '
-                               .format(url=image_url))
-
-    get_image_preview.short_description = _("Image Preview")
-
-    def name_colored(self, obj):
-        if obj.active:
-            if obj.image_url != "":
-                color_code = '7bc863'
-            else:
-                color_code = 'f2cdb3'
-        else:
-            color_code = 'C20000'
-        html = '<span style="color: #{};">{}</span>˓→'.format(color_code, obj.name)
-        return format_html(html)
-
-    name_colored.admin_order_field = 'name'
-    name_colored.short_description = 'name'
-
-    inlines = [
-        TranslationTreeInline,
-        ExerciseTreeParentsInline
-    ]
+''' 
+    ExercisePlan
+    ------------ 
+'''
 
 
 class TranslationPlanInline(admin.TabularInline):
     model = ExercisePlanTranslation
-    fields = ('language_code', 'name','description')
+    fields = ('language_code', 'name', 'description')
     extra = 0
 
 
@@ -154,9 +171,10 @@ class ExercisePlanAdmin(admin.ModelAdmin):
 
 
 class ExercisePlanDetailAdmin(admin.ModelAdmin):
-    list_display = ( 'get_plan', 'get_exercise_type', 'serie', 'repeats', 'weight_equation',)
+    list_display = ('get_plan', 'get_exercise_type', 'serie', 'repeats', 'weight_equation',)
     list_editable = ('serie', 'repeats', 'weight_equation',)
-    #list_editable_link('',)
+
+    # list_editable_link('',)
 
     def get_plan(self, obj):
         return obj.exercise_plan.name
@@ -167,7 +185,9 @@ class ExercisePlanDetailAdmin(admin.ModelAdmin):
 
 class ProductAdmin(admin.ModelAdmin):
     list_display = ('product_id', 'name', 'type')
-   #  Product.objects.all().aggregate(Sum('price'))
+
+
+#  Product.objects.all().aggregate(Sum('price'))
 
 
 class PurchaseAdmin(admin.ModelAdmin):
@@ -238,4 +258,3 @@ admin.site.register(Purchase, PurchaseAdmin)
 admin.site.register(Property, PropertyAdmin)
 admin.site.register(ExerciseDevice, ExerciseDeviceAdmin)
 admin.autodiscover()
-
diff --git a/aitrainer_backoffice/aitrainer_backoffice/models.py b/aitrainer_backoffice/aitrainer_backoffice/models.py
index 4613488..4955d71 100644
--- a/aitrainer_backoffice/aitrainer_backoffice/models.py
+++ b/aitrainer_backoffice/aitrainer_backoffice/models.py
@@ -8,6 +8,12 @@ class LanguageTypes(models.TextChoices):
     HU = "hu"
 
 
+''' 
+    ExerciseDevice
+    ------------ 
+'''
+
+
 class ExerciseDevice(models.Model):
     exercise_device_id = models.AutoField(primary_key=True)
     name = models.CharField(max_length=100)
@@ -30,9 +36,44 @@ class ExerciseDevice(models.Model):
         return self.name
 
 
+class ExerciseDeviceAlternative(models.Model):
+    exercise_device_alternative_id = models.AutoField(primary_key=True)
+    exercise_device_parent = models.ForeignKey(ExerciseDevice, on_delete=models.CASCADE,
+                                               related_name=_('exercise_device_parent'))
+    exercise_device_child = models.ForeignKey(ExerciseDevice, on_delete=models.CASCADE,
+                                              related_name=_('exercise_device_child'))
+
+    class Meta:
+        db_table = 'exercise_device_alternative'
+        verbose_name = _("Device Alternative")
+        verbose_name_plural = _("Device Alternatives")
+        unique_together = ['exercise_device_parent', 'exercise_device_child']
+
+
+class ExerciseDeviceTranslation(models.Model):
+    translation_id = models.AutoField(primary_key=True)
+    exercise_device = models.ForeignKey(ExerciseDevice, on_delete=models.CASCADE)
+    name = models.CharField(max_length=100)
+    language_code = models.CharField(max_length=2, choices=LanguageTypes.choices, default=LanguageTypes.HU)
+
+    class Meta:
+        db_table = 'exercise_device_translation'
+        verbose_name = _("Translation")
+        verbose_name_plural = _("Translations")
+
+    def __str__(self):
+        return self.name
+
+
+''' 
+    ------------
+    ExerciseTree
+    ------------ 
+'''
+
+
 class ExerciseTree(models.Model):
     tree_id = models.AutoField(primary_key=True)
-    parent_id = models.IntegerField(help_text='This is the parent menu ID. 0 if it is on the top of the tree')
     name = models.CharField(max_length=100, help_text='The name should be in English here')
     image_url = models.ImageField(upload_to='images/', help_text='The menu image size is 1366x768')
     active = models.BooleanField(default=0, blank=True, null=True)
@@ -46,6 +87,41 @@ class ExerciseTree(models.Model):
         return self.name
 
 
+class ExerciseTreeTranslation(models.Model):
+    translation_id = models.AutoField(primary_key=True)
+    tree = models.ForeignKey(ExerciseTree, on_delete=models.CASCADE)
+    language_code = models.CharField(max_length=2, choices=LanguageTypes.choices, default=LanguageTypes.HU)
+    name = models.CharField(max_length=100)
+
+    class Meta:
+        db_table = 'exercise_tree_translation'
+        verbose_name = _("Translation")
+        verbose_name_plural = _("Translations")
+
+    def __str__(self):
+        return self.name
+
+
+class ExerciseTreeParents(models.Model):
+    exercise_tree_parents_id = models.AutoField(primary_key=True)
+    exercise_tree_parent = models.ForeignKey(ExerciseTree, on_delete=models.CASCADE,
+                                             related_name=_('exercise_tree_parent'), help_text=_('Parent menu'), blank=True)
+    exercise_tree_child = models.ForeignKey(ExerciseTree, on_delete=models.CASCADE,
+                                            related_name=_('exercise_tree_child'), help_text=_('Actual menu'))
+
+    class Meta:
+        db_table = 'exercise_tree_parents'
+        verbose_name = _("Exercise Tree Parent")
+        verbose_name_plural = _("Exercise Tree Parents")
+        unique_together = [['exercise_tree_parent', 'exercise_tree_child']]
+
+
+''' 
+    ExerciseTYPE
+    ------------ 
+'''
+
+
 class ExerciseType(models.Model):
     class UnitTypes(models.TextChoices):
         REPEAT = 'repeat'
@@ -58,7 +134,6 @@ class ExerciseType(models.Model):
         KG = 'kilogram'
 
     exercise_type_id = models.AutoField(primary_key=True)
-#   tree = models.ForeignKey(ExerciseTree, on_delete=models.CASCADE)
     name = models.CharField(max_length=100, help_text='The name should be in English here')
     description = models.TextField(max_length=1000, blank=True, null=True, help_text='The description should be in '
                                                                                      'English here')
@@ -70,7 +145,6 @@ class ExerciseType(models.Model):
     base = models.BooleanField(default=0, blank=True, null=True)
     parents = models.ManyToManyField(ExerciseTree, through='ExerciseTypeParents', related_name='ExerciseTree')
 
-
     class Meta:
         db_table = 'exercise_type'
         verbose_name = _("Exercise")
@@ -117,19 +191,41 @@ class ExerciseTypeTranslation(models.Model):
         return self.name
 
 
-class ExerciseTreeTranslation(models.Model):
-    translation_id = models.AutoField(primary_key=True)
-    tree = models.ForeignKey(ExerciseTree, on_delete=models.CASCADE)
-    language_code = models.CharField(max_length=2, choices=LanguageTypes.choices, default=LanguageTypes.HU)
-    name = models.CharField(max_length=100)
+class ExerciseTypeDevice(models.Model):
+    exercise_type_device_id = models.AutoField(primary_key=True)
+    exercise_type = models.ForeignKey(ExerciseType, on_delete=models.CASCADE)
+    exercise_device = models.ForeignKey(ExerciseDevice, on_delete=models.CASCADE)
 
     class Meta:
-        db_table = 'exercise_tree_translation'
-        verbose_name = _("Translation")
-        verbose_name_plural = _("Translations")
+        db_table = 'exercise_type_device'
+        verbose_name = _("Exercise Device")
+        verbose_name_plural = _("Exercise Devices")
 
-    def __str__(self):
-        return self.name
+
+class ExerciseTypeAlternative(models.Model):
+    exercise_type_alternative_id = models.AutoField(primary_key=True)
+    exercise_type_parent = models.ForeignKey(ExerciseType, on_delete=models.CASCADE,
+                                             related_name=_('exercise_type_parent'))
+    exercise_type_child = models.ForeignKey(ExerciseType, on_delete=models.CASCADE,
+                                            related_name=_('exercise_type_child'))
+
+    class Meta:
+        db_table = 'exercise_type_alternative'
+        verbose_name = _("Exercise Alternative")
+        verbose_name_plural = _("Exercise Alternatives")
+        unique_together = [['exercise_type_parent', 'exercise_type_child']]
+
+
+class ExerciseTypeParents(models.Model):
+    exercise_type_parents_id = models.AutoField(primary_key=True)
+    exercise_type = models.ForeignKey(ExerciseType, on_delete=models.CASCADE)
+    exercise_tree = models.ForeignKey(ExerciseTree, on_delete=models.CASCADE)
+
+    class Meta:
+        db_table = 'exercise_type_parents'
+        verbose_name = _("Exercise Parent")
+        verbose_name_plural = _("Exercise Parents")
+        unique_together = [['exercise_type', 'exercise_tree']]
 
 
 class ExercisePlan(models.Model):
@@ -240,81 +336,3 @@ class PropertyTranslation(models.Model):
 
     def __str__(self):
         return self.property_name
-
-
-class ExerciseTypeDevice(models.Model):
-    exercise_type_device_id = models.AutoField(primary_key=True)
-    exercise_type = models.ForeignKey(ExerciseType, on_delete=models.CASCADE)
-    exercise_device = models.ForeignKey(ExerciseDevice, on_delete=models.CASCADE)
-
-    class Meta:
-        db_table = 'exercise_type_device'
-        verbose_name = _("Exercise Device")
-        verbose_name_plural = _("Exercise Devices")
-
-
-class ExerciseDeviceTranslation(models.Model):
-    translation_id = models.AutoField(primary_key=True)
-    exercise_device = models.ForeignKey(ExerciseDevice, on_delete=models.CASCADE)
-    name = models.CharField(max_length=100)
-    language_code = models.CharField(max_length=2, choices=LanguageTypes.choices, default=LanguageTypes.HU)
-
-    class Meta:
-        db_table = 'exercise_device_translation'
-        verbose_name = _("Translation")
-        verbose_name_plural = _("Translations")
-
-    def __str__(self):
-        return self.name
-
-
-class ExerciseDeviceAlternative(models.Model):
-    exercise_device_alternative_id = models.AutoField(primary_key=True)
-    exercise_device_parent = models.ForeignKey(ExerciseDevice, on_delete=models.CASCADE,
-                                               related_name=_('exercise_device_parent'))
-    exercise_device_child = models.ForeignKey(ExerciseDevice, on_delete=models.CASCADE,
-                                              related_name=_('exercise_device_child'))
-
-    class Meta:
-        db_table = 'exercise_device_alternative'
-        verbose_name = _("Device Alternative")
-        verbose_name_plural = _("Device Alternatives")
-        unique_together = ['exercise_device_parent', 'exercise_device_child']
-
-
-class ExerciseTypeAlternative(models.Model):
-    exercise_type_alternative_id = models.AutoField(primary_key=True)
-    exercise_type_parent = models.ForeignKey(ExerciseType, on_delete=models.CASCADE,
-                                             related_name=_('exercise_type_parent'))
-    exercise_type_child = models.ForeignKey(ExerciseType, on_delete=models.CASCADE,
-                                            related_name=_('exercise_type_child'))
-
-    class Meta:
-        db_table = 'exercise_type_alternative'
-        verbose_name = _("Exercise Alternative")
-        verbose_name_plural = _("Exercise Alternatives")
-        unique_together = [['exercise_type_parent', 'exercise_type_child']]
-
-
-class ExerciseTypeParents(models.Model):
-    exercise_type_parents_id = models.AutoField(primary_key=True)
-    exercise_type = models.ForeignKey(ExerciseType, on_delete=models.CASCADE)
-    exercise_tree = models.ForeignKey(ExerciseTree, on_delete=models.CASCADE)
-
-    class Meta:
-        db_table = 'exercise_type_parents'
-        verbose_name = _("Exercise Parent")
-        verbose_name_plural = _("Exercise Parents")
-        unique_together= [['exercise_type', 'exercise_tree']]
-
-
-class ExerciseTreeParents(models.Model):
-    exercise_tree_parents_id = models.AutoField(primary_key=True)
-    exercise_tree_parent = models.ForeignKey(ExerciseTree, on_delete=models.CASCADE, related_name=_('exercise_tree_parent'), help_text=_('Parent menu'))
-    exercise_tree_child = models.ForeignKey(ExerciseTree, on_delete=models.CASCADE, related_name=_('exercise_tree_child'), help_text=_('Actual menu'))
-
-    class Meta:
-        db_table = 'exercise_tree_parents'
-        verbose_name = _("Exercise Tree Parent")
-        verbose_name_plural = _("Exercise Tree Parents")
-        unique_together= [['exercise_tree_parent', 'exercise_tree_child']]
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 7262caa..d60b218 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
-django==3.1.4
+django==3.1.5
 asgiref==3.2.10
 certifi==2020.6.20
 chardet==3.0.4