From 6965fed7f5d07d12d71fbfb91af306d643cb58e5 Mon Sep 17 00:00:00 2001 From: behruz-dev Date: Wed, 26 Nov 2025 16:35:18 +0500 Subject: [PATCH] user list qoshildi --- config/conf/rest_framework.py | 2 + config/settings/base.py | 1 + config/urls.py | 1 + core/apps/dashboard/__init__.py | 0 core/apps/dashboard/apps.py | 6 ++ core/apps/dashboard/migrations/__init__.py | 0 core/apps/dashboard/serializers/user.py | 71 ++++++++++++++ core/apps/dashboard/urls.py | 14 +++ core/apps/dashboard/views/user.py | 105 +++++++++++++++++++++ core/apps/shared/views/plan.py | 3 + 10 files changed, 203 insertions(+) create mode 100644 core/apps/dashboard/__init__.py create mode 100644 core/apps/dashboard/apps.py create mode 100644 core/apps/dashboard/migrations/__init__.py create mode 100644 core/apps/dashboard/serializers/user.py create mode 100644 core/apps/dashboard/urls.py create mode 100644 core/apps/dashboard/views/user.py diff --git a/config/conf/rest_framework.py b/config/conf/rest_framework.py index 27753b7..c9e708a 100644 --- a/config/conf/rest_framework.py +++ b/config/conf/rest_framework.py @@ -4,4 +4,6 @@ REST_FRAMEWORK = { 'rest_framework.authentication.BasicAuthentication', 'rest_framework_simplejwt.authentication.JWTAuthentication', ], + 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', + 'PAGE_SIZE': 10 } \ No newline at end of file diff --git a/config/settings/base.py b/config/settings/base.py index 1ca9dea..b6ccc95 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -28,6 +28,7 @@ INSTALLED_APPS = [ 'core.apps.authentication', 'core.apps.accounts', 'core.apps.orders', + 'core.apps.dashboard', ] MIDDLEWARE = [ diff --git a/config/urls.py b/config/urls.py index 4f81364..4b760f8 100644 --- a/config/urls.py +++ b/config/urls.py @@ -40,6 +40,7 @@ urlpatterns += [ path('authentication/', include('core.apps.authentication.urls')), path('shared/', include('core.apps.shared.urls')), path('orders/', include('core.apps.orders.urls')), + path('admin/', include('core.apps.dashboard.urls')), ], )), ] \ No newline at end of file diff --git a/core/apps/dashboard/__init__.py b/core/apps/dashboard/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/apps/dashboard/apps.py b/core/apps/dashboard/apps.py new file mode 100644 index 0000000..32f9313 --- /dev/null +++ b/core/apps/dashboard/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class DashboardConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'core.apps.dashboard' diff --git a/core/apps/dashboard/migrations/__init__.py b/core/apps/dashboard/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/apps/dashboard/serializers/user.py b/core/apps/dashboard/serializers/user.py new file mode 100644 index 0000000..e7c32f5 --- /dev/null +++ b/core/apps/dashboard/serializers/user.py @@ -0,0 +1,71 @@ +# django +from django.db import transaction + +# rest framework +from rest_framework import serializers + +# accounts +from core.apps.accounts.models import User +# shared +from core.apps.shared.models import Region + + +class UserListSerializer(serializers.ModelSerializer): + region = serializers.SerializerMethodField() + + class Meta: + model = User + fields = [ + 'id', + 'first_name', + 'last_name', + 'region', + 'is_active', + 'created_at' + ] + + def get_region(self, obj): + return { + 'id': obj.region.id, + 'name': obj.region.name, + } + + +class UserCreateSerializer(serializers.Serializer): + first_name = serializers.CharField() + last_name = serializers.CharField() + region_id = serializers.IntegerField() + is_active = serializers.BooleanField() + + def validate(self, data): + region = Region.objects.filter(id=data['region_id']).first() + if not region: + raise serializers.ValidationError({"region": "Region topilmadi"}) + data['region'] = region + return data + + def create(self, validated_data): + with transaction.atomic(): + return User.objects.create( + username=f"{validated_data.get('first_name')} {validated_data.get('last_name')}", + first_name=validated_data.get('first_name'), + last_name=validated_data.get('last_name'), + region=validated_data.get('region'), + is_active=validated_data.get('is_active'), + ) + + +class UserUpdateSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = [ + 'first_name', 'last_name', 'region', 'is_active', + ] + + def update(self, instance, validated_data): + instance.first_name = validated_data.get('first_name', instance.first_name) + instance.last_name = validated_data.get('last_name', instance.last_name) + instance.region = validated_data.get('region', instance.region) + instance.is_active = validated_data.get('is_active', instance.is_active) + instance.save() + return instance \ No newline at end of file diff --git a/core/apps/dashboard/urls.py b/core/apps/dashboard/urls.py new file mode 100644 index 0000000..1f915c5 --- /dev/null +++ b/core/apps/dashboard/urls.py @@ -0,0 +1,14 @@ +from django.urls import path, include + +### dashboard ### +# users +from core.apps.dashboard.views import user as user_views + + +urlpatterns = [ + path('user/', include( + [ + path('list/', user_views.UserListApiView.as_view(), name='user-list-api'), + ], + )), +] \ No newline at end of file diff --git a/core/apps/dashboard/views/user.py b/core/apps/dashboard/views/user.py new file mode 100644 index 0000000..6f32d7b --- /dev/null +++ b/core/apps/dashboard/views/user.py @@ -0,0 +1,105 @@ +# django +from django.shortcuts import get_object_or_404 +from django.db.models import Q + +# rest framework +from rest_framework import generics +from rest_framework.pagination import PageNumberPagination +from rest_framework.permissions import IsAdminUser + +# drf yasg +from drf_yasg import openapi +from drf_yasg.utils import swagger_auto_schema + +# dashboard +from core.apps.dashboard.serializers import user as serializers +# accounts +from core.apps.accounts.models import User +# shared +from core.apps.shared.utils.response_mixin import ResponseMixin + + + +class UserListApiView(generics.GenericAPIView, ResponseMixin): + serializer_class = serializers.UserListSerializer + queryset = User.objects.all() + permission_classes = [IsAdminUser] + + @swagger_auto_schema( + manual_parameters=[ + openapi.Parameter( + name='search', + in_=openapi.IN_QUERY, + description='Search by first_name or last_name', + type=openapi.TYPE_STRING, + required=False, + ) + ], + responses={ + 200: openapi.Response( + schema=None, + description="Foydalanuvchilar ro'yxati", + examples={ + "application/json": { + "status_code": 200, + "success": "success", + "message": "Foydalanuvchilar ro'yxati", + "data": { + "count": 0, + "next": "string", + "previous": "string", + "results": [ + { + "id": 0, + "first_name": "string", + "last_name": "string", + "region": "string", + "is_active": "true", + "created_at": "2025-11-26T11:07:58.483Z" + } + ] + } + } + } + ), + 500: openapi.Response( + schema=None, + description="Server Error", + examples={ + "application/json": { + "status_code": 500, + "success": "error", + "message": 'xatolik', + "data": "some errors..." + } + } + ), + } + ) + def get(self, request): + try: + queryset = self.queryset.exclude(id=request.user.id) + # filters + search = request.query_params.get('search') + + if search: + queryset = queryset.filter( + Q(first_name__istartswith=search) | + Q(last_name__istartswith=search) + ) + page = self.paginate_queryset(queryset=queryset) + if page is not None: + serializer = self.serializer_class(page, many=True) + paginated_data = self.get_paginated_response(serializer.data) + return self.success_response( + data=paginated_data.data, + message="Foydalanuvchilar ro'yxati", + ) + else: + serializer = self.serializer_class(queryset, many=True) + return self.success_response( + data=serializer.data, + message="Foydalanuvchilar ro'yxati", + ) + except Exception as e: + return self.error_response(str(e), message="xatolik") \ No newline at end of file diff --git a/core/apps/shared/views/plan.py b/core/apps/shared/views/plan.py index ca60ab0..acbe906 100644 --- a/core/apps/shared/views/plan.py +++ b/core/apps/shared/views/plan.py @@ -66,6 +66,9 @@ class ComplitePlanApiView(generics.GenericAPIView, ResponseMixin): queryset = Plan.objects.all() permission_classes = [permissions.IsAuthenticated] + def get_serializer_class(self): + return super().get_serializer_class() + @swagger_auto_schema( responses={ 200: SuccessResponseSerializer(),