9 Commits

22 changed files with 381 additions and 23 deletions

View File

@@ -0,0 +1,34 @@
# Generated by Django 4.1 on 2022-08-24 15:30
import markdown
from django.db import migrations
def md_to_html(apps, schema_editor):
fields = {
"Consist": ["notes"],
}
for m in fields.items():
model = apps.get_model("consist", m[0])
for row in model.objects.all():
for field in m[1]:
html = markdown.markdown(getattr(row, field))
row.__dict__[field] = html
row.save(update_fields=m[1])
class Migration(migrations.Migration):
dependencies = [
("consist", "0005_alter_consist_notes"),
]
operations = [
migrations.RunPython(
md_to_html,
reverse_code=migrations.RunPython.noop
),
]

View File

@@ -20,8 +20,8 @@ class PropertyAdmin(admin.ModelAdmin):
@admin.register(Decoder) @admin.register(Decoder)
class DecoderAdmin(admin.ModelAdmin): class DecoderAdmin(admin.ModelAdmin):
readonly_fields = ("image_thumbnail",) readonly_fields = ("image_thumbnail",)
list_display = ("__str__", "interface") list_display = ("__str__", "sound")
list_filter = ("manufacturer", "interface") list_filter = ("manufacturer", "sound")
search_fields = ("name", "manufacturer__name") search_fields = ("name", "manufacturer__name")

View File

@@ -0,0 +1,18 @@
# Generated by Django 4.1.2 on 2022-10-31 23:01
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("metadata", "0007_rename_track_scale_tracks"),
("roster", "0013_rollingstock_decoder_interface"),
]
operations = [
migrations.RemoveField(
model_name="decoder",
name="interface",
),
]

View File

@@ -66,9 +66,6 @@ class Decoder(models.Model):
limit_choices_to={"category": "model"}, limit_choices_to={"category": "model"},
) )
version = models.CharField(max_length=64, blank=True) version = models.CharField(max_length=64, blank=True)
interface = models.PositiveSmallIntegerField(
choices=settings.DECODER_INTERFACES, null=True, blank=True
)
sound = models.BooleanField(default=False) sound = models.BooleanField(default=False)
image = models.ImageField(upload_to="images/", null=True, blank=True) image = models.ImageField(upload_to="images/", null=True, blank=True)

View File

@@ -9,7 +9,8 @@ admin.site.register(SiteConfiguration, SingletonModelAdmin)
@admin.register(Flatpage) @admin.register(Flatpage)
class FlatpageAdmin(admin.ModelAdmin): class FlatpageAdmin(admin.ModelAdmin):
readonly_fields = ("path", "creation_time", "updated_time") readonly_fields = ("path", "creation_time", "updated_time")
list_display = ("name", "path") list_display = ("name", "path", "published", "get_link")
list_filter = ("published",)
search_fields = ("name",) search_fields = ("name",)
fieldsets = ( fieldsets = (
@@ -20,7 +21,7 @@ class FlatpageAdmin(admin.ModelAdmin):
"name", "name",
"path", "path",
"content", "content",
"draft", "published",
) )
}, },
), ),

View File

@@ -0,0 +1,38 @@
# Generated by Django 4.1 on 2022-08-24 15:00
import markdown
from django.db import migrations
def md_to_html(apps, schema_editor):
fields = {
"SiteConfiguration": ["about", "footer", "footer_extended"],
"Flatpage": ["content"]
}
for m in fields.items():
model = apps.get_model("portal", m[0])
for row in model.objects.all():
for field in m[1]:
html = markdown.markdown(getattr(row, field))
row.__dict__[field] = html
row.save(update_fields=m[1])
class Migration(migrations.Migration):
dependencies = [
(
"portal",
"0011_alter_flatpage_content_alter_siteconfiguration_about_and_more",
),
]
operations = [
migrations.RunPython(
md_to_html,
reverse_code=migrations.RunPython.noop
),
]

View File

