feat: Модуль "Справочник товаров"

Создать структуру базы данных для товаров:

        Поля: наименование, штрих-код, срок годности, размеры, единицы измерения, производитель, категория товара, температурные условия хранения, акции (тип "1+1", "2+1").

 Реализовать функционал:
        Добавление, редактирование и удаление карточек товаров.
        Проверка на дублирование данных (штрих-код).
        Валидация данных (например, срок годности).
main
Artem-Darius Weber 1 day ago
parent 04581f5ebb
commit 87dae7b461

@ -1,19 +1,23 @@
from django.db import models from django.db import models
from django.contrib.auth.models import AbstractUser, Permission, Group from django.contrib.auth.models import AbstractUser, Permission, Group
# Справочник товаров from product_directory.models import Product
class Product(models.Model):
name = models.CharField(max_length=255, verbose_name="Наименование товара")
manufacturer_name = models.CharField(max_length=255, verbose_name="Производитель")
manufacturer_country = models.CharField(max_length=255, verbose_name="Страна производителя")
manufacturer_code = models.CharField(max_length=50, verbose_name="Код производителя", blank=True, null=True)
dimensions = models.CharField(max_length=255, verbose_name="Размеры", blank=True, null=True)
unit_of_measure = models.CharField(max_length=50, verbose_name="Единица измерения")
shelf_life_days = models.IntegerField(verbose_name="Срок годности (дни)")
barcode = models.CharField(max_length=50, unique=True, verbose_name="Штрихкод")
def __str__(self): # todo: нужно перенести уникальные поля в новую модель
return self.name
# Справочник товаров
# class Product(models.Model):
# name = models.CharField(max_length=255, verbose_name="Наименование товара")
# manufacturer_name = models.CharField(max_length=255, verbose_name="Производитель")
# manufacturer_country = models.CharField(max_length=255, verbose_name="Страна производителя")
# manufacturer_code = models.CharField(max_length=50, verbose_name="Код производителя", blank=True, null=True)
# dimensions = models.CharField(max_length=255, verbose_name="Размеры", blank=True, null=True)
# unit_of_measure = models.CharField(max_length=50, verbose_name="Единица измерения")
# shelf_life_days = models.IntegerField(verbose_name="Срок годности (дни)")
# barcode = models.CharField(max_length=50, unique=True, verbose_name="Штрихкод")
#
# def __str__(self):
# return self.name
# Справочник должностей # Справочник должностей
class Position(models.Model): class Position(models.Model):

@ -0,0 +1,2 @@
Watching for file changes with StatReloader
Watching for file changes with StatReloader

@ -0,0 +1,4 @@
Watching for file changes with StatReloader
/Users/darius/Documents/franchise_store/settings/base.py changed, reloading.
Watching for file changes with StatReloader
/Users/darius/Documents/franchise_store/settings/base.py changed, reloading.

@ -0,0 +1,8 @@
from django.contrib import admin
from .models import Product
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ('name', 'barcode', 'category', 'shelf_life_days', 'promotion')
search_fields = ('name', 'barcode')

@ -0,0 +1,7 @@
from rest_framework.viewsets import ModelViewSet
from .models import Product
from .serializers import ProductSerializer
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer

@ -0,0 +1,6 @@
from django.apps import AppConfig
class ProductDirectoryConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'product_directory'

@ -0,0 +1,15 @@
from django import forms
from .models import Product
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = '__all__'
def clean_shelf_life_days(self):
shelf_life_days = self.cleaned_data.get('shelf_life_days')
if shelf_life_days <= 0:
raise forms.ValidationError("Срок годности должен быть положительным числом.")
if shelf_life_days > 3650: # 10 лет
raise forms.ValidationError("Срок годности превышает допустимый предел.")
return shelf_life_days

@ -0,0 +1,29 @@
# Generated by Django 5.1.4 on 2025-01-08 14:18
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Product',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255, verbose_name='Наименование товара')),
('barcode', models.CharField(max_length=50, unique=True, verbose_name='Штрих-код')),
('shelf_life_days', models.PositiveIntegerField(verbose_name='Срок годности (дни)')),
('dimensions', models.CharField(max_length=255, verbose_name='Размеры')),
('unit_of_measure', models.CharField(max_length=50, verbose_name='Единицы измерения')),
('manufacturer', models.CharField(max_length=255, verbose_name='Производитель')),
('category', models.CharField(choices=[('Food', 'Продукты'), ('Electronics', 'Электроника'), ('Clothing', 'Одежда'), ('Other', 'Другое')], max_length=50, verbose_name='Категория')),
('storage_temperature', models.CharField(max_length=50, verbose_name='Температурные условия хранения')),
('promotion', models.CharField(blank=True, choices=[('1+1', '1+1'), ('2+1', '2+1')], max_length=10, null=True, verbose_name='Акция')),
],
),
]

