Add variant photo assoc
This commit is contained in:
parent
4b8831035e
commit
0e52e1bdfe
@ -10,6 +10,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 1,
|
"sorting": 1,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -25,6 +26,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 3,
|
"sorting": 3,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -40,6 +42,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 1,
|
"sorting": 1,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -55,6 +58,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 3,
|
"sorting": 3,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -70,6 +74,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 1,
|
"sorting": 1,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -85,6 +90,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 3,
|
"sorting": 3,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -100,6 +106,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 1,
|
"sorting": 1,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -115,6 +122,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 3,
|
"sorting": 3,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -130,6 +138,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 1,
|
"sorting": 1,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -145,6 +154,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 3,
|
"sorting": 3,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -160,6 +170,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 1,
|
"sorting": 1,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -175,6 +186,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 3,
|
"sorting": 3,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -190,6 +202,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 1,
|
"sorting": 1,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -205,6 +218,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 3,
|
"sorting": 3,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -220,6 +234,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 1,
|
"sorting": 1,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -235,6 +250,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 3,
|
"sorting": 3,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -250,6 +266,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 1,
|
"sorting": 1,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
@ -265,6 +282,7 @@
|
|||||||
"track_inventory": false,
|
"track_inventory": false,
|
||||||
"stock": null,
|
"stock": null,
|
||||||
"sorting": 3,
|
"sorting": 3,
|
||||||
|
"image": null,
|
||||||
"created_at": "2022-02-23T18:06:57.624Z",
|
"created_at": "2022-02-23T18:06:57.624Z",
|
||||||
"updated_at": "2022-02-23T18:06:57.624Z"
|
"updated_at": "2022-02-23T18:06:57.624Z"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -121,6 +121,29 @@ class Product(models.Model):
|
|||||||
ordering = ['sorting', 'name']
|
ordering = ['sorting', 'name']
|
||||||
|
|
||||||
|
|
||||||
|
class ProductPhoto(models.Model):
|
||||||
|
product = models.ForeignKey(Product, on_delete=models.CASCADE)
|
||||||
|
image = models.ImageField(upload_to='products/images')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.product.name} {self.image}'
|
||||||
|
|
||||||
|
def delete(self, *args, **kwargs):
|
||||||
|
storage, path = self.image.storage, self.image.path
|
||||||
|
|
||||||
|
super(ProductPhoto, self).delete(*args, **kwargs)
|
||||||
|
storage.delete(path)
|
||||||
|
|
||||||
|
# def save(self, *args, **kwargs):
|
||||||
|
# super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
# img = Image.open(self.image.path)
|
||||||
|
# if img.height > 400 or img.width > 400:
|
||||||
|
# output_size = (400, 400)
|
||||||
|
# img.thumbnail(output_size)
|
||||||
|
# img.save(self.image.path)
|
||||||
|
|
||||||
|
|
||||||
class ProductVariantManager(models.Manager):
|
class ProductVariantManager(models.Manager):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return super().get_queryset().annotate(
|
return super().get_queryset().annotate(
|
||||||
@ -135,7 +158,7 @@ class ProductVariant(models.Model):
|
|||||||
related_name='variants'
|
related_name='variants'
|
||||||
)
|
)
|
||||||
image = models.ForeignKey(
|
image = models.ForeignKey(
|
||||||
'ProductPhoto',
|
ProductPhoto,
|
||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
related_name='+',
|
related_name='+',
|
||||||
null=True
|
null=True
|
||||||
@ -195,29 +218,6 @@ class ProductOption(models.Model):
|
|||||||
return f'{self.name}'
|
return f'{self.name}'
|
||||||
|
|
||||||
|
|
||||||
class ProductPhoto(models.Model):
|
|
||||||
product = models.ForeignKey(Product, on_delete=models.CASCADE)
|
|
||||||
image = models.ImageField(upload_to='products/images')
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.product.name
|
|
||||||
|
|
||||||
def delete(self, *args, **kwargs):
|
|
||||||
storage, path = self.image.storage, self.image.path
|
|
||||||
|
|
||||||
super(ProductPhoto, self).delete(*args, **kwargs)
|
|
||||||
storage.delete(path)
|
|
||||||
|
|
||||||
# def save(self, *args, **kwargs):
|
|
||||||
# super().save(*args, **kwargs)
|
|
||||||
|
|
||||||
# img = Image.open(self.image.path)
|
|
||||||
# if img.height > 400 or img.width > 400:
|
|
||||||
# output_size = (400, 400)
|
|
||||||
# img.thumbnail(output_size)
|
|
||||||
# img.save(self.image.path)
|
|
||||||
|
|
||||||
|
|
||||||
class Coupon(models.Model):
|
class Coupon(models.Model):
|
||||||
type = models.CharField(
|
type = models.CharField(
|
||||||
max_length=20,
|
max_length=20,
|
||||||
|
|||||||
@ -3,6 +3,7 @@ from django import forms
|
|||||||
|
|
||||||
from core import OrderStatus
|
from core import OrderStatus
|
||||||
from core.models import (
|
from core.models import (
|
||||||
|
ProductVariant,
|
||||||
Order,
|
Order,
|
||||||
OrderLine,
|
OrderLine,
|
||||||
ShippingRate,
|
ShippingRate,
|
||||||
@ -14,6 +15,27 @@ from core.models import (
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ProductVariantUpdateForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = ProductVariant
|
||||||
|
fields = [
|
||||||
|
'name',
|
||||||
|
'sku',
|
||||||
|
'price',
|
||||||
|
'weight',
|
||||||
|
'track_inventory',
|
||||||
|
'stock',
|
||||||
|
'image'
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
if self.instance:
|
||||||
|
self.fields['image'].queryset = ProductPhoto.objects.filter(
|
||||||
|
product=self.instance.product
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CouponForm(forms.ModelForm):
|
class CouponForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Coupon
|
model = Coupon
|
||||||
|
|||||||
@ -25,7 +25,11 @@
|
|||||||
<div class="object__item object__item--col5">
|
<div class="object__item object__item--col5">
|
||||||
{% with product=item.variant.product %}
|
{% with product=item.variant.product %}
|
||||||
<figure class="item__figure">
|
<figure class="item__figure">
|
||||||
<img class="product__image product__image--small" src="{{product.get_first_img.image.url}}" alt="{{product.get_first_img.image}}">
|
{% if item.variant.image %}
|
||||||
|
<img class="item__image" src="{{item.variant.image.image.url}}" alt="{{item.variant.image.image}}">
|
||||||
|
{% else %}
|
||||||
|
<img class="item__image" src="{{product.get_first_img.image.url}}" alt="{{product.get_first_img.image}}">
|
||||||
|
{% endif %}
|
||||||
<figcaption><strong>{{item.variant}}</strong><br>{{item.customer_note}}</figcaption>
|
<figcaption><strong>{{item.variant}}</strong><br>{{item.customer_note}}</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
<span>{{product.sku}}</span>
|
<span>{{product.sku}}</span>
|
||||||
|
|||||||
@ -19,7 +19,11 @@
|
|||||||
<div class="object__item object__item--col5">
|
<div class="object__item object__item--col5">
|
||||||
{% with product=variant.product %}
|
{% with product=variant.product %}
|
||||||
<figure class="item__figure">
|
<figure class="item__figure">
|
||||||
|
{% if variant.image %}
|
||||||
|
<img class="item__image" src="{{variant.image.image.url}}" alt="{{variant.image.image}}">
|
||||||
|
{% else %}
|
||||||
<img class="product__image product__image--small" src="{{product.get_first_img.image.url}}" alt="{{product.get_first_img.image}}">
|
<img class="product__image product__image--small" src="{{product.get_first_img.image.url}}" alt="{{product.get_first_img.image}}">
|
||||||
|
{% endif %}
|
||||||
<figcaption><strong>{{variant}}</strong></figcaption>
|
<figcaption><strong>{{variant}}</strong></figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
<span>{{ variant.sku }}</span>
|
<span>{{ variant.sku }}</span>
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import logging
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django import forms
|
||||||
from django.shortcuts import render, reverse, redirect, get_object_or_404
|
from django.shortcuts import render, reverse, redirect, get_object_or_404
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.urls import reverse, reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user