@@ -0,0 +1,42 @@
# Generated by Django 4.1 on 2022-08-25 10:18
from django.db import migrations, models
def reverse_bool(apps, schema_editor):
model = apps.get_model("portal", "Flatpage")
for row in model.objects.all():
row.published = not row.draft
row.save(update_fields=["published"])
def reverse_bool_back(apps, schema_editor):
model = apps.get_model("portal", "Flatpage")
for row in model.objects.all():
row.draft = not row.published
row.save(update_fields=["draft"])
class Migration(migrations.Migration):
dependencies = [
("portal", "0012_md_to_html"),
]
operations = [
migrations.AddField(
model_name="flatpage",
name="published",
field=models.BooleanField(default=False),
),
migrations.RunPython(
reverse_bool,
reverse_code=reverse_bool_back
),
migrations.RemoveField(
model_name="flatpage",
name="draft",
),
]

View File

@@ -2,6 +2,7 @@ import django
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from django.dispatch.dispatcher import receiver from django.dispatch.dispatcher import receiver
from django.utils.safestring import mark_safe
from solo.models import SingletonModel from solo.models import SingletonModel
from ckeditor.fields import RichTextField from ckeditor.fields import RichTextField
@@ -51,7 +52,7 @@ class SiteConfiguration(SingletonModel):
class Flatpage(models.Model): class Flatpage(models.Model):
name = models.CharField(max_length=256, unique=True) name = models.CharField(max_length=256, unique=True)
path = models.CharField(max_length=256, unique=True) path = models.CharField(max_length=256, unique=True)
draft = models.BooleanField(default=True) published = models.BooleanField(default=False)
content = RichTextUploadingField() content = RichTextUploadingField()
creation_time = models.DateTimeField(auto_now_add=True) creation_time = models.DateTimeField(auto_now_add=True)
updated_time = models.DateTimeField(auto_now=True) updated_time = models.DateTimeField(auto_now=True)
@@ -62,6 +63,14 @@ class Flatpage(models.Model):
def get_absolute_url(self): def get_absolute_url(self):
return reverse("flatpage", kwargs={"flatpage": self.path}) return reverse("flatpage", kwargs={"flatpage": self.path})
def get_link(self):
if self.published:
return mark_safe(
'<a href="{0}" target="_blank">Link</a>'.format(
self.get_absolute_url()
)
)
@receiver(models.signals.pre_save, sender=Flatpage) @receiver(models.signals.pre_save, sender=Flatpage)
def tag_pre_save(sender, instance, **kwargs): def tag_pre_save(sender, instance, **kwargs):

View File

@@ -23,6 +23,15 @@ a.badge, a.badge:hover {
padding: .5rem; padding: .5rem;
} }
#nav-journal ul, #nav-journal ol {
margin: 0;
padding-left: 1rem;
}
#nav-journal p {
margin: 0;
}
#footer > p { #footer > p {
display: inline; display: inline;
} }

View File

@@ -59,7 +59,7 @@
<ul class="pagination justify-content-center mt-4 mb-0"> <ul class="pagination justify-content-center mt-4 mb-0">
{% if company.has_previous %} {% if company.has_previous %}
<li class="page-item"> <li class="page-item">
<a class="page-link" href="{% url 'company_pagination' page=company.previous_page_number %}#rolling-stock" tabindex="-1">Previous</a> <a class="page-link" href="{% url 'companies_pagination' page=company.previous_page_number %}#rolling-stock" tabindex="-1">Previous</a>
</li> </li>
{% else %} {% else %}
<li class="page-item disabled"> <li class="page-item disabled">
@@ -75,13 +75,13 @@
{% if i == company.paginator.ELLIPSIS %} {% if i == company.paginator.ELLIPSIS %}
<li class="page-item"><span class="page-link">{{ i }}</span></li> <li class="page-item"><span class="page-link">{{ i }}</span></li>
{% else %} {% else %}
<li class="page-item"><a class="page-link" href="{% url 'company_pagination' page=i %}#rolling-stock">{{ i }}</a></li> <li class="page-item"><a class="page-link" href="{% url 'companies_pagination' page=i %}#rolling-stock">{{ i }}</a></li>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% if company.has_next %} {% if company.has_next %}
<li class="page-item"> <li class="page-item">
<a class="page-link" href="{% url 'company_pagination' page=company.next_page_number %}#rolling-stock" tabindex="-1">Next</a> <a class="page-link" href="{% url 'companies_pagination' page=company.next_page_number %}#rolling-stock" tabindex="-1">Next</a>
</li> </li>
{% else %} {% else %}
<li class="page-item disabled"> <li class="page-item disabled">

