changing image size in truck reg
This commit is contained in:
parent
c5c799b7d6
commit
d8b540ccd4
Binary file not shown.
Binary file not shown.
@ -6,6 +6,7 @@ from django.contrib import messages
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
|
import os
|
||||||
from .models import Profile, Truck, Shipment, Bid, Message, WhatsAppConfig, Country, City, TruckType, AppSetting, Banner, HomeSection
|
from .models import Profile, Truck, Shipment, Bid, Message, WhatsAppConfig, Country, City, TruckType, AppSetting, Banner, HomeSection
|
||||||
from .whatsapp import send_whatsapp_message
|
from .whatsapp import send_whatsapp_message
|
||||||
|
|
||||||
@ -38,7 +39,14 @@ class ProfileAdmin(admin.ModelAdmin):
|
|||||||
if obj.is_expired():
|
if obj.is_expired():
|
||||||
return format_html('<span style="color: red; font-weight: bold;">{}</span>', _('Expired'))
|
return format_html('<span style="color: red; font-weight: bold;">{}</span>', _('Expired'))
|
||||||
|
|
||||||
days = obj.days_until_expiry()
|
# Profile model might not have days_until_expiry, let's check
|
||||||
|
# Based on models.py read earlier, it doesn't have it.
|
||||||
|
# It has a commented out section that seems to be a start of it.
|
||||||
|
# I'll use inline calculation
|
||||||
|
if not obj.subscription_expiry:
|
||||||
|
return format_html('<span style="color: red; font-weight: bold;">{}</span>', _('No Expiry'))
|
||||||
|
|
||||||
|
days = (obj.subscription_expiry - timezone.now().date()).days
|
||||||
if days <= 7:
|
if days <= 7:
|
||||||
return format_html('<span style="color: orange; font-weight: bold;">{} ({} {})</span>', _('Expiring soon'), days, _('days'))
|
return format_html('<span style="color: orange; font-weight: bold;">{} ({} {})</span>', _('Expiring soon'), days, _('days'))
|
||||||
|
|
||||||
@ -48,9 +56,56 @@ class ProfileAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
@admin.register(Truck)
|
@admin.register(Truck)
|
||||||
class TruckAdmin(admin.ModelAdmin):
|
class TruckAdmin(admin.ModelAdmin):
|
||||||
list_display = ('display_truck_type', 'model', 'plate_no', 'owner', 'load_capacity')
|
list_display = ('display_truck_type', 'model', 'plate_no', 'owner', 'load_capacity', 'is_approved')
|
||||||
search_fields = ('plate_no', 'owner__username', 'model')
|
search_fields = ('plate_no', 'owner__username', 'model')
|
||||||
list_filter = ('truck_type_link', 'is_approved')
|
list_filter = ('truck_type_link', 'is_approved')
|
||||||
|
readonly_fields = ('truck_picture_preview', 'registration_front_preview', 'registration_back_preview', 'driver_license_front_preview', 'driver_license_back_preview')
|
||||||
|
|
||||||
|
def truck_picture_preview(self, obj):
|
||||||
|
if obj.truck_picture:
|
||||||
|
return format_html('<img src="{}" style="max-height: 200px;"/>', obj.truck_picture.url)
|
||||||
|
return "-"
|
||||||
|
truck_picture_preview.short_description = _("Truck Picture Preview")
|
||||||
|
|
||||||
|
def _file_preview(self, field):
|
||||||
|
if not field:
|
||||||
|
return "-"
|
||||||
|
url = field.url
|
||||||
|
ext = os.path.splitext(field.name)[1].lower()
|
||||||
|
if ext in ['.jpg', '.jpeg', '.png', '.webp', '.gif']:
|
||||||
|
return format_html('<a href="{}" target="_blank"><img src="{}" style="max-height: 200px;"/></a>', url, url)
|
||||||
|
elif ext == '.pdf':
|
||||||
|
return format_html('<a href="{}" target="_blank"><i class="fa fa-file-pdf" style="font-size: 48px; color: red;"></i><br>{}</a>', url, _("View PDF Document"))
|
||||||
|
return format_html('<a href="{}" target="_blank">{}</a>', url, _("View File"))
|
||||||
|
|
||||||
|
def registration_front_preview(self, obj):
|
||||||
|
return self._file_preview(obj.registration_front)
|
||||||
|
registration_front_preview.short_description = _("Registration Front Preview")
|
||||||
|
|
||||||
|
def registration_back_preview(self, obj):
|
||||||
|
return self._file_preview(obj.registration_back)
|
||||||
|
registration_back_preview.short_description = _("Registration Back Preview")
|
||||||
|
|
||||||
|
def driver_license_front_preview(self, obj):
|
||||||
|
return self._file_preview(obj.driver_license_front)
|
||||||
|
driver_license_front_preview.short_description = _("Driver License Front Preview")
|
||||||
|
|
||||||
|
def driver_license_back_preview(self, obj):
|
||||||
|
return self._file_preview(obj.driver_license_back)
|
||||||
|
driver_license_back_preview.short_description = _("Driver License Back Preview")
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
(None, {'fields': ('owner', 'truck_type_link', 'is_approved')}),
|
||||||
|
(_('Details (EN)'), {'fields': ('truck_type', 'model', 'load_capacity', 'color', 'year', 'plate_no', 'registration_expiry_date')}),
|
||||||
|
(_('Details (AR)'), {'fields': ('truck_type_ar', 'model_ar', 'load_capacity_ar', 'color_ar')}),
|
||||||
|
(_('Pictures & Documents'), {'fields': (
|
||||||
|
'truck_picture', 'truck_picture_preview',
|
||||||
|
'registration_front', 'registration_front_preview',
|
||||||
|
'registration_back', 'registration_back_preview',
|
||||||
|
'driver_license_front', 'driver_license_front_preview',
|
||||||
|
'driver_license_back', 'driver_license_back_preview'
|
||||||
|
)}),
|
||||||
|
)
|
||||||
|
|
||||||
@admin.register(Shipment)
|
@admin.register(Shipment)
|
||||||
class ShipmentAdmin(admin.ModelAdmin):
|
class ShipmentAdmin(admin.ModelAdmin):
|
||||||
@ -134,4 +189,4 @@ class HomeSectionAdmin(admin.ModelAdmin):
|
|||||||
list_display = ('title', 'section_type', 'order', 'is_active')
|
list_display = ('title', 'section_type', 'order', 'is_active')
|
||||||
list_editable = ('order', 'is_active')
|
list_editable = ('order', 'is_active')
|
||||||
list_filter = ('section_type', 'is_active', 'background_color')
|
list_filter = ('section_type', 'is_active', 'background_color')
|
||||||
search_fields = ('title', 'title_ar', 'subtitle', 'subtitle_ar', 'content', 'content_ar')
|
search_fields = ('title', 'title_ar', 'subtitle', 'subtitle_ar', 'content', 'content_ar')
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2026-01-24 07:51
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0021_appsetting_thawani_enabled'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='truck',
|
||||||
|
name='driver_license_back',
|
||||||
|
field=models.FileField(blank=True, null=True, upload_to='docs/', verbose_name='Driver License (Back Face)'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='truck',
|
||||||
|
name='driver_license_front',
|
||||||
|
field=models.FileField(blank=True, null=True, upload_to='docs/', verbose_name='Driver License (Front Face)'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='truck',
|
||||||
|
name='registration_back',
|
||||||
|
field=models.FileField(blank=True, null=True, upload_to='docs/', verbose_name='Registration (Back Face)'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='truck',
|
||||||
|
name='registration_front',
|
||||||
|
field=models.FileField(blank=True, null=True, upload_to='docs/', verbose_name='Registration (Front Face)'),
|
||||||
|
),
|
||||||
|
]
|
||||||
Binary file not shown.
@ -5,8 +5,12 @@ from django.dispatch import receiver
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.utils.translation import get_language
|
from django.utils.translation import get_language
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.core.files import File
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
|
import os
|
||||||
|
from io import BytesIO
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
class Country(models.Model):
|
class Country(models.Model):
|
||||||
name = models.CharField(_('Country Name'), max_length=100)
|
name = models.CharField(_('Country Name'), max_length=100)
|
||||||
@ -127,10 +131,10 @@ class Truck(models.Model):
|
|||||||
|
|
||||||
# Pictures
|
# Pictures
|
||||||
truck_picture = models.ImageField(_('Truck Picture'), upload_to='trucks/', blank=True, null=True)
|
truck_picture = models.ImageField(_('Truck Picture'), upload_to='trucks/', blank=True, null=True)
|
||||||
registration_front = models.ImageField(_('Registration (Front Face)'), upload_to='docs/', blank=True, null=True)
|
registration_front = models.FileField(_('Registration (Front Face)'), upload_to='docs/', blank=True, null=True)
|
||||||
registration_back = models.ImageField(_('Registration (Back Face)'), upload_to='docs/', blank=True, null=True)
|
registration_back = models.FileField(_('Registration (Back Face)'), upload_to='docs/', blank=True, null=True)
|
||||||
driver_license_front = models.ImageField(_('Driver License (Front Face)'), upload_to='docs/', blank=True, null=True)
|
driver_license_front = models.FileField(_('Driver License (Front Face)'), upload_to='docs/', blank=True, null=True)
|
||||||
driver_license_back = models.ImageField(_('Driver License (Back Face)'), upload_to='docs/', blank=True, null=True)
|
driver_license_back = models.FileField(_('Driver License (Back Face)'), upload_to='docs/', blank=True, null=True)
|
||||||
|
|
||||||
is_approved = models.BooleanField(_('Is Approved'), default=False)
|
is_approved = models.BooleanField(_('Is Approved'), default=False)
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
@ -166,6 +170,55 @@ class Truck(models.Model):
|
|||||||
return self.color_ar
|
return self.color_ar
|
||||||
return self.color
|
return self.color
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
# Compress images
|
||||||
|
if self.truck_picture:
|
||||||
|
self.truck_picture = self.compress_image(self.truck_picture)
|
||||||
|
|
||||||
|
# For docs, compress only if they are images
|
||||||
|
if self.registration_front:
|
||||||
|
self.registration_front = self.compress_image(self.registration_front)
|
||||||
|
if self.registration_back:
|
||||||
|
self.registration_back = self.compress_image(self.registration_back)
|
||||||
|
if self.driver_license_front:
|
||||||
|
self.driver_license_front = self.compress_image(self.driver_license_front)
|
||||||
|
if self.driver_license_back:
|
||||||
|
self.driver_license_back = self.compress_image(self.driver_license_back)
|
||||||
|
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
def compress_image(self, image_field):
|
||||||
|
if not image_field:
|
||||||
|
return image_field
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Check file extension
|
||||||
|
ext = os.path.splitext(image_field.name)[1].lower()
|
||||||
|
if ext not in ['.jpg', '.jpeg', '.png', '.webp']:
|
||||||
|
return image_field
|
||||||
|
|
||||||
|
img = Image.open(image_field)
|
||||||
|
|
||||||
|
# If already small enough, don't compress (optional, but good for performance)
|
||||||
|
# if image_field.size < 300 * 1024: return image_field
|
||||||
|
|
||||||
|
if img.mode != 'RGB':
|
||||||
|
img = img.convert('RGB')
|
||||||
|
|
||||||
|
# Resize if too large
|
||||||
|
max_size = (1200, 1200)
|
||||||
|
img.thumbnail(max_size, Image.LANCZOS)
|
||||||
|
|
||||||
|
output = BytesIO()
|
||||||
|
img.save(output, format='JPEG', quality=70, optimize=True)
|
||||||
|
output.seek(0)
|
||||||
|
|
||||||
|
new_name = os.path.splitext(image_field.name)[0] + '.jpg'
|
||||||
|
return File(output, name=new_name)
|
||||||
|
except Exception as e:
|
||||||
|
# Not an image or other error, return as is
|
||||||
|
return image_field
|
||||||
|
|
||||||
class Shipment(models.Model):
|
class Shipment(models.Model):
|
||||||
STATUS_CHOICES = (
|
STATUS_CHOICES = (
|
||||||
('OPEN', _('Open for Bids')),
|
('OPEN', _('Open for Bids')),
|
||||||
@ -421,4 +474,4 @@ class Transaction(models.Model):
|
|||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.receipt_number} - {self.user.username} ({self.amount})"
|
return f"{self.receipt_number} - {self.user.username} ({self.amount})"
|
||||||
@ -125,6 +125,7 @@
|
|||||||
|
|
||||||
<hr class="my-4">
|
<hr class="my-4">
|
||||||
<h5>{% trans "Documents & Photos" %}</h5>
|
<h5>{% trans "Documents & Photos" %}</h5>
|
||||||
|
<p class="text-muted small">{% trans "Photos will be automatically resized for better performance. PDF files are accepted for documents." %}</p>
|
||||||
|
|
||||||
<div class="row {% if CURRENT_LANGUAGE == "ar" %}flex-row-reverse{% endif %}">
|
<div class="row {% if CURRENT_LANGUAGE == "ar" %}flex-row-reverse{% endif %}">
|
||||||
<div class="col-md-12 mb-3">
|
<div class="col-md-12 mb-3">
|
||||||
@ -144,7 +145,15 @@
|
|||||||
<label class="form-label">{% trans "Driver License (Front Face)" %}</label>
|
<label class="form-label">{% trans "Driver License (Front Face)" %}</label>
|
||||||
{% if truck.driver_license_front %}
|
{% if truck.driver_license_front %}
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<img src="{{ truck.driver_license_front.url }}" class="img-thumbnail" style="height: 100px;">
|
{% with ext=truck.driver_license_front.name|lower %}
|
||||||
|
{% if ".pdf" in ext %}
|
||||||
|
<a href="{{ truck.driver_license_front.url }}" target="_blank" class="btn btn-outline-danger btn-sm">
|
||||||
|
<i class="fa fa-file-pdf me-1"></i> {% trans "View PDF" %}
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<img src="{{ truck.driver_license_front.url }}" class="img-thumbnail" style="height: 100px;">
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ form.driver_license_front }}
|
{{ form.driver_license_front }}
|
||||||
@ -154,7 +163,15 @@
|
|||||||
<label class="form-label">{% trans "Driver License (Back Face)" %}</label>
|
<label class="form-label">{% trans "Driver License (Back Face)" %}</label>
|
||||||
{% if truck.driver_license_back %}
|
{% if truck.driver_license_back %}
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<img src="{{ truck.driver_license_back.url }}" class="img-thumbnail" style="height: 100px;">
|
{% with ext=truck.driver_license_back.name|lower %}
|
||||||
|
{% if ".pdf" in ext %}
|
||||||
|
<a href="{{ truck.driver_license_back.url }}" target="_blank" class="btn btn-outline-danger btn-sm">
|
||||||
|
<i class="fa fa-file-pdf me-1"></i> {% trans "View PDF" %}
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<img src="{{ truck.driver_license_back.url }}" class="img-thumbnail" style="height: 100px;">
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ form.driver_license_back }}
|
{{ form.driver_license_back }}
|
||||||
@ -167,7 +184,15 @@
|
|||||||
<label class="form-label">{% trans "Registration (Front Face)" %}</label>
|
<label class="form-label">{% trans "Registration (Front Face)" %}</label>
|
||||||
{% if truck.registration_front %}
|
{% if truck.registration_front %}
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<img src="{{ truck.registration_front.url }}" class="img-thumbnail" style="height: 100px;">
|
{% with ext=truck.registration_front.name|lower %}
|
||||||
|
{% if ".pdf" in ext %}
|
||||||
|
<a href="{{ truck.registration_front.url }}" target="_blank" class="btn btn-outline-danger btn-sm">
|
||||||
|
<i class="fa fa-file-pdf me-1"></i> {% trans "View PDF" %}
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<img src="{{ truck.registration_front.url }}" class="img-thumbnail" style="height: 100px;">
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ form.registration_front }}
|
{{ form.registration_front }}
|
||||||
@ -177,7 +202,15 @@
|
|||||||
<label class="form-label">{% trans "Registration (Back Face)" %}</label>
|
<label class="form-label">{% trans "Registration (Back Face)" %}</label>
|
||||||
{% if truck.registration_back %}
|
{% if truck.registration_back %}
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
<img src="{{ truck.registration_back.url }}" class="img-thumbnail" style="height: 100px;">
|
{% with ext=truck.registration_back.name|lower %}
|
||||||
|
{% if ".pdf" in ext %}
|
||||||
|
<a href="{{ truck.registration_back.url }}" target="_blank" class="btn btn-outline-danger btn-sm">
|
||||||
|
<i class="fa fa-file-pdf me-1"></i> {% trans "View PDF" %}
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<img src="{{ truck.registration_back.url }}" class="img-thumbnail" style="height: 100px;">
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ form.registration_back }}
|
{{ form.registration_back }}
|
||||||
@ -198,4 +231,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user