-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add the product and product images models
- Loading branch information
Showing
14 changed files
with
213 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,9 @@ | ||
# See https://pre-commit.com for more information | ||
# See https://pre-commit.com/hooks.html for more hooks | ||
repos: | ||
- repo: https://github.com/pre-commit/pre-commit-hooks | ||
- repo: https://github.com/pre-commit/pre-commit-hooks | ||
rev: v2.4.0 | ||
hooks: | ||
- id: trailing-whitespace | ||
- id: end-of-file-fixer | ||
- id: check-added-large-files | ||
- repo: https://github.com/pre-commit/mirrors-mypy | ||
rev: v0.782 | ||
hooks: | ||
- id: mypy | ||
- id: trailing-whitespace | ||
- id: end-of-file-fixer | ||
- id: check-added-large-files |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
from django.contrib import admin | ||
|
||
# Register your models here. | ||
from main.models import Product, ProductImage | ||
|
||
admin.site.register(Product) | ||
admin.site.register(ProductImage) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,6 @@ | |
|
||
class MainConfig(AppConfig): | ||
name = 'main' | ||
|
||
def ready(self): | ||
import main.signals |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Generated by Django 3.0.7 on 2020-09-26 15:32 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
initial = True | ||
|
||
dependencies = [ | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='Product', | ||
fields=[ | ||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('name', models.CharField(max_length=60, verbose_name='Name')), | ||
('description', models.CharField(blank=True, max_length=255, null=True, verbose_name='Description')), | ||
('site', models.CharField(max_length=60, verbose_name='Site')), | ||
('active', models.BooleanField(default=True, verbose_name='Active')), | ||
('product_code', models.CharField(blank=True, max_length=60, null=True, verbose_name='Product code')), | ||
('date_updated', models.DateTimeField(auto_now=True)), | ||
('date_created', models.DateTimeField(auto_now_add=True)), | ||
], | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Generated by Django 3.0.7 on 2020-09-26 16:34 | ||
|
||
from django.db import migrations, models | ||
import django.db.models.deletion | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('main', '0001_initial'), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='ProductImage', | ||
fields=[ | ||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('image', models.ImageField(upload_to='product-images')), | ||
('thumbnail', models.ImageField(null=True, upload_to='product-thumbnails')), | ||
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.Product')), | ||
], | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,24 @@ | ||
from django.db import models | ||
|
||
# Create your models here. | ||
|
||
class ProductManager(models.Manager): | ||
def active(self): | ||
return self.filter(active=True) | ||
|
||
|
||
class Product(models.Model): | ||
name = models.CharField('Name', null=False, blank=False, max_length=60) | ||
description = models.CharField('Description', null=True, blank=True, max_length=255) | ||
site = models.CharField('Site', null=False, blank=False, max_length=60) | ||
active = models.BooleanField('Active', null=False, default=True) | ||
product_code = models.CharField('Product code', null=True, blank=True, max_length=60) | ||
date_updated = models.DateTimeField(auto_now=True) | ||
date_created = models.DateTimeField(auto_now_add=True, null=False) | ||
|
||
objects = ProductManager() | ||
|
||
|
||
class ProductImage(models.Model): | ||
product = models.ForeignKey(Product, on_delete=models.CASCADE) | ||
image = models.ImageField(upload_to='product-images') | ||
thumbnail = models.ImageField(upload_to='product-thumbnails', null=True, blank=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import logging | ||
from io import BytesIO | ||
|
||
from PIL import Image | ||
from django.core.files.base import ContentFile | ||
from django.db.models.signals import pre_save | ||
from django.dispatch import receiver | ||
|
||
from main.models import ProductImage | ||
|
||
THUMBNAIL_SIZE = (300, 300) | ||
logger = logging.getLogger(__name__) | ||
|
||
|
||
@receiver(pre_save, sender=ProductImage) | ||
def generate_thumbnail(sender, instance, **kwargs): | ||
logger.info('Generating thumbnail for product %d', instance.product.id) | ||
image = Image.open(instance.image) | ||
image = image.convert('RGB') | ||
image.thumbnail(THUMBNAIL_SIZE, Image.ANTIALIAS) | ||
|
||
temp_thumb = BytesIO() | ||
image.save(temp_thumb, 'JPEG') | ||
temp_thumb.seek(0) | ||
|
||
# set save=False, otherwise it will run in an infinite loop | ||
instance.thumbnail.save( | ||
instance.image.name, | ||
ContentFile(temp_thumb.read()), | ||
save=False, | ||
) | ||
temp_thumb.close() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import factory.fuzzy | ||
|
||
from main import models | ||
|
||
|
||
class ProductFactory(factory.django.DjangoModelFactory): | ||
name = factory.Sequence(lambda x: f'Product {x}') | ||
description = factory.fuzzy.FuzzyText() | ||
site = factory.faker.Faker('url') | ||
product_code = factory.Sequence(lambda x: f'product_{x}') | ||
|
||
class Meta: | ||
model = models.Product |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
from django.test import TestCase | ||
|
||
from main.models import Product | ||
from main.tests.factories import ProductFactory | ||
|
||
|
||
class TestModels(TestCase): | ||
def test_product_manager(self): | ||
ProductFactory.create_batch(2, active=True) | ||
ProductFactory.create(active=False) | ||
self.assertEqual(2, len(Product.objects.active())) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
from decimal import Decimal | ||
|
||
from django.core.files.images import ImageFile | ||
from django.test import TestCase | ||
|
||
from main import models | ||
from main.tests.factories import ProductFactory | ||
|
||
|
||
class TestSignal(TestCase): | ||
def test_thumbnails_are_generated_on_save(self): | ||
product = ProductFactory() | ||
|
||
with open('main/fixtures/cat.jpeg', 'rb') as f: | ||
image = models.ProductImage(product=product, image=ImageFile(f, name='cat.jpeg')) | ||
image.save() | ||
image.refresh_from_db() | ||
with open('media/product-thumbnails/cat.jpeg', 'rb') as f: | ||
expected_content = f.read() | ||
assert image.thumbnail.read() == expected_content | ||
image.thumbnail.delete(save=False) | ||
image.image.delete(save=False) |