View File

@@ -3,10 +3,10 @@
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false">
More ... More ...
</a> </a>
{% for m in menu %}
<ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink"> <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
{% for m in menu %}
<li><a class="dropdown-item" href="{{ m.get_absolute_url }}">{{ m.name }}</a></li> <li><a class="dropdown-item" href="{{ m.get_absolute_url }}">{{ m.name }}</a></li>
</ul>
{% endfor %} {% endfor %}
</ul>
</li> </li>
{% endif %} {% endif %}

View File

@@ -7,6 +7,7 @@
<li><a class="dropdown-item" href="{% url 'admin:roster_rollingstock_changelist' %}">Rolling stock</a></li> <li><a class="dropdown-item" href="{% url 'admin:roster_rollingstock_changelist' %}">Rolling stock</a></li>
<li><a class="dropdown-item" href="{% url 'admin:consist_consist_changelist' %}">Consists</a></li> <li><a class="dropdown-item" href="{% url 'admin:consist_consist_changelist' %}">Consists</a></li>
<li><a class="dropdown-item" href="{% url 'admin:app_list' 'metadata' %}">Metadata</a></li> <li><a class="dropdown-item" href="{% url 'admin:app_list' 'metadata' %}">Metadata</a></li>
<li><a class="dropdown-item" href="{% url 'admin:portal_flatpage_changelist' %}">Pages</a></li>
<li><hr class="dropdown-divider"></li> <li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="{% url 'admin:index' %}">Admin</a></li> <li><a class="dropdown-item" href="{% url 'admin:index' %}">Admin</a></li>
<li><a class="dropdown-item" href="{% url 'admin:portal_siteconfiguration_changelist' %}">Site configuration</a></li> <li><a class="dropdown-item" href="{% url 'admin:portal_siteconfiguration_changelist' %}">Site configuration</a></li>

View File

