BO 1.27 Drag&Drop TrainingPlanDetail, TrainingPlan clone
This commit is contained in:
parent
462877c8a9
commit
2340c3e21a
@ -0,0 +1,8 @@
|
|||||||
|
{% extends "adminsortable2/change_list.html" %}
|
||||||
|
|
||||||
|
{% block object-tools-items %}
|
||||||
|
{{ block.super }}
|
||||||
|
<li>
|
||||||
|
<a href="mylink/">My Link</a>
|
||||||
|
</li>
|
||||||
|
{% endblock %}
|
@ -0,0 +1,81 @@
|
|||||||
|
{% load i18n admin_urls static admin_modify %}
|
||||||
|
<div class="js-inline-admin-formset inline-group" id="{{ inline_admin_formset.formset.prefix }}-group"
|
||||||
|
data-inline-type="tabular"
|
||||||
|
data-inline-formset="{{ inline_admin_formset.inline_formset_data }}">
|
||||||
|
<div class="tabular inline-related {% if forloop.last %}last-related{% endif %}">
|
||||||
|
{{ inline_admin_formset.formset.management_form }}
|
||||||
|
<fieldset class="module {{ inline_admin_formset.classes }}">
|
||||||
|
{% if inline_admin_formset.formset.max_num == 1 %}
|
||||||
|
<h2>{{ inline_admin_formset.opts.verbose_name|capfirst }}</h2>
|
||||||
|
{% else %}
|
||||||
|
<h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h2>
|
||||||
|
{% endif %}
|
||||||
|
{{ inline_admin_formset.formset.non_form_errors }}
|
||||||
|
<table>
|
||||||
|
<thead><tr>
|
||||||
|
<th class="original"></th>
|
||||||
|
{% for field in inline_admin_formset.fields %}
|
||||||
|
{% if not field.widget.is_hidden %}
|
||||||
|
<th class="column-{{ field.name }}{% if field.required %} required{% endif %}">{{ field.label|capfirst }}
|
||||||
|
{% if field.help_text %}<img src="{% static "admin/img/icon-unknown.svg" %}" class="help help-tooltip" width="10" height="10" alt="({{ field.help_text|striptags }})" title="{{ field.help_text|striptags }}">{% endif %}
|
||||||
|
</th>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission %}<th>{% translate "Delete?" %}</th>{% endif %}
|
||||||
|
<th>{% translate "Clone?" %}</th>
|
||||||
|
</tr></thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{% for inline_admin_form in inline_admin_formset %}
|
||||||
|
{% if inline_admin_form.form.non_field_errors %}
|
||||||
|
<tr class="row-form-errors"><td colspan="{{ inline_admin_form|cell_count }}">{{ inline_admin_form.form.non_field_errors }}</td></tr>
|
||||||
|
{% endif %}
|
||||||
|
<tr class="form-row {% if inline_admin_form.original or inline_admin_form.show_url %}has_original{% endif %}{% if forloop.last and inline_admin_formset.has_add_permission %} empty-form{% endif %}"
|
||||||
|
id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
|
||||||
|
<td class="original">
|
||||||
|
{% if inline_admin_form.original or inline_admin_form.show_url %}<p>
|
||||||
|
{% if inline_admin_form.original %}
|
||||||
|
{{ inline_admin_form.original }}
|
||||||
|
{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %}<a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="{% if inline_admin_formset.has_change_permission %}inlinechangelink{% else %}inlineviewlink{% endif %}">{% if inline_admin_formset.has_change_permission %}{% translate "Change" %}{% else %}{% translate "View" %}{% endif %}</a>{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if inline_admin_form.show_url %}<a href="{{ inline_admin_form.absolute_url }}">{% translate "View on site" %}</a>{% endif %}
|
||||||
|
</p>{% endif %}
|
||||||
|
{% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
|
||||||
|
{% if inline_admin_form.fk_field %}{{ inline_admin_form.fk_field.field }}{% endif %}
|
||||||
|
{% spaceless %}
|
||||||
|
{% for fieldset in inline_admin_form %}
|
||||||
|
{% for line in fieldset %}
|
||||||
|
{% for field in line %}
|
||||||
|
{% if not field.is_readonly and field.field.is_hidden %}{{ field.field }}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endspaceless %}
|
||||||
|
</td>
|
||||||
|
{% for fieldset in inline_admin_form %}
|
||||||
|
{% for line in fieldset %}
|
||||||
|
{% for field in line %}
|
||||||
|
{% if field.is_readonly or not field.field.is_hidden %}
|
||||||
|
<td{% if field.field.name %} class="field-{{ field.field.name }}"{% endif %}>
|
||||||
|
{% if field.is_readonly %}
|
||||||
|
<p>{{ field.contents }}</p>
|
||||||
|
{% else %}
|
||||||
|
{{ field.field.errors.as_ul }}
|
||||||
|
{{ field.field }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
{% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission %}
|
||||||
|
<td class="delete">{% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %}</td>
|
||||||
|
{% endif %}
|
||||||
|
<td class="clone">{{ inline_admin_form.clone_field.field }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -1,20 +1,22 @@
|
|||||||
|
from adminsortable2.admin import SortableAdminMixin, SortableInlineAdminMixin
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from inline_actions.admin import InlineActionsMixin
|
||||||
|
from inline_actions.admin import InlineActionsModelAdminMixin
|
||||||
|
|
||||||
from ..models.training_plan import TrainingPlan, TrainingPlanDetail, TrainingPlanTranslation
|
from ..models.training_plan import TrainingPlan, TrainingPlanDetail, TrainingPlanTranslation
|
||||||
|
|
||||||
|
|
||||||
class TrainingPlanDetailInline(admin.TabularInline):
|
class TrainingPlanDetailInline(InlineActionsMixin, SortableInlineAdminMixin, admin.TabularInline):
|
||||||
model = TrainingPlanDetail
|
model = TrainingPlanDetail
|
||||||
#fk_name = 'training_plan_detail_id'
|
|
||||||
extra = 0
|
extra = 0
|
||||||
list_display = (
|
list_display = (
|
||||||
'training_plan', 'exercise_type', 'sort', 'set', 'repeats', 'max', 'weight', 'calc',
|
'sort', 'training_plan', 'exercise_type', 'set', 'repeats', 'max', 'weight', 'calc',
|
||||||
'resting_time', 'parallel', 'day')
|
'resting_time', 'parallel', 'day')
|
||||||
list_filter = ('training_plan__name', 'exercise_type__name')
|
|
||||||
list_editable = (
|
list_editable = (
|
||||||
'exercise_type', 'sort', 'set', 'repeats', 'weight', 'resting_time', 'parallel', 'day')
|
'sort', 'exercise_type', 'set', 'repeats', 'weight', 'resting_time', 'parallel', 'day')
|
||||||
|
list_display_links = ('sort', )
|
||||||
ordering = ('sort',)
|
ordering = ('sort',)
|
||||||
|
|
||||||
def repeat_max(self, obj):
|
def repeat_max(self, obj):
|
||||||
@ -39,12 +41,17 @@ class TrainingPlanDetailInline(admin.TabularInline):
|
|||||||
pass
|
pass
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def copy_attributes(self, request, queryset):
|
def get_inline_actions(self, request, obj=None):
|
||||||
name = str(queryset[0].training_plan)
|
actions = super(TrainingPlanDetailInline, self).get_inline_actions(request, obj)
|
||||||
|
return actions
|
||||||
|
|
||||||
|
def copy_attributes(self, request, obj, parent_obj=None):
|
||||||
|
|
||||||
|
name = str(request.queryset[0].training_plan)
|
||||||
details = TrainingPlanDetail.objects.filter(training_plan__name=name).order_by('sort')
|
details = TrainingPlanDetail.objects.filter(training_plan__name=name).order_by('sort')
|
||||||
new_sort = details[len(details) - 1].sort + 1
|
new_sort = details[len(details) - 1].sort + 1
|
||||||
|
|
||||||
for objectAttr in queryset:
|
for objectAttr in request.queryset:
|
||||||
objectAttr.pk = None
|
objectAttr.pk = None
|
||||||
objectAttr.sort = new_sort
|
objectAttr.sort = new_sort
|
||||||
objectAttr.save()
|
objectAttr.save()
|
||||||
@ -82,8 +89,6 @@ class TrainingPlanDetailInline(admin.TabularInline):
|
|||||||
html = '<span style="color: #{};font-size:32px">{}</span>'.format(color_code, "*")
|
html = '<span style="color: #{};font-size:32px">{}</span>'.format(color_code, "*")
|
||||||
return format_html(html)
|
return format_html(html)
|
||||||
|
|
||||||
actions = [copy_attributes, select_max_repeat, select_weight_calc]
|
|
||||||
|
|
||||||
|
|
||||||
class TranslationTrainingPlanInline(admin.TabularInline):
|
class TranslationTrainingPlanInline(admin.TabularInline):
|
||||||
model = TrainingPlanTranslation
|
model = TrainingPlanTranslation
|
||||||
@ -91,7 +96,7 @@ class TranslationTrainingPlanInline(admin.TabularInline):
|
|||||||
extra = 0
|
extra = 0
|
||||||
|
|
||||||
|
|
||||||
class TrainingPlanAdmin(admin.ModelAdmin):
|
class TrainingPlanAdmin(InlineActionsModelAdminMixin, admin.ModelAdmin):
|
||||||
list_display = ('training_plan_id', 'name', 'internal_name', 'free', 'active')
|
list_display = ('training_plan_id', 'name', 'internal_name', 'free', 'active')
|
||||||
fields = ('tree', 'name', 'description', 'internal_name', 'free', 'active')
|
fields = ('tree', 'name', 'description', 'internal_name', 'free', 'active')
|
||||||
list_editable = ('name', 'internal_name', 'free', 'active')
|
list_editable = ('name', 'internal_name', 'free', 'active')
|
||||||
@ -101,14 +106,41 @@ class TrainingPlanAdmin(admin.ModelAdmin):
|
|||||||
TrainingPlanDetailInline
|
TrainingPlanDetailInline
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@admin.action(description='clone selected training plans')
|
||||||
|
def clone(self, request, queryset):
|
||||||
|
for trainingPlan in queryset:
|
||||||
|
print("clone " + trainingPlan.name)
|
||||||
|
id = trainingPlan.training_plan_id
|
||||||
|
trainingPlan.pk = None
|
||||||
|
trainingPlan.name = trainingPlan.name + " COPY"
|
||||||
|
trainingPlan.internal_name = trainingPlan.internal_name + "_copy"
|
||||||
|
trainingPlan.active = False
|
||||||
|
trainingPlan.save()
|
||||||
|
newId = trainingPlan.pk
|
||||||
|
|
||||||
class TrainingPlanDetailAdmin(admin.ModelAdmin):
|
details = TrainingPlanDetail.objects.filter(training_plan__training_plan_id=id)
|
||||||
|
for detail in details:
|
||||||
|
detail.pk = None
|
||||||
|
detail.training_plan_id = newId
|
||||||
|
detail.save()
|
||||||
|
|
||||||
|
translations = TrainingPlanTranslation.objects.filter(training_plan__training_plan_id=id)
|
||||||
|
for translation in translations:
|
||||||
|
translation.pk = None
|
||||||
|
translation.training_plan_id = newId
|
||||||
|
translation.name_translation = translation.name_translation + " COPY"
|
||||||
|
translation.save()
|
||||||
|
|
||||||
|
actions = ['clone']
|
||||||
|
|
||||||
|
|
||||||
|
class TrainingPlanDetailAdmin(SortableAdminMixin, admin.ModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'training_plan', 'exercise_type', 'sort', 'set', 'repeats', 'max', 'weight', 'calc',
|
'sort', 'training_plan', 'exercise_type', 'set', 'repeats', 'max', 'weight', 'calc',
|
||||||
'resting_time', 'parallel', 'day')
|
'resting_time', 'parallel', 'day')
|
||||||
list_filter = ('training_plan__name', 'exercise_type__name')
|
list_filter = ('training_plan__name', 'exercise_type__name')
|
||||||
list_editable = (
|
list_editable = (
|
||||||
'exercise_type', 'sort', 'set', 'repeats', 'weight', 'resting_time', 'parallel', 'day')
|
'exercise_type', 'set', 'repeats', 'weight', 'resting_time', 'parallel', 'day')
|
||||||
ordering = ('sort',)
|
ordering = ('sort',)
|
||||||
|
|
||||||
def repeat_max(self, obj):
|
def repeat_max(self, obj):
|
||||||
@ -180,5 +212,5 @@ class TrainingPlanDetailAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
|
|
||||||
admin.site.register(TrainingPlan, TrainingPlanAdmin)
|
admin.site.register(TrainingPlan, TrainingPlanAdmin)
|
||||||
#admin.site.register(TrainingPlanDetail, TrainingPlanDetailAdmin)
|
admin.site.register(TrainingPlanDetail, TrainingPlanDetailAdmin)
|
||||||
admin.autodiscover()
|
admin.autodiscover()
|
||||||
|
@ -43,6 +43,7 @@ class TrainingPlanDetail(models.Model):
|
|||||||
db_table = 'training_plan_detail'
|
db_table = 'training_plan_detail'
|
||||||
verbose_name = _("Training Plan Detail")
|
verbose_name = _("Training Plan Detail")
|
||||||
verbose_name_plural = _("Training Plan Details")
|
verbose_name_plural = _("Training Plan Details")
|
||||||
|
ordering = ['sort']
|
||||||
|
|
||||||
|
|
||||||
class TrainingPlanTranslation(models.Model):
|
class TrainingPlanTranslation(models.Model):
|
||||||
|
@ -49,6 +49,8 @@ INSTALLED_APPS = [
|
|||||||
'ckeditor_uploader',
|
'ckeditor_uploader',
|
||||||
'django_admin_json_editor',
|
'django_admin_json_editor',
|
||||||
'rangefilter',
|
'rangefilter',
|
||||||
|
'adminsortable2',
|
||||||
|
'inline_actions',
|
||||||
#'django_cron',
|
#'django_cron',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -45,6 +45,8 @@ INSTALLED_APPS = [
|
|||||||
'ckeditor_uploader',
|
'ckeditor_uploader',
|
||||||
'django_admin_json_editor',
|
'django_admin_json_editor',
|
||||||
'rangefilter',
|
'rangefilter',
|
||||||
|
'adminsortable2',
|
||||||
|
'inline_actions',
|
||||||
#'django_cron',
|
#'django_cron',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user