@ -0,0 +1,26 @@
from django.db import models
class Product(models.Model):
CATEGORY_CHOICES = [
('Food', 'Продукты'),
('Electronics', 'Электроника'),
('Clothing', 'Одежда'),
('Other', 'Другое'),
]
PROMOTION_CHOICES = [
('1+1', '1+1'),
('2+1', '2+1'),
]
name = models.CharField(max_length=255, verbose_name="Наименование товара")
barcode = models.CharField(max_length=50, unique=True, verbose_name="Штрих-код")
shelf_life_days = models.PositiveIntegerField(verbose_name="Срок годности (дни)")
dimensions = models.CharField(max_length=255, verbose_name="Размеры")
unit_of_measure = models.CharField(max_length=50, verbose_name="Единицы измерения")
manufacturer = models.CharField(max_length=255, verbose_name="Производитель")
category = models.CharField(max_length=50, choices=CATEGORY_CHOICES, verbose_name="Категория")
storage_temperature = models.CharField(max_length=50, verbose_name="Температурные условия хранения")
promotion = models.CharField(max_length=10, choices=PROMOTION_CHOICES, verbose_name="Акция", blank=True, null=True)
def __str__(self):
return self.name

@ -0,0 +1,7 @@
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'

@ -0,0 +1,13 @@
{% for product in products %}
<tr>
<td>{{ product.name }}</td>
<td>{{ product.barcode }}</td>
<td>{{ product.category }}</td>
<td>{{ product.shelf_life_days }}</td>
<td>{{ product.promotion }}</td>
<td>
<a href="{% url 'product_update' product.id %}">Изменить</a>
<a href="{% url 'product_delete' product.id %}">Удалить</a>
</td>
</tr>
{% endfor %}

@ -0,0 +1,18 @@
from django.test import TestCase
from .models import Product
class ProductTestCase(TestCase):
def test_product_creation(self):
product = Product.objects.create(
name="Тестовый товар",
barcode="1234567890123",
shelf_life_days=365,
dimensions="10x10x10",
unit_of_measure="шт.",
manufacturer="Производитель",
category="Food",
storage_temperature="+4C",
promotion="1+1"
)
self.assertEqual(Product.objects.count(), 1)
self.assertEqual(product.name, "Тестовый товар")

@ -0,0 +1,42 @@
import logging # Импортируем библиотеку для логирования
from django.shortcuts import render, get_object_or_404, redirect
from .models import Product
from .forms import ProductForm
# Настраиваем логгер
logger = logging.getLogger(__name__)
def product_list(request):
products = Product.objects.all()
return render(request, 'product_directory/product_list.html', {'products': products})
def product_create(request):
if request.method == 'POST':
form = ProductForm(request.POST)
if form.is_valid():
product = form.save()
logger.info(f"Пользователь {request.user} создал товар '{product.name}'")
return redirect('product_list')
else:
form = ProductForm()
return render(request, 'product_directory/product_form.html', {'form': form})
def product_update(request, pk):
product = get_object_or_404(Product, pk=pk)
if request.method == 'POST':
form = ProductForm(request.POST, instance=product)
if form.is_valid():
product = form.save()
logger.info(f"Пользователь {request.user} обновил товар '{product.name}'")
return redirect('product_list')
else:
form = ProductForm(instance=product)
return render(request, 'product_directory/product_form.html', {'form': form})
def product_delete(request, pk):
product = get_object_or_404(Product, pk=pk)
if request.method == 'POST':
logger.warning(f"Пользователь {request.user} удалил товар '{product.name}'")
product.delete()
return redirect('product_list')
return render(request, 'product_directory/product_confirm_delete.html', {'product': product})

@ -56,6 +56,31 @@ INSTALLED_APPS = [
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'rest_framework', 'rest_framework',
'inventory', 'inventory',
'product_directory',
] ]
ROOT_URLCONF = 'urls' ROOT_URLCONF = 'urls'
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'file': {
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': 'logs.log', # путь к файлу для логов
},
},
'loggers': {
'django': {
'handlers': ['file'],
'level': 'INFO',
'propagate': True,
},
'product_directory': {
'handlers': ['file'],
'level': 'INFO',
'propagate': True,
},
},
}

Loading…
Cancel
Save