@@ -47,6 +47,7 @@
{% if rolling_stock.decoder %}<button class="nav-link" id="nav-dcc-tab" data-bs-toggle="tab" data-bs-target="#nav-dcc" type="button" role="tab" aria-controls="nav-dcc" aria-selected="false">DCC</button>{% endif %} {% if rolling_stock.decoder %}<button class="nav-link" id="nav-dcc-tab" data-bs-toggle="tab" data-bs-target="#nav-dcc" type="button" role="tab" aria-controls="nav-dcc" aria-selected="false">DCC</button>{% endif %}
{% if rolling_stock.notes %}<button class="nav-link" id="nav-notes-tab" data-bs-toggle="tab" data-bs-target="#nav-notes" type="button" role="tab" aria-controls="nav-notes" aria-selected="false">Notes</button>{% endif %} {% if rolling_stock.notes %}<button class="nav-link" id="nav-notes-tab" data-bs-toggle="tab" data-bs-target="#nav-notes" type="button" role="tab" aria-controls="nav-notes" aria-selected="false">Notes</button>{% endif %}
{% if rolling_stock.document.count > 0 %}<button class="nav-link" id="nav-documents-tab" data-bs-toggle="tab" data-bs-target="#nav-documents" type="button" role="tab" aria-controls="nav-documents" aria-selected="false">Documents</button>{% endif %} {% if rolling_stock.document.count > 0 %}<button class="nav-link" id="nav-documents-tab" data-bs-toggle="tab" data-bs-target="#nav-documents" type="button" role="tab" aria-controls="nav-documents" aria-selected="false">Documents</button>{% endif %}
{% if rolling_stock_journal.count > 0 %}<button class="nav-link" id="nav-journal-tab" data-bs-toggle="tab" data-bs-target="#nav-journal" type="button" role="tab" aria-controls="nav-journal" aria-selected="false">Journal</button>{% endif %}
</div> </div>
</nav> </nav>
<div class="tab-content" id="nav-tabContent"> <div class="tab-content" id="nav-tabContent">
@@ -101,7 +102,7 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
{% if rolling_stock.decoder %} {% if rolling_stock.decoder or rolling_stock.decoder_interface %}
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
<tr> <tr>
@@ -110,13 +111,19 @@
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<th width="35%" scope="row">Decoder</th> <th width="35%" scope="row">Interface</th>
<td>{{ rolling_stock.get_decoder_interface_display }}</td>
</tr>
{% if rolling_stock.decoder %}
<tr>
<th scope="row">Decoder</th>
<td>{{ rolling_stock.decoder }}</td> <td>{{ rolling_stock.decoder }}</td>
</tr> </tr>
<tr> <tr>
<th scope="row">Address</th> <th scope="row">Address</th>
<td>{{ rolling_stock.address }}</td> <td>{{ rolling_stock.address }}</td>
</tr> </tr>
{% endif %}
</tbody> </tbody>
</table> </table>
{% endif %} {% endif %}
@@ -229,6 +236,10 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr>
<th scope="row">Interface</th>
<td>{{ rolling_stock.get_decoder_interface_display }}</td>
</tr>
<tr> <tr>
<th width="35%" scope="row">Address</th> <th width="35%" scope="row">Address</th>
<td>{{ rolling_stock.address }}</td> <td>{{ rolling_stock.address }}</td>
@@ -245,10 +256,6 @@
<th scope="row">Version</th> <th scope="row">Version</th>
<td>{{ rolling_stock.decoder.version }}</td> <td>{{ rolling_stock.decoder.version }}</td>
</tr> </tr>
<tr>
<th scope="row">Interface</th>
<td>{{ rolling_stock.decoder.get_interface_display }}</td>
</tr>
<tr> <tr>
<th scope="row">Sound</th> <th scope="row">Sound</th>
<td>{{ rolling_stock.decoder.sound | yesno:"Yes,No" }}</td> <td>{{ rolling_stock.decoder.sound | yesno:"Yes,No" }}</td>
@@ -277,6 +284,23 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="tab-pane fade" id="nav-journal" role="tabpanel" aria-labelledby="nav-journal-tab">
<table class="table table-striped">
<thead>
<tr>
<th colspan="3" scope="row">Journal</th>
</tr>
</thead>
<tbody>
{% for j in rolling_stock_journal %}
<tr>
<th width="35%" scope="row">{{ j.date }}</th>
<td>{{ j.log | safe }}</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div> </div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end"> <div class="d-grid gap-2 d-md-flex justify-content-md-end">
{% if request.user.is_staff %}<a class="btn btn-sm btn-outline-danger" href="{% url 'admin:roster_rollingstock_change' rolling_stock.pk %}">Edit</a>{% endif %} {% if request.user.is_staff %}<a class="btn btn-sm btn-outline-danger" href="{% url 'admin:roster_rollingstock_change' rolling_stock.pk %}">Edit</a>{% endif %}

View File

@@ -6,5 +6,5 @@ register = template.Library()
@register.inclusion_tag('flatpage_menu.html') @register.inclusion_tag('flatpage_menu.html')
def show_menu(): def show_menu():
menu = Flatpage.objects.all() menu = Flatpage.objects.filter(published=True).order_by("name")
return {"menu": menu} return {"menu": menu}

View File

