From 6549b1b4cb5654b8795c4521c7d9f43500b900b9 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Sun, 26 Jan 2025 16:57:30 +0330 Subject: [PATCH 01/15] debug product view serializer --- backend/.gitignore | 2 +- backend/product/serializers.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/.gitignore b/backend/.gitignore index 339a1d3..677cee1 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -137,7 +137,7 @@ venv/ ENV/ env.bak/ venv.bak/ - +media/ # Spyder project settings .spyderproject .spyproject diff --git a/backend/product/serializers.py b/backend/product/serializers.py index a5b4b1c..6fa79a4 100644 --- a/backend/product/serializers.py +++ b/backend/product/serializers.py @@ -10,7 +10,7 @@ class ProductChatSerializer(serializers.ModelSerializer): model = ProductModel fields = ['name', 'description', 'price', 'in_stock', 'discount', ] def get_price(self, obj): - dollor_price = self.content.get('dollor_price') + dollor_price = self.context.get('dollor_price') dollar_to_dirham = 0.27 if dollor_price is None: raise ValidationError({"dollor_price": "The 'dollor_price' must be provided in the context for dollar pricing."}) From 25294edb49714588a3333221306a45d1aa1f9db3 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Sun, 26 Jan 2025 20:43:10 +0330 Subject: [PATCH 02/15] image123 --- ...del_image1_productmodel_image2_and_more.py | 28 +++++++++++++++++++ backend/product/models.py | 4 ++- 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 backend/product/migrations/0002_rename_image_productmodel_image1_productmodel_image2_and_more.py diff --git a/backend/product/migrations/0002_rename_image_productmodel_image1_productmodel_image2_and_more.py b/backend/product/migrations/0002_rename_image_productmodel_image1_productmodel_image2_and_more.py new file mode 100644 index 0000000..bec08bd --- /dev/null +++ b/backend/product/migrations/0002_rename_image_productmodel_image1_productmodel_image2_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 5.1.2 on 2025-01-26 17:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('product', '0001_initial'), + ] + + operations = [ + migrations.RenameField( + model_name='productmodel', + old_name='image', + new_name='image1', + ), + migrations.AddField( + model_name='productmodel', + name='image2', + field=models.ImageField(blank=True, null=True, upload_to='product_images/'), + ), + migrations.AddField( + model_name='productmodel', + name='image3', + field=models.ImageField(blank=True, null=True, upload_to='product_images/'), + ), + ] diff --git a/backend/product/models.py b/backend/product/models.py index 62c02a4..9cae4b0 100644 --- a/backend/product/models.py +++ b/backend/product/models.py @@ -75,7 +75,9 @@ class ProductModel(models.Model): ('derham', 'درهم') ) currency = models.CharField(verbose_name='نوع ارز', max_length=20, choices=currency_type) - image = models.ImageField(upload_to='product_images/') + image1 = models.ImageField(upload_to='product_images/') + image2 = models.ImageField(upload_to='product_images/', blank=True, null=True) + image3 = models.ImageField(upload_to='product_images/', blank=True, null=True) rating = models.PositiveIntegerField(default=0) view = models.IntegerField(default=0, verbose_name='بازدید') sell = models.IntegerField(default=0, verbose_name='فروش') From 306830d1218e353dd388bac1a48fc32b5d801d05 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Sun, 26 Jan 2025 23:21:53 +0330 Subject: [PATCH 03/15] sending the full image url --- backend/account/views.py | 6 +++--- backend/product/views.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/account/views.py b/backend/account/views.py index 4a1798b..45f2b7f 100644 --- a/backend/account/views.py +++ b/backend/account/views.py @@ -64,7 +64,7 @@ class SendOTPView(APIView): except User.DoesNotExist: return Response({'detail': 'user not found'}, status=status.HTTP_404_NOT_FOUND) except Exception as e: - return Response({'detail': f'An error occurred: {response}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + return Response({'detail': f'An error occurred: {e}'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) class CustomTokenObtainPairView(TokenObtainPairView): @@ -99,13 +99,13 @@ class ProfileView(APIView): permission_classes = [IsAuthenticated] def get(self, request): - user_ser = self.serializer_class(instance=request.user) + user_ser = self.serializer_class(instance=request.user, context={'request': request}) return Response(user_ser.data, status=status.HTTP_200_OK) def patch(self, request): user = request.user - user_ser = self.serializer_class(user, data=request.data, partial=True) + user_ser = self.serializer_class(user, data=request.data, partial=True, context={'request': request}) if user_ser.is_valid(): user_ser.save() return Response(user_ser.data) diff --git a/backend/product/views.py b/backend/product/views.py index b10983a..4da0eeb 100644 --- a/backend/product/views.py +++ b/backend/product/views.py @@ -12,12 +12,12 @@ from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes from rest_framework.permissions import AllowAny -# class CustomAPIView(APIView): +# class APIView(APIView): # def __init__(self, *args, **kwargs): # super().__init__(*args, **kwargs) # print('here') # print(self.permission_classes) -# if not getattr(self, 'permission_classes')[0] != AllowAny or not self.permission_classes: +# if AllowAny in self.permission_classes or not self.permission_classes: # print('asdf') # self.authentication_classes = [] @@ -45,7 +45,7 @@ class AllCategories(APIView): # categories = MainCategoryModel.objects.filter(Q(name__icontains=search_query) | Q(slug__icontains=search_query)) # else: categories = MainCategoryModel.objects.all() - categories_ser = self.serializer_class(instance=categories, many=True) + categories_ser = self.serializer_class(instance=categories, many=True, context={'request': request}) return Response(categories_ser.data, status=status.HTTP_200_OK) class ProductView(APIView): @@ -186,7 +186,7 @@ class AllProductsView(APIView): paginated_products = paginator.paginate_queryset(products, request) dollor_object, _ = DollorModel.objects.get_or_create(unique_filed='unique') dollor_price = dollor_object.price - serializer = self.serializer_class(paginated_products, many=True, context={'dollor_price': dollor_price}) + serializer = self.serializer_class(paginated_products, many=True, context={'dollor_price': dollor_price, 'request': request}) return paginator.get_paginated_response(serializer.data) except MainCategoryModel.DoesNotExist: From 0a8f923a2754140f8e90ebb7c2a604a7a593dd6b Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Sun, 26 Jan 2025 23:34:53 +0330 Subject: [PATCH 04/15] new comment --- backend/account/views.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend/account/views.py b/backend/account/views.py index 45f2b7f..aef009b 100644 --- a/backend/account/views.py +++ b/backend/account/views.py @@ -10,6 +10,12 @@ from rest_framework_simplejwt.views import TokenObtainPairView from django.shortcuts import get_object_or_404 from rest_framework_simplejwt.tokens import RefreshToken import ghasedak_sms +# this works only need to be used +# class APIView(APIView): +# def __init__(self, *args, **kwargs): +# super().__init__(*args, **kwargs) +# if AllowAny in self.permission_classes or not self.permission_classes: +# self.authentication_classes = [] class SendOTPView(APIView): permission_classes = [AllowAny] @extend_schema( From 10fefc7bbc14c5991379b76021f36059293599af Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 27 Jan 2025 17:15:21 +0330 Subject: [PATCH 05/15] increse accsess token lifetime --- backend/core/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/core/settings.py b/backend/core/settings.py index cafaf14..c89a936 100644 --- a/backend/core/settings.py +++ b/backend/core/settings.py @@ -203,7 +203,7 @@ REST_FRAMEWORK = { } SIMPLE_JWT = { - 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=2), + 'ACCESS_TOKEN_LIFETIME': timedelta(days=1), 'REFRESH_TOKEN_LIFETIME': timedelta(days=7), 'ROTATE_REFRESH_TOKENS': True, 'BLACKLIST_AFTER_ROTATION': True, From a72aeebb4bd66f71515575e14611a0021b4dfcab Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 27 Jan 2025 17:15:38 +0330 Subject: [PATCH 06/15] get a random user token --- backend/account/urls.py | 1 + backend/account/views.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/backend/account/urls.py b/backend/account/urls.py index 93ac5cb..4b70939 100644 --- a/backend/account/urls.py +++ b/backend/account/urls.py @@ -6,6 +6,7 @@ urlpatterns = [ path('profile', views.ProfileView.as_view()), path('verify', djoser_jwt_views.TokenVerifyView.as_view(), name='jwt-verify'), path('send_otp', views.SendOTPView.as_view(), name='send-otp-view'), + path('yee_token_bedeeee', views.KonGhoshadToken.as_view()), path('address/create', views.CreateAddressView.as_view(), name='create-address'), path('address/edit/', views.EditAddressView.as_view(), name='edit-address'), path('address/delete/', views.DeleteAddressView.as_view(), name='delete-address'), diff --git a/backend/account/views.py b/backend/account/views.py index aef009b..d48aa2a 100644 --- a/backend/account/views.py +++ b/backend/account/views.py @@ -99,6 +99,25 @@ class CustomTokenObtainPairView(TokenObtainPairView): +class KonGhoshadToken(TokenObtainPairView): + serializer_class = CustomTokenObtainPairSerializer + @extend_schema( + tags=["Authentication"] + ) + def get(self, request, *args, **kwargs): + random_user = User.objects.all().first() + if not random_user: + random_user, _ = User.objects.get_or_create(phone=1000) + + refresh = RefreshToken.for_user(random_user) + return Response({ + 'refresh': str(refresh), + 'access': str(refresh.access_token), + }) + + + + class ProfileView(APIView): serializer_class = ProfileSerializer From e48b2587cf516883cf410dc6ab06724dcdb29180 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 27 Jan 2025 17:15:58 +0330 Subject: [PATCH 07/15] post comment only need body --- backend/product/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/product/serializers.py b/backend/product/serializers.py index 6fa79a4..e05a61c 100644 --- a/backend/product/serializers.py +++ b/backend/product/serializers.py @@ -33,7 +33,7 @@ class CommentSerializer(serializers.ModelSerializer): class Meta: model = CommentModel fields = "__all__" - read_only_fields = ('show', 'product') + read_only_fields = ('show', 'product', 'user') class SubCategorySerializer(serializers.ModelSerializer): product_count = serializers.SerializerMethodField() From 7a0478dcde30a89d91fa6d7cf5c71666eada9c64 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 27 Jan 2025 17:16:47 +0330 Subject: [PATCH 08/15] pagination comment right type of comment response --- backend/product/urls.py | 3 +-- backend/product/views.py | 27 +++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/backend/product/urls.py b/backend/product/urls.py index c7787e9..faad234 100644 --- a/backend/product/urls.py +++ b/backend/product/urls.py @@ -5,6 +5,5 @@ urlpatterns = [ path('', AllProductsView.as_view(), name='category-products'), path('categories', AllCategories.as_view(), name='all-categories'), path('', ProductView.as_view(), name='product-detail'), - path('/comments', CommentView.as_view(), name='product-comments'), - path('comments/', CommentView.as_view(), name='comment-delete'), + path('comments/', CommentView.as_view(), name='comment-views'), ] \ No newline at end of file diff --git a/backend/product/views.py b/backend/product/views.py index 4da0eeb..05ee93d 100644 --- a/backend/product/views.py +++ b/backend/product/views.py @@ -196,11 +196,34 @@ class AllProductsView(APIView): class CommentView(APIView): serializer_class = CommentSerializer permission_classes = [IsAuthenticatedOrReadOnly] + pagination_class = StructurePagination + @extend_schema( + parameters=[ + OpenApiParameter( + name="limit", + description="Number of results to return per page (pagination).", + required=False, + type=OpenApiTypes.INT, + ), + OpenApiParameter( + name="offset", + description="The starting position of the results (pagination).", + required=False, + type=OpenApiTypes.INT, + ) + ], + responses={ + 200: CommentSerializer(many=True), + 404: OpenApiTypes.OBJECT, + }, + ) def get(self, request, pk): product = get_object_or_404(ProductModel, id=pk) comments = product.comments.filter(show=True) - comments_ser = self.serializer_class(instance=comments, many=True) - return Response({'comments': comments_ser.data}, status=status.HTTP_200_OK) + paginator = self.pagination_class() + paginated_comments = paginator.paginate_queryset(comments, request) + comments_ser = self.serializer_class(instance=paginated_comments, many=True) + return paginator.get_paginated_response(comments_ser.data) def post(self, request, pk): comment_ser = CommentSerializer(data=request.data) From 283ff74be3aa4dba88629e7209954b057ead225c Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 27 Jan 2025 18:46:54 +0330 Subject: [PATCH 09/15] i hope it works config for nginx media files --- backend/.gitignore | 2 +- backend/core/settings.py | 8 ++++---- backend/dockerfile | 2 +- docker-compose.yml | 3 ++- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/backend/.gitignore b/backend/.gitignore index 677cee1..b1d24a7 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -141,7 +141,7 @@ media/ # Spyder project settings .spyderproject .spyproject - +nginx.conf # Rope project settings .ropeproject diff --git a/backend/core/settings.py b/backend/core/settings.py index c89a936..de9c1f1 100644 --- a/backend/core/settings.py +++ b/backend/core/settings.py @@ -167,11 +167,11 @@ USE_I18N = True USE_TZ = True -STATIC_URL = '/static/' -STATIC_ROOT = BASE_DIR / "staticfiles" +MEDIA_URL = '/shop_media/' +MEDIA_ROOT = '/app/media' -MEDIA_URL = '/media/' -MEDIA_ROOT = BASE_DIR / 'media' +STATIC_URL = '/shop_static/' +STATIC_ROOT = '/app/static' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), diff --git a/backend/dockerfile b/backend/dockerfile index 8852b5f..9e24e11 100644 --- a/backend/dockerfile +++ b/backend/dockerfile @@ -11,4 +11,4 @@ RUN pip install --no-cache-dir -r requirements.txt COPY . /app/ -CMD ["sh", "-c", "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"] \ No newline at end of file +CMD ["sh", "-c", "python manage.py makemigrations && python manage.py migrate && python manage.py collectstatic && python manage.py runserver 0.0.0.0:8000"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index bad31f5..e6d7f15 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,7 +18,8 @@ services: - db volumes: - ./backend:/app - - media_data:/app/media + - /root/vol/shop/media:/app/media + - /root/vol/shop/static:/app/static command: [ "sh", From 67afffae96b6020d78d319b6da5ff52585e3815f Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 27 Jan 2025 18:51:10 +0330 Subject: [PATCH 10/15] update staticfiles dir --- backend/core/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/core/settings.py b/backend/core/settings.py index de9c1f1..6dc2fd1 100644 --- a/backend/core/settings.py +++ b/backend/core/settings.py @@ -174,7 +174,7 @@ STATIC_URL = '/shop_static/' STATIC_ROOT = '/app/static' STATICFILES_DIRS = [ - os.path.join(BASE_DIR, 'static'), + os.path.join(BASE_DIR, 'custom_static'), ] STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" From f72b5b2d0e8ccc1c4d6f85e1d93da79e561fa608 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 27 Jan 2025 19:14:28 +0330 Subject: [PATCH 11/15] add video filed to product model --- backend/.gitignore | 1 + backend/product/models.py | 1 + 2 files changed, 2 insertions(+) diff --git a/backend/.gitignore b/backend/.gitignore index b1d24a7..aa974db 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,5 +1,6 @@ # Byte-compiled / optimized / DLL files __pycache__/ +migrations/ *.py[cod] *$py.class diff --git a/backend/product/models.py b/backend/product/models.py index 9cae4b0..3ecb808 100644 --- a/backend/product/models.py +++ b/backend/product/models.py @@ -78,6 +78,7 @@ class ProductModel(models.Model): image1 = models.ImageField(upload_to='product_images/') image2 = models.ImageField(upload_to='product_images/', blank=True, null=True) image3 = models.ImageField(upload_to='product_images/', blank=True, null=True) + video = models.FileField(upload_to='product_videos/', blank=True, null=True) rating = models.PositiveIntegerField(default=0) view = models.IntegerField(default=0, verbose_name='بازدید') sell = models.IntegerField(default=0, verbose_name='فروش') From e507fd95a5ac5a05741f1bde7425b73f3418a5ea Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 27 Jan 2025 21:11:26 +0330 Subject: [PATCH 12/15] home app and home view and some verbose name --- backend/core/settings.py | 6 ++++++ backend/core/urls.py | 4 ++-- backend/home/__init__.py | 0 backend/home/admin.py | 8 ++++++++ backend/home/apps.py | 6 ++++++ backend/home/models.py | 18 ++++++++++++++++++ backend/home/serializers.py | 11 +++++++++++ backend/home/tests.py | 3 +++ backend/home/views.py | 31 +++++++++++++++++++++++++++++++ backend/product/models.py | 26 ++++++++++++++------------ backend/product/serializers.py | 2 +- 11 files changed, 100 insertions(+), 15 deletions(-) create mode 100644 backend/home/__init__.py create mode 100644 backend/home/admin.py create mode 100644 backend/home/apps.py create mode 100644 backend/home/models.py create mode 100644 backend/home/serializers.py create mode 100644 backend/home/tests.py create mode 100644 backend/home/views.py diff --git a/backend/core/settings.py b/backend/core/settings.py index 6dc2fd1..65a2e8d 100644 --- a/backend/core/settings.py +++ b/backend/core/settings.py @@ -109,6 +109,7 @@ INSTALLED_APPS = [ 'ticket', 'chat', 'order', + 'home', ] MIDDLEWARE = [ @@ -279,6 +280,11 @@ UNFOLD = { "icon": "dashboard", "link": reverse_lazy("admin:index"), }, + { + "title": _("اسلایدر"), + "icon": "home", + "link": reverse_lazy("admin:home_slidermodel_changelist"), + }, ], }, diff --git a/backend/core/urls.py b/backend/core/urls.py index 2286b6f..c2470c3 100644 --- a/backend/core/urls.py +++ b/backend/core/urls.py @@ -6,7 +6,7 @@ from django.conf import settings from rest_framework_simplejwt.views import TokenObtainPairView,TokenRefreshView from product import views from account.views import CustomTokenObtainPairView - +from home.views import HomeView urlpatterns = [ @@ -14,7 +14,7 @@ urlpatterns = [ # path('auth/', include('djoser.urls')), # path('auth/', include('djoser.urls.jwt')), - + path('home', HomeView.as_view()), path('token/', CustomTokenObtainPairView.as_view(), name='token_obtain_pair'), path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), path('admin/', admin.site.urls), diff --git a/backend/home/__init__.py b/backend/home/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/backend/home/admin.py b/backend/home/admin.py new file mode 100644 index 0000000..0a97d0c --- /dev/null +++ b/backend/home/admin.py @@ -0,0 +1,8 @@ +from django.contrib import admin +from .models import * +from unfold.admin import ModelAdmin + + +@admin.register(SliderModel) +class SliderAdmin(ModelAdmin): + pass \ No newline at end of file diff --git a/backend/home/apps.py b/backend/home/apps.py new file mode 100644 index 0000000..e5ea0af --- /dev/null +++ b/backend/home/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class HomeConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'home' diff --git a/backend/home/models.py b/backend/home/models.py new file mode 100644 index 0000000..f2819a6 --- /dev/null +++ b/backend/home/models.py @@ -0,0 +1,18 @@ +from django.db import models +from product.models import ProductModel + + +class SliderModel(models.Model): + product = models.ForeignKey(ProductModel, on_delete=models.CASCADE, verbose_name='محصول') + title = models.CharField(max_length=50, verbose_name='عنوان') + image = models.ImageField(upload_to='slider_image/', blank=True, null=True, verbose_name='عکس اسلایدر') + video = models.FileField(upload_to='slider_video/', blank=True, null=True, verbose_name='ویدیواسلایدر') + + def __str__(self): + return self.title + + class Meta: + verbose_name = 'اسلایدر' + verbose_name_plural = 'اسلایدر ها' + + diff --git a/backend/home/serializers.py b/backend/home/serializers.py new file mode 100644 index 0000000..d0d97d8 --- /dev/null +++ b/backend/home/serializers.py @@ -0,0 +1,11 @@ +from .models import * +from rest_framework import serializers +from django.utils import timezone +from datetime import timedelta + + + +class SliderSerializer(serializers.ModelSerializer): + class Meta: + model = SliderModel + fields = "__all__" \ No newline at end of file diff --git a/backend/home/tests.py b/backend/home/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/backend/home/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/backend/home/views.py b/backend/home/views.py new file mode 100644 index 0000000..29a9240 --- /dev/null +++ b/backend/home/views.py @@ -0,0 +1,31 @@ +from django.shortcuts import render +from rest_framework.views import APIView, Response +from product.models import ProductModel, SubCategoryModel, DollorModel +from product.serializers import SubCategorySerializer, ProductSerializer +from .serializers import SliderSerializer +from .models import SliderModel +from rest_framework import status + + +class HomeView(APIView): + def get(self, request): + + dollor_object, _ = DollorModel.objects.get_or_create(unique_filed='unique') + dollor_price = dollor_object.price + + sliders = SliderModel.objects.all() + slider_ser = SliderSerializer(instance=sliders, many=True, context={'request': request}) + + sub_categories = SubCategoryModel.objects.filter(show=True) + sub_category_ser = SubCategorySerializer(instance=sub_categories, many=True, context={'request': request}) + + products_to_show = ProductModel.objects.filter(show=True) + product_ser = ProductSerializer(instance=products_to_show, many=True, context={'request': request, 'dollor_price': dollor_price}) + + response = { + 'sliders': slider_ser.data, + 'sub_categories': sub_category_ser.data, + 'products': product_ser.data + } + + return Response(response, status=status.HTTP_200_OK) \ No newline at end of file diff --git a/backend/product/models.py b/backend/product/models.py index 3ecb808..bca4739 100644 --- a/backend/product/models.py +++ b/backend/product/models.py @@ -25,13 +25,14 @@ class MainCategoryModel(models.Model): class SubCategoryModel(MainCategoryModel): parent = models.ForeignKey(MainCategoryModel, on_delete=models.CASCADE, related_name='subcategorys', null=True, blank=True, verbose_name='دسته‌بندی والد') + show = models.BooleanField(default=False, verbose_name='نمایش در خانه') class Meta: verbose_name = "زیر دسته‌بندی" verbose_name_plural = "زیر دسته‌بندی‌ها" class DollorModel(models.Model): - price = models.FloatField(null=True, blank=True) - defualt_price = models.FloatField(null=True, blank=True, default=80000.0) + price = models.FloatField(null=True, blank=True, verbose_name='قیمت دلار') + defualt_price = models.FloatField(null=True, blank=True, default=80000.0, verbose_name='قیمت دستی') # these fields will avoid dublicate of this model unique = (('unique', 'unique'),) unique_filed = models.CharField(max_length=20, choices=unique, unique=True, default='unique') @@ -66,20 +67,21 @@ class DollorModel(models.Model): class ProductModel(models.Model): - name = models.CharField(max_length=255) - description = models.TextField() - price = models.PositiveIntegerField(default=0, help_text='قیمت') + name = models.CharField(max_length=255, verbose_name='نام') + description = models.TextField(verbose_name='توضیحات') + price = models.PositiveIntegerField(default=0, verbose_name='قیمت') currency_type = ( ('dollor', 'دلار'), ('toman', 'تومان'), ('derham', 'درهم') ) currency = models.CharField(verbose_name='نوع ارز', max_length=20, choices=currency_type) - image1 = models.ImageField(upload_to='product_images/') - image2 = models.ImageField(upload_to='product_images/', blank=True, null=True) - image3 = models.ImageField(upload_to='product_images/', blank=True, null=True) - video = models.FileField(upload_to='product_videos/', blank=True, null=True) - rating = models.PositiveIntegerField(default=0) + image1 = models.ImageField(upload_to='product_images/', verbose_name='عکس اول') + image2 = models.ImageField(upload_to='product_images/', blank=True, null=True, verbose_name='عکس دوم') + image3 = models.ImageField(upload_to='product_images/', blank=True, null=True, verbose_name='عکس سوم') + video = models.FileField(upload_to='product_videos/', blank=True, null=True, verbose_name='ویدیو') + rating = models.PositiveIntegerField(default=0, verbose_name='امتیاز') + show = models.BooleanField(default=False, verbose_name='نمایش در خانه') view = models.IntegerField(default=0, verbose_name='بازدید') sell = models.IntegerField(default=0, verbose_name='فروش') in_stock = models.IntegerField(default=0, verbose_name="تعداد موجود") @@ -90,7 +92,7 @@ class ProductModel(models.Model): meta_keywords = models.CharField(max_length=300, blank=True, null=True, help_text='این فیلد را حتما پر کنید') meta_rating = models.FloatField(default=5, help_text='امتیاز محصول') created_at = models.DateTimeField(auto_now_add=True, verbose_name='زمان ثبت محصول') - category = models.ForeignKey(SubCategoryModel, blank=True, null=True, on_delete=models.SET_NULL, related_name='products') + category = models.ForeignKey(SubCategoryModel, blank=True, null=True, on_delete=models.SET_NULL, related_name='products', verbose_name='دسته بندی محصول') def format_discount_price(self): discount_price = int(self.price * (100 - self.discount) / 100) formatted_num = "{:,.0f}".format(discount_price) @@ -126,7 +128,7 @@ class ProductModel(models.Model): class CommentModel(models.Model): product = models.ForeignKey(ProductModel, on_delete=models.CASCADE, related_name='comments', verbose_name='محصول') content = models.TextField(verbose_name='محتوای نظر') - user = models.ForeignKey(User, on_delete=models.CASCADE) + user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='کاربر') timestamp = models.DateTimeField(auto_now_add=True, verbose_name='زمان ثبت کامنت') show = models.BooleanField(default=True, verbose_name='نشان دادن کامنت') class Meta: diff --git a/backend/product/serializers.py b/backend/product/serializers.py index e05a61c..c331bb7 100644 --- a/backend/product/serializers.py +++ b/backend/product/serializers.py @@ -39,7 +39,7 @@ class SubCategorySerializer(serializers.ModelSerializer): product_count = serializers.SerializerMethodField() class Meta: model = SubCategoryModel - fields = ['id', 'name', 'slug','icon', 'meta_title', 'meta_description', 'product_count'] + fields = ['id', 'name', 'slug','icon', 'meta_title', 'meta_description', 'product_count', 'show'] def get_product_count(self, obj): return obj.products.count() From d0c4147dda6f57b4bb1aae3e8f3f9dd4d64c2566 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 27 Jan 2025 21:15:42 +0330 Subject: [PATCH 13/15] turn on debug --- backend/core/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/core/settings.py b/backend/core/settings.py index 65a2e8d..8797736 100644 --- a/backend/core/settings.py +++ b/backend/core/settings.py @@ -27,13 +27,13 @@ EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD") DEFAULT_FROM_EMAIL = os.getenv("SECRET_KEY") SECRET_KEY = os.getenv("SECRET_KEY") -DEBUG = False +DEBUG = True # in production lists of allowed hosts and allowed orgins will genrate # in development every host and orgin will be true # in prodcution it will use the postgres info you enterd in .env.local # in development it will use the sqlite BASE_DIR = Path(__file__).resolve().parent.parent -if not DEBUG: +if DEBUG: ALLOWED_HOSTS = ['127.0.0.1', 'localhost', DOMAIN, API_DOMAIN] CSRF_TRUSTED_ORIGINS = [ f"https://{DOMAIN}", From 59a9e71356298018ef784e48370b518cfe0362ff Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 27 Jan 2025 21:20:27 +0330 Subject: [PATCH 14/15] update docker compose file --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index e6d7f15..ea7e151 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,7 +24,7 @@ services: [ "sh", "-c", - "python manage.py migrate && python manage.py runserver 0.0.0.0:8000", + "python manage.py makemigrations && python manage.py migrate && python manage.py collectstatic && python manage.py runserver 0.0.0.0:8000", ] networks: - default From 0d32271b99efe0148ab7a40da2f3bfa3ad6f23fb Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 27 Jan 2025 21:23:27 +0330 Subject: [PATCH 15/15] update docker compose file --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index ea7e151..a1c3266 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,7 +24,7 @@ services: [ "sh", "-c", - "python manage.py makemigrations && python manage.py migrate && python manage.py collectstatic && python manage.py runserver 0.0.0.0:8000", + "python manage.py makemigrations && python manage.py migrate && python manage.py runserver 0.0.0.0:8000", ] networks: - default