Merge pull request 'Attributes model added.' (#1) from feat/attributes-model into main
Reviewed-on: #1
This commit is contained in:
1
=4.12
Normal file
1
=4.12
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Requirement already satisfied: typing_extensions in ./.venv/lib/python3.12/site-packages (4.12.2)
|
||||||
@@ -179,6 +179,9 @@ REST_FRAMEWORK = {
|
|||||||
"user": "60/min",
|
"user": "60/min",
|
||||||
},
|
},
|
||||||
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
||||||
|
"DEFAULT_AUTHENTICATION_CLASSES": [
|
||||||
|
"rest_framework.authentication.TokenAuthentication",
|
||||||
|
]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,9 +40,8 @@ def sms_code(test_user):
|
|||||||
def test_reg_view(api_client):
|
def test_reg_view(api_client):
|
||||||
data = {
|
data = {
|
||||||
"phone": "998999999991",
|
"phone": "998999999991",
|
||||||
"first_name": "John",
|
|
||||||
"last_name": "Doe",
|
|
||||||
"password": "password",
|
"password": "password",
|
||||||
|
"confirm_password":"password"
|
||||||
}
|
}
|
||||||
with patch.object(SmsService, "send_confirm", return_value=True):
|
with patch.object(SmsService, "send_confirm", return_value=True):
|
||||||
response = api_client.post(reverse("auth-register"), data=data)
|
response = api_client.post(reverse("auth-register"), data=data)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import uuid
|
import uuid
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
|
from rest_framework.authentication import TokenAuthentication
|
||||||
|
|
||||||
from core.services import UserService, SmsService
|
from core.services import UserService, SmsService
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@@ -186,6 +188,7 @@ class MeView(BaseViewSetMixin, GenericViewSet, UserService):
|
|||||||
class ChangePasswordView(BaseViewSetMixin, GenericViewSet):
|
class ChangePasswordView(BaseViewSetMixin, GenericViewSet):
|
||||||
serializer_class = ChangePasswordSerializer
|
serializer_class = ChangePasswordSerializer
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (IsAuthenticated,)
|
||||||
|
authentication_classes = [TokenAuthentication]
|
||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
request=serializer_class,
|
request=serializer_class,
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
from .attributes import * # noqa
|
||||||
|
|||||||
28
core/apps/api/admin/attributes.py
Normal file
28
core/apps/api/admin/attributes.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from unfold.admin import ModelAdmin
|
||||||
|
|
||||||
|
from core.apps.api.models import ColorModel, ProductlikeModel, SizeModel
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(SizeModel)
|
||||||
|
class SizeAdmin(ModelAdmin):
|
||||||
|
list_display = (
|
||||||
|
"id",
|
||||||
|
"__str__",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(ColorModel)
|
||||||
|
class ColorAdmin(ModelAdmin):
|
||||||
|
list_display = (
|
||||||
|
"id",
|
||||||
|
"__str__",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(ProductlikeModel)
|
||||||
|
class ProductlikeAdmin(ModelAdmin):
|
||||||
|
list_display = (
|
||||||
|
"id",
|
||||||
|
"__str__",
|
||||||
|
)
|
||||||
1
core/apps/api/filters/__init__.py
Normal file
1
core/apps/api/filters/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .attributes import * # noqa
|
||||||
33
core/apps/api/filters/attributes.py
Normal file
33
core/apps/api/filters/attributes.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
from django_filters import rest_framework as filters
|
||||||
|
|
||||||
|
from core.apps.api.models import ColorModel, ProductlikeModel, SizeModel
|
||||||
|
|
||||||
|
|
||||||
|
class SizeFilter(filters.FilterSet):
|
||||||
|
# name = filters.CharFilter(field_name="name", lookup_expr="icontains")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = SizeModel
|
||||||
|
fields = [
|
||||||
|
"name",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class ColorFilter(filters.FilterSet):
|
||||||
|
# name = filters.CharFilter(field_name="name", lookup_expr="icontains")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = ColorModel
|
||||||
|
fields = [
|
||||||
|
"name",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class ProductlikeFilter(filters.FilterSet):
|
||||||
|
# name = filters.CharFilter(field_name="name", lookup_expr="icontains")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = ProductlikeModel
|
||||||
|
fields = [
|
||||||
|
"name",
|
||||||
|
]
|
||||||
1
core/apps/api/forms/__init__.py
Normal file
1
core/apps/api/forms/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .attributes import * # noqa
|
||||||
24
core/apps/api/forms/attributes.py
Normal file
24
core/apps/api/forms/attributes.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
from django import forms
|
||||||
|
|
||||||
|
from core.apps.api.models import ColorModel, ProductlikeModel, SizeModel
|
||||||
|
|
||||||
|
|
||||||
|
class SizeForm(forms.ModelForm):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = SizeModel
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class ColorForm(forms.ModelForm):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = ColorModel
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
|
class ProductlikeForm(forms.ModelForm):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = ProductlikeModel
|
||||||
|
fields = "__all__"
|
||||||
57
core/apps/api/migrations/0001_initial.py
Normal file
57
core/apps/api/migrations/0001_initial.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2026-03-09 07:48
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ColorModel',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
|
('name', models.CharField(max_length=255, verbose_name='name')),
|
||||||
|
('code', models.CharField(max_length=255, verbose_name='name')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'ColorModel',
|
||||||
|
'verbose_name_plural': 'ColorModels',
|
||||||
|
'db_table': 'color',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ProductlikeModel',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
|
('name', models.CharField(max_length=255, verbose_name='name')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'ProductlikeModel',
|
||||||
|
'verbose_name_plural': 'ProductlikeModels',
|
||||||
|
'db_table': 'productlike',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='SizeModel',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('updated_at', models.DateTimeField(auto_now=True)),
|
||||||
|
('name', models.CharField(max_length=255, verbose_name='name')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'SizeModel',
|
||||||
|
'verbose_name_plural': 'SizeModels',
|
||||||
|
'db_table': 'size',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .attributes import * # noqa
|
||||||
|
|||||||
55
core/apps/api/models/attributes.py
Normal file
55
core/apps/api/models/attributes.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django_core.models import AbstractBaseModel
|
||||||
|
from model_bakery import baker
|
||||||
|
|
||||||
|
|
||||||
|
class SizeModel(AbstractBaseModel):
|
||||||
|
|
||||||
|
name = models.CharField(verbose_name=_("name"), max_length=255)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.pk)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _baker(cls):
|
||||||
|
return baker.make(cls)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "size"
|
||||||
|
verbose_name = _("SizeModel")
|
||||||
|
verbose_name_plural = _("SizeModels")
|
||||||
|
|
||||||
|
|
||||||
|
class ColorModel(AbstractBaseModel):
|
||||||
|
|
||||||
|
name = models.CharField(verbose_name=_("name"), max_length=255)
|
||||||
|
code = models.CharField(verbose_name=_("name"), max_length=255)
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.pk)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _baker(cls):
|
||||||
|
return baker.make(cls)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "color"
|
||||||
|
verbose_name = _("ColorModel")
|
||||||
|
verbose_name_plural = _("ColorModels")
|
||||||
|
|
||||||
|
|
||||||
|
class ProductlikeModel(AbstractBaseModel):
|
||||||
|
|
||||||
|
name = models.CharField(verbose_name=_("name"), max_length=255)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.pk)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _baker(cls):
|
||||||
|
return baker.make(cls)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "productlike"
|
||||||
|
verbose_name = _("ProductlikeModel")
|
||||||
|
verbose_name_plural = _("ProductlikeModels")
|
||||||
1
core/apps/api/permissions/__init__.py
Normal file
1
core/apps/api/permissions/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .attributes import * # noqa
|
||||||
34
core/apps/api/permissions/attributes.py
Normal file
34
core/apps/api/permissions/attributes.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
from rest_framework import permissions
|
||||||
|
|
||||||
|
|
||||||
|
class SizePermission(permissions.BasePermission):
|
||||||
|
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def has_permission(self, request, view):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class ColorPermission(permissions.BasePermission):
|
||||||
|
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def has_permission(self, request, view):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class ProductlikePermission(permissions.BasePermission):
|
||||||
|
|
||||||
|
def __init__(self) -> None: ...
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def has_permission(self, request, view):
|
||||||
|
return True
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .attributes import * # noqa
|
||||||
|
|||||||
3
core/apps/api/serializers/attributes/__init__.py
Normal file
3
core/apps/api/serializers/attributes/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from .color import * # noqa
|
||||||
|
from .productlike import * # noqa
|
||||||
|
from .size import * # noqa
|
||||||
28
core/apps/api/serializers/attributes/color.py
Normal file
28
core/apps/api/serializers/attributes/color.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from core.apps.api.models import ColorModel
|
||||||
|
|
||||||
|
|
||||||
|
class BaseColorSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = ColorModel
|
||||||
|
fields = [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class ListColorSerializer(BaseColorSerializer):
|
||||||
|
class Meta(BaseColorSerializer.Meta): ...
|
||||||
|
|
||||||
|
|
||||||
|
class RetrieveColorSerializer(BaseColorSerializer):
|
||||||
|
class Meta(BaseColorSerializer.Meta): ...
|
||||||
|
|
||||||
|
|
||||||
|
class CreateColorSerializer(BaseColorSerializer):
|
||||||
|
class Meta(BaseColorSerializer.Meta):
|
||||||
|
fields = [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
]
|
||||||
28
core/apps/api/serializers/attributes/productlike.py
Normal file
28
core/apps/api/serializers/attributes/productlike.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from core.apps.api.models import ProductlikeModel
|
||||||
|
|
||||||
|
|
||||||
|
class BaseProductlikeSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = ProductlikeModel
|
||||||
|
fields = [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class ListProductlikeSerializer(BaseProductlikeSerializer):
|
||||||
|
class Meta(BaseProductlikeSerializer.Meta): ...
|
||||||
|
|
||||||
|
|
||||||
|
class RetrieveProductlikeSerializer(BaseProductlikeSerializer):
|
||||||
|
class Meta(BaseProductlikeSerializer.Meta): ...
|
||||||
|
|
||||||
|
|
||||||
|
class CreateProductlikeSerializer(BaseProductlikeSerializer):
|
||||||
|
class Meta(BaseProductlikeSerializer.Meta):
|
||||||
|
fields = [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
]
|
||||||
28
core/apps/api/serializers/attributes/size.py
Normal file
28
core/apps/api/serializers/attributes/size.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from core.apps.api.models import SizeModel
|
||||||
|
|
||||||
|
|
||||||
|
class BaseSizeSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = SizeModel
|
||||||
|
fields = [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class ListSizeSerializer(BaseSizeSerializer):
|
||||||
|
class Meta(BaseSizeSerializer.Meta): ...
|
||||||
|
|
||||||
|
|
||||||
|
class RetrieveSizeSerializer(BaseSizeSerializer):
|
||||||
|
class Meta(BaseSizeSerializer.Meta): ...
|
||||||
|
|
||||||
|
|
||||||
|
class CreateSizeSerializer(BaseSizeSerializer):
|
||||||
|
class Meta(BaseSizeSerializer.Meta):
|
||||||
|
fields = [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
]
|
||||||
1
core/apps/api/signals/__init__.py
Normal file
1
core/apps/api/signals/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .attributes import * # noqa
|
||||||
16
core/apps/api/signals/attributes.py
Normal file
16
core/apps/api/signals/attributes.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from django.db.models.signals import post_save
|
||||||
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
from core.apps.api.models import ColorModel, ProductlikeModel, SizeModel
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=SizeModel)
|
||||||
|
def SizeSignal(sender, instance, created, **kwargs): ...
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=ColorModel)
|
||||||
|
def ColorSignal(sender, instance, created, **kwargs): ...
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=ProductlikeModel)
|
||||||
|
def ProductlikeSignal(sender, instance, created, **kwargs): ...
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .attributes import * # noqa
|
||||||
|
|||||||
3
core/apps/api/tests/attributes/__init__.py
Normal file
3
core/apps/api/tests/attributes/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from .test_color import * # noqa
|
||||||
|
from .test_productlike import * # noqa
|
||||||
|
from .test_size import * # noqa
|
||||||
101
core/apps/api/tests/attributes/test_color.py
Normal file
101
core/apps/api/tests/attributes/test_color.py
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import pytest
|
||||||
|
from django.urls import reverse
|
||||||
|
from rest_framework.test import APIClient
|
||||||
|
|
||||||
|
from core.apps.api.models import ColorModel
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def instance(db):
|
||||||
|
return ColorModel._baker()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def api_client(instance):
|
||||||
|
client = APIClient()
|
||||||
|
##client.force_authenticate(user=instance.user)
|
||||||
|
return client, instance
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def data(api_client):
|
||||||
|
client, instance = api_client
|
||||||
|
return (
|
||||||
|
{
|
||||||
|
"list": reverse("color-list"),
|
||||||
|
"retrieve": reverse("color-detail", kwargs={"pk": instance.pk}),
|
||||||
|
"retrieve-not-found": reverse("color-detail", kwargs={"pk": 1000}),
|
||||||
|
},
|
||||||
|
client,
|
||||||
|
instance,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_list(data):
|
||||||
|
urls, client, _ = data
|
||||||
|
response = client.get(urls["list"])
|
||||||
|
data_resp = response.json()
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert data_resp["status"] is True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_retrieve(data):
|
||||||
|
urls, client, _ = data
|
||||||
|
response = client.get(urls["retrieve"])
|
||||||
|
data_resp = response.json()
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert data_resp["status"] is True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_retrieve_not_found(data):
|
||||||
|
urls, client, _ = data
|
||||||
|
response = client.get(urls["retrieve-not-found"])
|
||||||
|
data_resp = response.json()
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert data_resp["status"] is False
|
||||||
|
|
||||||
|
|
||||||
|
# @pytest.mark.django_db
|
||||||
|
# def test_create(data):
|
||||||
|
# urls, client, _ = data
|
||||||
|
# response = client.post(urls["list"], data={"name": "test"})
|
||||||
|
# assert response.json()["status"] is True
|
||||||
|
# assert response.status_code == 201
|
||||||
|
|
||||||
|
|
||||||
|
# @pytest.mark.django_db
|
||||||
|
# def test_update(data):
|
||||||
|
# urls, client, _ = data
|
||||||
|
# response = client.patch(urls["retrieve"], data={"name": "updated"})
|
||||||
|
# assert response.json()["status"] is True
|
||||||
|
# assert response.status_code == 200
|
||||||
|
#
|
||||||
|
# # verify updated value
|
||||||
|
# response = client.get(urls["retrieve"])
|
||||||
|
# assert response.json()["status"] is True
|
||||||
|
# assert response.status_code == 200
|
||||||
|
# assert response.json()["data"]["name"] == "updated"
|
||||||
|
|
||||||
|
|
||||||
|
# @pytest.mark.django_db
|
||||||
|
# def test_partial_update():
|
||||||
|
# urls, client, _ = data
|
||||||
|
# response = client.patch(urls["retrieve"], data={"name": "updated"})
|
||||||
|
# assert response.json()["status"] is True
|
||||||
|
# assert response.status_code == 200
|
||||||
|
#
|
||||||
|
# # verify updated value
|
||||||
|
# response = client.get(urls["retrieve"])
|
||||||
|
# assert response.json()["status"] is True
|
||||||
|
# assert response.status_code == 200
|
||||||
|
# assert response.json()["data"]["name"] == "updated"
|
||||||
|
|
||||||
|
|
||||||
|
# @pytest.mark.django_db
|
||||||
|
# def test_destroy(data):
|
||||||
|
# urls, client, _ = data
|
||||||
|
# response = client.delete(urls["retrieve"])
|
||||||
|
# assert response.status_code == 204
|
||||||
101
core/apps/api/tests/attributes/test_productlike.py
Normal file
101
core/apps/api/tests/attributes/test_productlike.py
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import pytest
|
||||||
|
from django.urls import reverse
|
||||||
|
from rest_framework.test import APIClient
|
||||||
|
|
||||||
|
from core.apps.api.models import ProductlikeModel
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def instance(db):
|
||||||
|
return ProductlikeModel._baker()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def api_client(instance):
|
||||||
|
client = APIClient()
|
||||||
|
##client.force_authenticate(user=instance.user)
|
||||||
|
return client, instance
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def data(api_client):
|
||||||
|
client, instance = api_client
|
||||||
|
return (
|
||||||
|
{
|
||||||
|
"list": reverse("productlike-list"),
|
||||||
|
"retrieve": reverse("productlike-detail", kwargs={"pk": instance.pk}),
|
||||||
|
"retrieve-not-found": reverse("productlike-detail", kwargs={"pk": 1000}),
|
||||||
|
},
|
||||||
|
client,
|
||||||
|
instance,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_list(data):
|
||||||
|
urls, client, _ = data
|
||||||
|
response = client.get(urls["list"])
|
||||||
|
data_resp = response.json()
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert data_resp["status"] is True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_retrieve(data):
|
||||||
|
urls, client, _ = data
|
||||||
|
response = client.get(urls["retrieve"])
|
||||||
|
data_resp = response.json()
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert data_resp["status"] is True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_retrieve_not_found(data):
|
||||||
|
urls, client, _ = data
|
||||||
|
response = client.get(urls["retrieve-not-found"])
|
||||||
|
data_resp = response.json()
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert data_resp["status"] is False
|
||||||
|
|
||||||
|
|
||||||
|
# @pytest.mark.django_db
|
||||||
|
# def test_create(data):
|
||||||
|
# urls, client, _ = data
|
||||||
|
# response = client.post(urls["list"], data={"name": "test"})
|
||||||
|
# assert response.json()["status"] is True
|
||||||
|
# assert response.status_code == 201
|
||||||
|
|
||||||
|
|
||||||
|
# @pytest.mark.django_db
|
||||||
|
# def test_update(data):
|
||||||
|
# urls, client, _ = data
|
||||||
|
# response = client.patch(urls["retrieve"], data={"name": "updated"})
|
||||||
|
# assert response.json()["status"] is True
|
||||||
|
# assert response.status_code == 200
|
||||||
|
#
|
||||||
|
# # verify updated value
|
||||||
|
# response = client.get(urls["retrieve"])
|
||||||
|
# assert response.json()["status"] is True
|
||||||
|
# assert response.status_code == 200
|
||||||
|
# assert response.json()["data"]["name"] == "updated"
|
||||||
|
|
||||||
|
|
||||||
|
# @pytest.mark.django_db
|
||||||
|
# def test_partial_update():
|
||||||
|
# urls, client, _ = data
|
||||||
|
# response = client.patch(urls["retrieve"], data={"name": "updated"})
|
||||||
|
# assert response.json()["status"] is True
|
||||||
|
# assert response.status_code == 200
|
||||||
|
#
|
||||||
|
# # verify updated value
|
||||||
|
# response = client.get(urls["retrieve"])
|
||||||
|
# assert response.json()["status"] is True
|
||||||
|
# assert response.status_code == 200
|
||||||
|
# assert response.json()["data"]["name"] == "updated"
|
||||||
|
|
||||||
|
|
||||||
|
# @pytest.mark.django_db
|
||||||
|
# def test_destroy(data):
|
||||||
|
# urls, client, _ = data
|
||||||
|
# response = client.delete(urls["retrieve"])
|
||||||
|
# assert response.status_code == 204
|
||||||
101
core/apps/api/tests/attributes/test_size.py
Normal file
101
core/apps/api/tests/attributes/test_size.py
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import pytest
|
||||||
|
from django.urls import reverse
|
||||||
|
from rest_framework.test import APIClient
|
||||||
|
|
||||||
|
from core.apps.api.models import SizeModel
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def instance(db):
|
||||||
|
return SizeModel._baker()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def api_client(instance):
|
||||||
|
client = APIClient()
|
||||||
|
##client.force_authenticate(user=instance.user)
|
||||||
|
return client, instance
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def data(api_client):
|
||||||
|
client, instance = api_client
|
||||||
|
return (
|
||||||
|
{
|
||||||
|
"list": reverse("size-list"),
|
||||||
|
"retrieve": reverse("size-detail", kwargs={"pk": instance.pk}),
|
||||||
|
"retrieve-not-found": reverse("size-detail", kwargs={"pk": 1000}),
|
||||||
|
},
|
||||||
|
client,
|
||||||
|
instance,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_list(data):
|
||||||
|
urls, client, _ = data
|
||||||
|
response = client.get(urls["list"])
|
||||||
|
data_resp = response.json()
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert data_resp["status"] is True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_retrieve(data):
|
||||||
|
urls, client, _ = data
|
||||||
|
response = client.get(urls["retrieve"])
|
||||||
|
data_resp = response.json()
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert data_resp["status"] is True
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_retrieve_not_found(data):
|
||||||
|
urls, client, _ = data
|
||||||
|
response = client.get(urls["retrieve-not-found"])
|
||||||
|
data_resp = response.json()
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert data_resp["status"] is False
|
||||||
|
|
||||||
|
|
||||||
|
# @pytest.mark.django_db
|
||||||
|
# def test_create(data):
|
||||||
|
# urls, client, _ = data
|
||||||
|
# response = client.post(urls["list"], data={"name": "test"})
|
||||||
|
# assert response.json()["status"] is True
|
||||||
|
# assert response.status_code == 201
|
||||||
|
|
||||||
|
|
||||||
|
# @pytest.mark.django_db
|
||||||
|
# def test_update(data):
|
||||||
|
# urls, client, _ = data
|
||||||
|
# response = client.patch(urls["retrieve"], data={"name": "updated"})
|
||||||
|
# assert response.json()["status"] is True
|
||||||
|
# assert response.status_code == 200
|
||||||
|
#
|
||||||
|
# # verify updated value
|
||||||
|
# response = client.get(urls["retrieve"])
|
||||||
|
# assert response.json()["status"] is True
|
||||||
|
# assert response.status_code == 200
|
||||||
|
# assert response.json()["data"]["name"] == "updated"
|
||||||
|
|
||||||
|
|
||||||
|
# @pytest.mark.django_db
|
||||||
|
# def test_partial_update():
|
||||||
|
# urls, client, _ = data
|
||||||
|
# response = client.patch(urls["retrieve"], data={"name": "updated"})
|
||||||
|
# assert response.json()["status"] is True
|
||||||
|
# assert response.status_code == 200
|
||||||
|
#
|
||||||
|
# # verify updated value
|
||||||
|
# response = client.get(urls["retrieve"])
|
||||||
|
# assert response.json()["status"] is True
|
||||||
|
# assert response.status_code == 200
|
||||||
|
# assert response.json()["data"]["name"] == "updated"
|
||||||
|
|
||||||
|
|
||||||
|
# @pytest.mark.django_db
|
||||||
|
# def test_destroy(data):
|
||||||
|
# urls, client, _ = data
|
||||||
|
# response = client.delete(urls["retrieve"])
|
||||||
|
# assert response.status_code == 204
|
||||||
1
core/apps/api/translation/__init__.py
Normal file
1
core/apps/api/translation/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .attributes import * # noqa
|
||||||
18
core/apps/api/translation/attributes.py
Normal file
18
core/apps/api/translation/attributes.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from modeltranslation.translator import TranslationOptions, register
|
||||||
|
|
||||||
|
from core.apps.api.models import ColorModel, ProductlikeModel, SizeModel
|
||||||
|
|
||||||
|
|
||||||
|
@register(SizeModel)
|
||||||
|
class SizeTranslation(TranslationOptions):
|
||||||
|
fields = []
|
||||||
|
|
||||||
|
|
||||||
|
@register(ColorModel)
|
||||||
|
class ColorTranslation(TranslationOptions):
|
||||||
|
fields = []
|
||||||
|
|
||||||
|
|
||||||
|
@register(ProductlikeModel)
|
||||||
|
class ProductlikeTranslation(TranslationOptions):
|
||||||
|
fields = []
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
from django.urls import path, include
|
from django.urls import include, path
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
|
from .views import ColorView, ProductlikeView, SizeView
|
||||||
|
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
|
router.register("productlike", ProductlikeView, basename="productlike")
|
||||||
|
router.register("color", ColorView, basename="color")
|
||||||
urlpatterns = [
|
router.register("size", SizeView, basename="size")
|
||||||
path("", include(router.urls)),
|
urlpatterns = [path("", include(router.urls))]
|
||||||
]
|
|
||||||
|
|||||||
1
core/apps/api/validators/__init__.py
Normal file
1
core/apps/api/validators/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .attributes import * # noqa
|
||||||
22
core/apps/api/validators/attributes.py
Normal file
22
core/apps/api/validators/attributes.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
|
|
||||||
|
class SizeValidator:
|
||||||
|
def __init__(self): ...
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class ColorValidator:
|
||||||
|
def __init__(self): ...
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class ProductlikeValidator:
|
||||||
|
def __init__(self): ...
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
return True
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .attributes import * # noqa
|
||||||
|
|||||||
59
core/apps/api/views/attributes.py
Normal file
59
core/apps/api/views/attributes.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
from django_core.mixins import BaseViewSetMixin
|
||||||
|
from drf_spectacular.utils import extend_schema
|
||||||
|
from rest_framework.permissions import AllowAny
|
||||||
|
from rest_framework.viewsets import ReadOnlyModelViewSet
|
||||||
|
|
||||||
|
from core.apps.api.models import ColorModel, ProductlikeModel, SizeModel
|
||||||
|
from core.apps.api.serializers.attributes import (
|
||||||
|
CreateColorSerializer,
|
||||||
|
CreateProductlikeSerializer,
|
||||||
|
CreateSizeSerializer,
|
||||||
|
ListColorSerializer,
|
||||||
|
ListProductlikeSerializer,
|
||||||
|
ListSizeSerializer,
|
||||||
|
RetrieveColorSerializer,
|
||||||
|
RetrieveProductlikeSerializer,
|
||||||
|
RetrieveSizeSerializer,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema(tags=["size"])
|
||||||
|
class SizeView(BaseViewSetMixin, ReadOnlyModelViewSet):
|
||||||
|
queryset = SizeModel.objects.all()
|
||||||
|
serializer_class = ListSizeSerializer
|
||||||
|
permission_classes = [AllowAny]
|
||||||
|
|
||||||
|
action_permission_classes = {}
|
||||||
|
action_serializer_class = {
|
||||||
|
"list": ListSizeSerializer,
|
||||||
|
"retrieve": RetrieveSizeSerializer,
|
||||||
|
"create": CreateSizeSerializer,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema(tags=["color"])
|
||||||
|
class ColorView(BaseViewSetMixin, ReadOnlyModelViewSet):
|
||||||
|
queryset = ColorModel.objects.all()
|
||||||
|
serializer_class = ListColorSerializer
|
||||||
|
permission_classes = [AllowAny]
|
||||||
|
|
||||||
|
action_permission_classes = {}
|
||||||
|
action_serializer_class = {
|
||||||
|
"list": ListColorSerializer,
|
||||||
|
"retrieve": RetrieveColorSerializer,
|
||||||
|
"create": CreateColorSerializer,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema(tags=["productlike"])
|
||||||
|
class ProductlikeView(BaseViewSetMixin, ReadOnlyModelViewSet):
|
||||||
|
queryset = ProductlikeModel.objects.all()
|
||||||
|
serializer_class = ListProductlikeSerializer
|
||||||
|
permission_classes = [AllowAny]
|
||||||
|
|
||||||
|
action_permission_classes = {}
|
||||||
|
action_serializer_class = {
|
||||||
|
"list": ListProductlikeSerializer,
|
||||||
|
"retrieve": RetrieveProductlikeSerializer,
|
||||||
|
"create": CreateProductlikeSerializer,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user