@@ -154,6 +154,12 @@ class GetRollingStock(View):
else rolling_stock.property.filter(property__private=False) else rolling_stock.property.filter(property__private=False)
) )
rolling_stock_journal = (
rolling_stock.journal.all()
if request.user.is_authenticated
else rolling_stock.journal.filter(private=False)
)
return render( return render(
request, request,
"page.html", "page.html",
@@ -161,6 +167,7 @@ class GetRollingStock(View):
"rolling_stock": rolling_stock, "rolling_stock": rolling_stock,
"class_properties": class_properties, "class_properties": class_properties,
"rolling_stock_properties": rolling_stock_properties, "rolling_stock_properties": rolling_stock_properties,
"rolling_stock_journal": rolling_stock_journal,
}, },
) )
@@ -249,7 +256,7 @@ class GetFlatpage(View):
def get(self, request, flatpage): def get(self, request, flatpage):
try: try:
flatpage = Flatpage.objects.get( flatpage = Flatpage.objects.get(
Q(Q(path=flatpage) & Q(draft=False)) Q(Q(path=flatpage) & Q(published=True))
) )
except ObjectDoesNotExist: except ObjectDoesNotExist:
raise Http404 raise Http404

View File

@@ -1,4 +1,4 @@
from ram.utils import git_suffix from ram.utils import git_suffix
__version__ = "0.0.16" __version__ = "0.0.20"
__version__ += git_suffix(__file__) __version__ += git_suffix(__file__)

View File

