diff --git a/core/apps/projects/admin/project.py b/core/apps/projects/admin/project.py index 7939908..f8872ed 100644 --- a/core/apps/projects/admin/project.py +++ b/core/apps/projects/admin/project.py @@ -1,6 +1,6 @@ from django.contrib import admin -from core.apps.projects.models.project import ProjectDepartment, Project +from core.apps.projects.models.project import ProjectDepartment, Project, ProjectFolder class ProjectDepartmentInline(admin.TabularInline): @@ -18,4 +18,10 @@ class ProjectAdmin(admin.ModelAdmin): @admin.register(ProjectDepartment) class ProjectDepartmentAdmin(admin.ModelAdmin): list_display = ['name', 'project'] + search_fields = ['name'] + + +@admin.register(ProjectFolder) +class ProjectFolderAdmin(admin.ModelAdmin): + list_display = ['id', 'name'] search_fields = ['name'] \ No newline at end of file diff --git a/core/apps/projects/migrations/0002_projectfolder_project_folder.py b/core/apps/projects/migrations/0002_projectfolder_project_folder.py new file mode 100644 index 0000000..5255313 --- /dev/null +++ b/core/apps/projects/migrations/0002_projectfolder_project_folder.py @@ -0,0 +1,33 @@ +# Generated by Django 5.2.4 on 2025-08-04 10:23 + +import django.db.models.deletion +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='ProjectFolder', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('name', models.CharField(max_length=200)), + ], + options={ + 'verbose_name': 'Loyiha papkasi', + 'verbose_name_plural': 'Loyiha papkalari', + }, + ), + migrations.AddField( + model_name='project', + name='folder', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='projects.projectfolder'), + ), + ] diff --git a/core/apps/projects/migrations/0003_alter_project_folder.py b/core/apps/projects/migrations/0003_alter_project_folder.py new file mode 100644 index 0000000..b2e87d4 --- /dev/null +++ b/core/apps/projects/migrations/0003_alter_project_folder.py @@ -0,0 +1,19 @@ +# Generated by Django 5.2.4 on 2025-08-04 10:27 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0002_projectfolder_project_folder'), + ] + + operations = [ + migrations.AlterField( + model_name='project', + name='folder', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='projects', to='projects.projectfolder'), + ), + ] diff --git a/core/apps/projects/models/project.py b/core/apps/projects/models/project.py index 77ad2c2..75f3583 100644 --- a/core/apps/projects/models/project.py +++ b/core/apps/projects/models/project.py @@ -4,11 +4,25 @@ from django.utils.translation import gettext_lazy as _ from core.apps.shared.models import BaseModel +class ProjectFolder(BaseModel): + name = models.CharField(max_length=200) + + def __str__(self): + return self.name + + class Meta: + verbose_name = _('Loyiha papkasi') + verbose_name_plural = _('Loyiha papkalari') + + class Project(BaseModel): name = models.CharField(max_length=200) location = models.CharField(max_length=200) start_date = models.DateField() end_date = models.DateField() + folder = models.ForeignKey( + ProjectFolder, on_delete=models.SET_NULL, null=True, blank=True, related_name='projects' + ) def __str__(self): return self.name diff --git a/core/apps/projects/serializers/project.py b/core/apps/projects/serializers/project.py index e238e48..676f5c2 100644 --- a/core/apps/projects/serializers/project.py +++ b/core/apps/projects/serializers/project.py @@ -1,6 +1,8 @@ +from django.db import transaction + from rest_framework import serializers -from core.apps.projects.models.project import Project, ProjectDepartment +from core.apps.projects.models.project import Project, ProjectDepartment, ProjectFolder class ProjectDepartmentListSerializer(serializers.ModelSerializer): @@ -26,4 +28,65 @@ class ProjectDetailSerialzier(serializers.ModelSerializer): model = Project fields = [ 'id', 'name', 'location', 'start_date', 'end_date', 'project_departments' - ] \ No newline at end of file + ] + + +class ProjectCreateSerializer(serializers.ModelSerializer): + location = serializers.CharField() + start_date = serializers.DateField() + end_date = serializers.DateField() + name = serializers.CharField() + + def create(self, validated_data): + with transaction.atomic(): + return Project.objects.create( + name=validated_data.get('name'), + start_date=validated_data.get('start_date'), + end_date=validated_data.get('end_date'), + location=validated_data.get('location') + ) + + +class ProjectFolderCreateSerializer(serializers.Serializer): + name = serializers.CharField() + + def create(self, validated_data): + with transaction.atomic(): + folder = ProjectFolder.objects.create( + name=validated_data.get('name') + ) + return folder + + +class ProjectFolderListSerializer(serializers.ModelSerializer): + projects = ProjectListSerializer(many=True) + + class Meta: + model = ProjectFolder + fields = ['id', 'name', 'projects'] + + +class ProjectFolderProjectCreateSerializer(serializers.Serializer): + folder_id = serializers.UUIDField() + name = serializers.CharField() + location = serializers.CharField() + start_date = serializers.DateField() + end_date = serializers.DateField() + + def validate(self, data): + folder = ProjectFolder.objects.filter(id=data['folder_id']).first() + if not folder: + raise serializers.ValidationError("Folder not found") + data['folder'] = folder + return data + + def create(self, validated_data): + with transaction.atomic(): + return Project.objects.create( + name=validated_data.get('name'), + folder=validated_data.get('folder'), + location=validated_data.get('location'), + start_date=validated_data.get('start_date'), + end_date=validated_data.get('end_date') + ) + diff --git a/core/apps/projects/urls.py b/core/apps/projects/urls.py index 4baf941..c65df40 100644 --- a/core/apps/projects/urls.py +++ b/core/apps/projects/urls.py @@ -7,6 +7,14 @@ urlpatterns = [ [ path('list/', project_views.ProjectListApiView.as_view()), path('/', project_views.ProjectDetailApiView.as_view()), + path('create/', project_views.ProjectCreateApiView.as_view()), + ] + )), + path('project_folder/', include( + [ + path('create/', project_views.ProjectFolderCreateApiView.as_view()), + path('list/', project_views.ProjectFolderListApiView.as_view()), + path('create/project/', project_views.ProjectFolderCreateProjectApiView.as_view()), ] )) ] \ No newline at end of file diff --git a/core/apps/projects/views/project.py b/core/apps/projects/views/project.py index 8a7d538..f5c529a 100644 --- a/core/apps/projects/views/project.py +++ b/core/apps/projects/views/project.py @@ -1,7 +1,7 @@ from rest_framework import generics, status from rest_framework.response import Response -from core.apps.projects.models.project import Project, ProjectDepartment +from core.apps.projects.models.project import Project, ProjectDepartment, ProjectFolder from core.apps.projects.serializers import project as serializers from core.apps.accounts.permissions.permissions import HasRolePermission from core.apps.shared.paginations.custom import CustomPageNumberPagination @@ -20,4 +20,34 @@ class ProjectDetailApiView(generics.RetrieveAPIView): queryset = Project.objects.prefetch_related('project_departments') permission_classes = [HasRolePermission] required_permissions = [] - lookup_field = 'id' \ No newline at end of file + lookup_field = 'id' + + +class ProjectCreateApiView(generics.CreateAPIView): + serializer_class = serializers.ProjectCreateSerializer + queryset = Project.objects.all() + permission_classes = [HasRolePermission] + required_permissions = [] + + +# Project Folder +class ProjectFolderCreateApiView(generics.CreateAPIView): + serializer_class = serializers.ProjectFolderCreateSerializer + queryset = ProjectFolder.objects.all() + permission_classes = [HasRolePermission] + required_permissions = [] + + +class ProjectFolderListApiView(generics.ListAPIView): + serializer_class = serializers.ProjectFolderListSerializer + queryset = ProjectFolder.objects.prefetch_related('projects') + permission_classes = [HasRolePermission] + required_permissions = [] + pagination_class = CustomPageNumberPagination + + +class ProjectFolderCreateProjectApiView(generics.CreateAPIView): + serializer_class = serializers.ProjectFolderProjectCreateSerializer + queryset = Project.objects.all() + permission_classes = [HasRolePermission] + required_permissions = [] \ No newline at end of file