@@ -6,6 +6,7 @@ from roster.models import (
RollingStockImage, RollingStockImage,
RollingStockDocument, RollingStockDocument,
RollingStockProperty, RollingStockProperty,
RollingStockJournal,
) )
@@ -31,6 +32,7 @@ class RollingStockDocInline(admin.TabularInline):
model = RollingStockDocument model = RollingStockDocument
min_num = 0 min_num = 0
extra = 0 extra = 0
classes = ["collapse"]
class RollingStockImageInline(admin.TabularInline): class RollingStockImageInline(admin.TabularInline):
@@ -38,6 +40,7 @@ class RollingStockImageInline(admin.TabularInline):
min_num = 0 min_num = 0
extra = 0 extra = 0
readonly_fields = ("image_thumbnail",) readonly_fields = ("image_thumbnail",)
classes = ["collapse"]
class RollingStockPropertyInline(admin.TabularInline): class RollingStockPropertyInline(admin.TabularInline):
@@ -46,6 +49,13 @@ class RollingStockPropertyInline(admin.TabularInline):
extra = 0 extra = 0
class RollingStockJournalInline(admin.TabularInline):
model = RollingStockJournal
min_num = 0
extra = 0
classes = ["collapse"]
@admin.register(RollingStockDocument) @admin.register(RollingStockDocument)
class RollingStockDocumentAdmin(admin.ModelAdmin): class RollingStockDocumentAdmin(admin.ModelAdmin):
list_display = ( list_display = (
@@ -62,12 +72,33 @@ class RollingStockDocumentAdmin(admin.ModelAdmin):
) )
@admin.register(RollingStockJournal)
class RollingJournalDocumentAdmin(admin.ModelAdmin):
list_display = (
"__str__",
"date",
"rolling_stock",
"private",
)
list_filter = (
"date",
"private",
)
search_fields = (
"rolling_stock__rolling_class__identifier",
"rolling_stock__road_number",
"rolling_stock__sku",
"log",
)
@admin.register(RollingStock) @admin.register(RollingStock)
class RollingStockAdmin(admin.ModelAdmin): class RollingStockAdmin(admin.ModelAdmin):
inlines = ( inlines = (
RollingStockPropertyInline, RollingStockPropertyInline,
RollingStockImageInline, RollingStockImageInline,
RollingStockDocInline, RollingStockDocInline,
RollingStockJournalInline,
) )
readonly_fields = ("creation_time", "updated_time") readonly_fields = ("creation_time", "updated_time")
list_display = ( list_display = (
@@ -117,6 +148,7 @@ class RollingStockAdmin(admin.ModelAdmin):
"DCC", "DCC",
{ {
"fields": ( "fields": (
"decoder_interface",
"decoder", "decoder",
"address", "address",
) )

View File

@@ -0,0 +1,34 @@
# Generated by Django 4.1 on 2022-08-24 15:30
import markdown
from django.db import migrations
def md_to_html(apps, schema_editor):
fields = {
"RollingStock": ["notes"],
}
for m in fields.items():
model = apps.get_model("roster", m[0])
for row in model.objects.all():
for field in m[1]:
html = markdown.markdown(getattr(row, field))
row.__dict__[field] = html
row.save(update_fields=m[1])
class Migration(migrations.Migration):
dependencies = [
("roster", "0010_alter_rollingstock_notes"),
]
operations = [
migrations.RunPython(
md_to_html,
reverse_code=migrations.RunPython.noop
),
]

View File

@@ -0,0 +1,45 @@
# Generated by Django 4.1 on 2022-08-27 12:43
import ckeditor_uploader.fields
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("roster", "0011_md_to_html"),
]
operations = [
migrations.CreateModel(
name="RollingStockJournal",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("date", models.DateField()),
("log", ckeditor_uploader.fields.RichTextUploadingField()),
("private", models.BooleanField(default=False)),
("creation_time", models.DateTimeField(auto_now_add=True)),
("updated_time", models.DateTimeField(auto_now=True)),
(
"rolling_stock",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="journal",
to="roster.rollingstock",
),
),
],
options={
"ordering": ["date", "rolling_stock"],
},
),
]

View File

@@ -0,0 +1,42 @@
# Generated by Django 4.1 on 2022-10-31 22:27
from django.db import migrations, models
def meta_to_roster(apps, schema_editor):
model = apps.get_model("roster", "RollingStock")
for row in model.objects.all():
if row.decoder:
decoder_interface = row.decoder.interface
row.__dict__["decoder_interface"] = decoder_interface
row.save(update_fields=["decoder_interface"])
class Migration(migrations.Migration):
dependencies = [
("roster", "0012_rollingstockjournal"),
]
operations = [
migrations.AddField(
model_name="rollingstock",
name="decoder_interface",
field=models.PositiveSmallIntegerField(
blank=True,
choices=[
(1, "NEM651"),
(2, "NEM652"),
(3, "PluX"),
(4, "21MTC"),
(5, "Next18/Next18S"),
],
null=True,
),
),
migrations.RunPython(
meta_to_roster,
reverse_code=migrations.RunPython.noop
),
]

View File

@@ -3,6 +3,7 @@ import re
from uuid import uuid4 from uuid import uuid4
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from django.conf import settings
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
@@ -87,6 +88,9 @@ class RollingStock(models.Model):
) )
scale = models.ForeignKey(Scale, on_delete=models.CASCADE) scale = models.ForeignKey(Scale, on_delete=models.CASCADE)
sku = models.CharField(max_length=32, blank=True) sku = models.CharField(max_length=32, blank=True)
decoder_interface = models.PositiveSmallIntegerField(
choices=settings.DECODER_INTERFACES, null=True, blank=True
)
decoder = models.ForeignKey( decoder = models.ForeignKey(
Decoder, on_delete=models.CASCADE, null=True, blank=True Decoder, on_delete=models.CASCADE, null=True, blank=True
) )
@@ -191,6 +195,27 @@ class RollingStockProperty(models.Model):
verbose_name_plural = "Properties" verbose_name_plural = "Properties"
class RollingStockJournal(models.Model):
rolling_stock = models.ForeignKey(
RollingStock,
on_delete=models.CASCADE,
related_name="journal",
null=False,
blank=False,
)
date = models.DateField()
log = RichTextUploadingField()
private = models.BooleanField(default=False)
creation_time = models.DateTimeField(auto_now_add=True)
updated_time = models.DateTimeField(auto_now=True)
def __str__(self):
return "{0} - {1}".format(self.rolling_stock, self.date)
class Meta:
ordering = ["date", "rolling_stock"]
# @receiver(models.signals.post_delete, sender=Cab) # @receiver(models.signals.post_delete, sender=Cab)
# def post_save_image(sender, instance, *args, **kwargs): # def post_save_image(sender, instance, *args, **kwargs):
# try: # try: