From 7a2ea48a8e443bf54bd41ee35416901fb3eece95 Mon Sep 17 00:00:00 2001 From: muhammadvadud Date: Sat, 20 Sep 2025 13:06:19 +0500 Subject: [PATCH] Modellarga o'zgartirish kiritildi va filters qo'shildi --- .../serializers/participant/participant.py | 2 - core/apps/blog/serializers/post/post.py | 4 +- core/apps/tickets/admin/__init__.py | 1 + core/apps/tickets/admin/badge.py | 12 +++++ core/apps/tickets/admin/hotel.py | 10 +++- core/apps/tickets/filters/__init__.py | 1 + core/apps/tickets/filters/badge.py | 13 +++++ core/apps/tickets/filters/tickets.py | 50 +++++++++++++++---- core/apps/tickets/forms/__init__.py | 1 + core/apps/tickets/forms/badge.py | 10 ++++ ...emodel_alter_ticketsmodel_slug_and_more.py | 38 ++++++++++++++ .../0003_ticketsmodel_visa_required.py | 19 +++++++ .../migrations/0004_hotelmodel_meal_plan.py | 18 +++++++ ...05_hoteltypemodel_hotelmodel_hotel_type.py | 30 +++++++++++ core/apps/tickets/models/__init__.py | 3 +- core/apps/tickets/models/badge.py | 34 +++++++++++++ core/apps/tickets/models/hotel.py | 28 +++++++++++ core/apps/tickets/models/tickets.py | 9 +++- core/apps/tickets/permissions/__init__.py | 1 + core/apps/tickets/permissions/badge.py | 12 +++++ core/apps/tickets/serializers/__init__.py | 1 + .../tickets/serializers/badge/__init__.py | 1 + core/apps/tickets/serializers/badge/badge.py | 29 +++++++++++ .../serializers/tickets/ticketorder.py | 2 - .../tickets/serializers/tickets/tickets.py | 32 +++++++++++- core/apps/tickets/signals/__init__.py | 1 + core/apps/tickets/signals/badge.py | 8 +++ core/apps/tickets/tests/__init__.py | 1 + core/apps/tickets/tests/test_badge.py | 47 +++++++++++++++++ .../apps/tickets/tests/test_extra_services.py | 6 +-- core/apps/tickets/translation/__init__.py | 1 + core/apps/tickets/translation/badge.py | 8 +++ core/apps/tickets/urls.py | 3 +- core/apps/tickets/validators/__init__.py | 1 + core/apps/tickets/validators/badge.py | 8 +++ core/apps/tickets/views/__init__.py | 1 + core/apps/tickets/views/badge.py | 21 ++++++++ core/apps/tickets/views/extra_services.py | 2 +- core/apps/tickets/views/tickets.py | 6 ++- 39 files changed, 446 insertions(+), 29 deletions(-) create mode 100644 core/apps/tickets/admin/badge.py create mode 100644 core/apps/tickets/filters/badge.py create mode 100644 core/apps/tickets/forms/badge.py create mode 100644 core/apps/tickets/migrations/0002_badgemodel_alter_ticketsmodel_slug_and_more.py create mode 100644 core/apps/tickets/migrations/0003_ticketsmodel_visa_required.py create mode 100644 core/apps/tickets/migrations/0004_hotelmodel_meal_plan.py create mode 100644 core/apps/tickets/migrations/0005_hoteltypemodel_hotelmodel_hotel_type.py create mode 100644 core/apps/tickets/models/badge.py create mode 100644 core/apps/tickets/permissions/badge.py create mode 100644 core/apps/tickets/serializers/badge/__init__.py create mode 100644 core/apps/tickets/serializers/badge/badge.py create mode 100644 core/apps/tickets/signals/badge.py create mode 100644 core/apps/tickets/tests/test_badge.py create mode 100644 core/apps/tickets/translation/badge.py create mode 100644 core/apps/tickets/validators/badge.py create mode 100644 core/apps/tickets/views/badge.py diff --git a/core/apps/accounts/serializers/participant/participant.py b/core/apps/accounts/serializers/participant/participant.py index f0cfd67..56ae697 100644 --- a/core/apps/accounts/serializers/participant/participant.py +++ b/core/apps/accounts/serializers/participant/participant.py @@ -8,7 +8,6 @@ class BaseParticipantSerializer(serializers.ModelSerializer): model = ParticipantModel fields = [ "id", - "name", ] @@ -24,5 +23,4 @@ class CreateParticipantSerializer(BaseParticipantSerializer): class Meta(BaseParticipantSerializer.Meta): fields = [ "id", - "name", ] diff --git a/core/apps/blog/serializers/post/post.py b/core/apps/blog/serializers/post/post.py index 9630ebe..f20c046 100644 --- a/core/apps/blog/serializers/post/post.py +++ b/core/apps/blog/serializers/post/post.py @@ -7,7 +7,7 @@ class BasePostSerializer(serializers.ModelSerializer): model = PostModel fields = [ "id", - "name", + "title", ] @@ -24,6 +24,6 @@ class CreatePostSerializer(BasePostSerializer): class Meta(BasePostSerializer.Meta): fields = [ "id", - "name", + "title", ] diff --git a/core/apps/tickets/admin/__init__.py b/core/apps/tickets/admin/__init__.py index a9ccb1e..90c5d47 100644 --- a/core/apps/tickets/admin/__init__.py +++ b/core/apps/tickets/admin/__init__.py @@ -1,3 +1,4 @@ +from .badge import * # noqa from .extra_services import * # noqa from .hotel import * # noqa from .tariff import * # noqa diff --git a/core/apps/tickets/admin/badge.py b/core/apps/tickets/admin/badge.py new file mode 100644 index 0000000..0b16697 --- /dev/null +++ b/core/apps/tickets/admin/badge.py @@ -0,0 +1,12 @@ +from django.contrib import admin +from unfold.admin import ModelAdmin + +from core.apps.tickets.models import BadgeModel + + +@admin.register(BadgeModel) +class BadgeAdmin(ModelAdmin): + list_display = ( + "id", + "__str__", + ) diff --git a/core/apps/tickets/admin/hotel.py b/core/apps/tickets/admin/hotel.py index e684bee..593e7d1 100644 --- a/core/apps/tickets/admin/hotel.py +++ b/core/apps/tickets/admin/hotel.py @@ -1,7 +1,7 @@ from django.contrib import admin from unfold.admin import ModelAdmin -from core.apps.tickets.models import HotelModel, HotelImagesModel +from core.apps.tickets.models import HotelModel, HotelImagesModel, HotelTypeModel class HotelImagesInline(admin.TabularInline): @@ -18,3 +18,11 @@ class HotelAdmin(ModelAdmin): inlines = ( HotelImagesInline, ) + + +@admin.register(HotelTypeModel) +class HotelTypeModelAdmin(ModelAdmin): + list_display = ( + "id", + "__str__", + ) diff --git a/core/apps/tickets/filters/__init__.py b/core/apps/tickets/filters/__init__.py index a9ccb1e..90c5d47 100644 --- a/core/apps/tickets/filters/__init__.py +++ b/core/apps/tickets/filters/__init__.py @@ -1,3 +1,4 @@ +from .badge import * # noqa from .extra_services import * # noqa from .hotel import * # noqa from .tariff import * # noqa diff --git a/core/apps/tickets/filters/badge.py b/core/apps/tickets/filters/badge.py new file mode 100644 index 0000000..17c08cd --- /dev/null +++ b/core/apps/tickets/filters/badge.py @@ -0,0 +1,13 @@ +from django_filters import rest_framework as filters + +from core.apps.tickets.models import BadgeModel + + +class BadgeFilter(filters.FilterSet): + # name = filters.CharFilter(field_name="name", lookup_expr="icontains") + + class Meta: + model = BadgeModel + fields = [ + "name", + ] diff --git a/core/apps/tickets/filters/tickets.py b/core/apps/tickets/filters/tickets.py index ceaf113..3ecb3fb 100644 --- a/core/apps/tickets/filters/tickets.py +++ b/core/apps/tickets/filters/tickets.py @@ -1,23 +1,51 @@ from django_filters import rest_framework as filters - -from core.apps.tickets.models import TicketorderModel, TicketsModel +from core.apps.tickets.models import TicketsModel class TicketsFilter(filters.FilterSet): - # name = filters.CharFilter(field_name="name", lookup_expr="icontains") + title = filters.CharFilter(field_name="title", lookup_expr="icontains") + destinations = filters.CharFilter(field_name="ticket_itinerary__ticket_itinerary_destinations__name", + lookup_expr="icontains") + min_price = filters.NumberFilter(field_name="price", lookup_expr="gte") + max_price = filters.NumberFilter(field_name="price", lookup_expr="lte") + cheapest = filters.BooleanFilter(method="filter_cheapest") + most_expensive = filters.BooleanFilter(method="filter_most_expensive") + visa_required = filters.BooleanFilter(method="filter_visa_required") + duration_days = filters.NumberFilter(field_name="duration_days", lookup_expr="exact") + hotel_rating = filters.NumberFilter(field_name="ticket_hotel__rating", lookup_expr="exact") + meal_plan = filters.CharFilter(field_name="ticket_hotel__meal_plan", lookup_expr="icontains") + hotel_type = filters.CharFilter(field_name="ticket_hotel__hotel_type__name", lookup_expr="icontains") + ticket_amenities = filters.CharFilter(field_name="ticket_amenities__name", lookup_expr="icontains") class Meta: model = TicketsModel fields = [ - "name", + "title", + "min_price", + "max_price", + "visa_required", + "duration_days", + "destinations", + "hotel_rating", + "hotel_type", + "ticket_amenities", ] + def filter_cheapest(self, queryset, name, value): + if value: + return queryset.order_by("price") + return queryset -class TicketorderFilter(filters.FilterSet): - # name = filters.CharFilter(field_name="name", lookup_expr="icontains") + def filter_most_expensive(self, queryset, name, value): + if value: + return queryset.order_by("-price") + return queryset - class Meta: - model = TicketorderModel - fields = [ - "name", - ] + def filter_visa_required(self, queryset, name, value): + if value: + visa_required = queryset.filter(visa_required=value) + return visa_required + elif value is False: + visa_required = queryset.filter(visa_required=value) + return visa_required + return queryset diff --git a/core/apps/tickets/forms/__init__.py b/core/apps/tickets/forms/__init__.py index a9ccb1e..90c5d47 100644 --- a/core/apps/tickets/forms/__init__.py +++ b/core/apps/tickets/forms/__init__.py @@ -1,3 +1,4 @@ +from .badge import * # noqa from .extra_services import * # noqa from .hotel import * # noqa from .tariff import * # noqa diff --git a/core/apps/tickets/forms/badge.py b/core/apps/tickets/forms/badge.py new file mode 100644 index 0000000..a02889b --- /dev/null +++ b/core/apps/tickets/forms/badge.py @@ -0,0 +1,10 @@ +from django import forms + +from core.apps.tickets.models import BadgeModel + + +class BadgeForm(forms.ModelForm): + + class Meta: + model = BadgeModel + fields = "__all__" diff --git a/core/apps/tickets/migrations/0002_badgemodel_alter_ticketsmodel_slug_and_more.py b/core/apps/tickets/migrations/0002_badgemodel_alter_ticketsmodel_slug_and_more.py new file mode 100644 index 0000000..2a74915 --- /dev/null +++ b/core/apps/tickets/migrations/0002_badgemodel_alter_ticketsmodel_slug_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 5.1.3 on 2025-09-19 11:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tickets', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='BadgeModel', + 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='badge name')), + ('color', models.CharField(choices=[('red', 'red'), ('green', 'green'), ('blue', 'blue'), ('yellow', 'yellow'), ('orange', 'orange'), ('purple', 'purple'), ('black', 'black'), ('white', 'white'), ('gray', 'gray')], default='red', max_length=255, verbose_name='badge color')), + ], + options={ + 'verbose_name': 'BadgeModel', + 'verbose_name_plural': 'BadgeModels', + 'db_table': 'badge', + }, + ), + migrations.AlterField( + model_name='ticketsmodel', + name='slug', + field=models.SlugField(blank=True, max_length=255, null=True, unique=True, verbose_name='slug'), + ), + migrations.AddField( + model_name='ticketsmodel', + name='badge', + field=models.ManyToManyField(blank=True, null=True, to='tickets.badgemodel', verbose_name='badge'), + ), + ] diff --git a/core/apps/tickets/migrations/0003_ticketsmodel_visa_required.py b/core/apps/tickets/migrations/0003_ticketsmodel_visa_required.py new file mode 100644 index 0000000..d6bf403 --- /dev/null +++ b/core/apps/tickets/migrations/0003_ticketsmodel_visa_required.py @@ -0,0 +1,19 @@ +# Generated by Django 5.1.3 on 2025-09-20 07:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tickets', '0002_badgemodel_alter_ticketsmodel_slug_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='ticketsmodel', + name='visa_required', + field=models.BooleanField(default=True, verbose_name='visa required'), + preserve_default=False, + ), + ] diff --git a/core/apps/tickets/migrations/0004_hotelmodel_meal_plan.py b/core/apps/tickets/migrations/0004_hotelmodel_meal_plan.py new file mode 100644 index 0000000..28f73fd --- /dev/null +++ b/core/apps/tickets/migrations/0004_hotelmodel_meal_plan.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.3 on 2025-09-20 07:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tickets', '0003_ticketsmodel_visa_required'), + ] + + operations = [ + migrations.AddField( + model_name='hotelmodel', + name='meal_plan', + field=models.CharField(choices=[('all_inclusive', 'All Inclusive'), ('breakfast', 'Breakfast Only'), ('half_board', 'Half Board'), ('full_board', 'Full Board')], default='breakfast', max_length=255, verbose_name='meal plan'), + ), + ] diff --git a/core/apps/tickets/migrations/0005_hoteltypemodel_hotelmodel_hotel_type.py b/core/apps/tickets/migrations/0005_hoteltypemodel_hotelmodel_hotel_type.py new file mode 100644 index 0000000..3c6c9cc --- /dev/null +++ b/core/apps/tickets/migrations/0005_hoteltypemodel_hotelmodel_hotel_type.py @@ -0,0 +1,30 @@ +# Generated by Django 5.1.3 on 2025-09-20 07:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tickets', '0004_hotelmodel_meal_plan'), + ] + + operations = [ + migrations.CreateModel( + name='HotelTypeModel', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, verbose_name='name')), + ], + options={ + 'verbose_name': 'HotelTypeModel', + 'verbose_name_plural': 'HotelTypeModels', + 'db_table': 'hotel_types', + }, + ), + migrations.AddField( + model_name='hotelmodel', + name='hotel_type', + field=models.ManyToManyField(to='tickets.hoteltypemodel', verbose_name='hotel type'), + ), + ] diff --git a/core/apps/tickets/models/__init__.py b/core/apps/tickets/models/__init__.py index 78aded8..90c5d47 100644 --- a/core/apps/tickets/models/__init__.py +++ b/core/apps/tickets/models/__init__.py @@ -1,4 +1,5 @@ +from .badge import * # noqa from .extra_services import * # noqa from .hotel import * # noqa from .tariff import * # noqa -from .tickets import * # noqa \ No newline at end of file +from .tickets import * # noqa diff --git a/core/apps/tickets/models/badge.py b/core/apps/tickets/models/badge.py new file mode 100644 index 0000000..2892bb0 --- /dev/null +++ b/core/apps/tickets/models/badge.py @@ -0,0 +1,34 @@ +from django.db import models +from django.utils.translation import gettext_lazy as _ +from django_core.models import AbstractBaseModel + + +class BadgeModel(AbstractBaseModel): + Color_Choice = ( + ("red", "red"), + ("green", "green"), + ("blue", "blue"), + ("yellow", "yellow"), + ("orange", "orange"), + ("purple", "purple"), + ("black", "black"), + ("white", "white"), + ("gray", "gray"), + ) + + name = models.CharField(max_length=255, verbose_name=_("badge name")) + color = models.CharField(max_length=255, choices=Color_Choice, verbose_name=_("badge color"), default="red") + + def __str__(self): + return str(self.pk) + + @classmethod + def _create_fake(self): + return self.objects.create( + name="mock", + ) + + class Meta: + db_table = "badge" + verbose_name = _("BadgeModel") + verbose_name_plural = _("BadgeModels") diff --git a/core/apps/tickets/models/hotel.py b/core/apps/tickets/models/hotel.py index b7d6a25..052550e 100644 --- a/core/apps/tickets/models/hotel.py +++ b/core/apps/tickets/models/hotel.py @@ -4,7 +4,32 @@ from django_core.models import AbstractBaseModel from .tickets import TicketsModel +class HotelTypeModel(models.Model): + name = models.CharField(verbose_name=_("name"), max_length=255) + + def __str__(self): + return str(self.pk) + + @classmethod + def _create_fake(self): + return self.objects.create( + name="mock", + ) + + class Meta: + db_table = "hotel_types" + verbose_name = _("HotelTypeModel") + verbose_name_plural = _("HotelTypeModels") + + class HotelModel(AbstractBaseModel): + MEAL_PLAN_CHOICES = [ + ("all_inclusive", "All Inclusive"), + ("breakfast", "Breakfast Only"), + ("half_board", "Half Board"), + ("full_board", "Full Board"), + ] + ticket = models.ForeignKey(TicketsModel, related_name="ticket_hotel", verbose_name=_("ticket"), on_delete=models.CASCADE) name = models.CharField(verbose_name=_("name"), max_length=255) @@ -15,6 +40,9 @@ class HotelModel(AbstractBaseModel): phone = models.CharField(verbose_name=_("phone number"), max_length=50, blank=True, null=True) website = models.URLField(verbose_name=_("hotel website"), blank=True, null=True) rating = models.FloatField(verbose_name=_("rating"), blank=True, null=True) + meal_plan = models.CharField(verbose_name=_("meal plan"), choices=MEAL_PLAN_CHOICES, max_length=255, + default="breakfast") + hotel_type = models.ManyToManyField(HotelTypeModel, verbose_name=_("hotel type")) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) diff --git a/core/apps/tickets/models/tickets.py b/core/apps/tickets/models/tickets.py index be23254..b41f8fa 100644 --- a/core/apps/tickets/models/tickets.py +++ b/core/apps/tickets/models/tickets.py @@ -4,7 +4,6 @@ from django_core.models import AbstractBaseModel from core.apps.accounts.models import User from core.apps.accounts.models.participant import ParticipantModel - from .tariff import TariffModel from django.utils.text import slugify @@ -29,7 +28,9 @@ class TicketsModel(AbstractBaseModel): duration_days = models.IntegerField(verbose_name=_("duration days")) hotel_meals = models.TextField(verbose_name=_("hotel meals"), null=True, blank=True) tariff = models.ManyToManyField(TariffModel, related_name="ticket_tariffs", verbose_name=_("tariff")) - slug = models.SlugField(verbose_name=_("slug"), max_length=255, unique=True) + slug = models.SlugField(verbose_name=_("slug"), max_length=255, unique=True, null=True, blank=True) + badge = models.ManyToManyField("tickets.BadgeModel", verbose_name=_("badge"), null=True, blank=True) + visa_required = models.BooleanField(verbose_name=_("visa required")) created_at = models.DateTimeField(verbose_name=_("created at"), auto_now_add=True) updated_at = models.DateTimeField(verbose_name=_("updated at"), auto_now=True) @@ -43,6 +44,8 @@ class TicketsModel(AbstractBaseModel): @classmethod def _create_fake(self): + from core.apps.tickets.models.badge import BadgeModel + return self.objects.create( name="mock", price=150000, @@ -53,6 +56,7 @@ class TicketsModel(AbstractBaseModel): rating=4.5, hotel_info="mock", duration_days=15, + badge=BadgeModel._create_fake(), ) class Meta: @@ -301,6 +305,7 @@ class TicketorderModel(AbstractBaseModel): @classmethod def _create_fake(self): + from core.apps.tickets.models.extra_services import ExtraServicesModel, PaidServicesModel return self.objects.create( user=User._create_fake(), departure="mock", diff --git a/core/apps/tickets/permissions/__init__.py b/core/apps/tickets/permissions/__init__.py index a9ccb1e..90c5d47 100644 --- a/core/apps/tickets/permissions/__init__.py +++ b/core/apps/tickets/permissions/__init__.py @@ -1,3 +1,4 @@ +from .badge import * # noqa from .extra_services import * # noqa from .hotel import * # noqa from .tariff import * # noqa diff --git a/core/apps/tickets/permissions/badge.py b/core/apps/tickets/permissions/badge.py new file mode 100644 index 0000000..d036bca --- /dev/null +++ b/core/apps/tickets/permissions/badge.py @@ -0,0 +1,12 @@ +from rest_framework import permissions + + +class BadgePermission(permissions.BasePermission): + + def __init__(self) -> None: ... + + def __call__(self, *args, **kwargs): + return self + + def has_permission(self, request, view): + return True diff --git a/core/apps/tickets/serializers/__init__.py b/core/apps/tickets/serializers/__init__.py index a9ccb1e..90c5d47 100644 --- a/core/apps/tickets/serializers/__init__.py +++ b/core/apps/tickets/serializers/__init__.py @@ -1,3 +1,4 @@ +from .badge import * # noqa from .extra_services import * # noqa from .hotel import * # noqa from .tariff import * # noqa diff --git a/core/apps/tickets/serializers/badge/__init__.py b/core/apps/tickets/serializers/badge/__init__.py new file mode 100644 index 0000000..9b32903 --- /dev/null +++ b/core/apps/tickets/serializers/badge/__init__.py @@ -0,0 +1 @@ +from .badge import * # noqa diff --git a/core/apps/tickets/serializers/badge/badge.py b/core/apps/tickets/serializers/badge/badge.py new file mode 100644 index 0000000..60fa1b7 --- /dev/null +++ b/core/apps/tickets/serializers/badge/badge.py @@ -0,0 +1,29 @@ +from rest_framework import serializers + +from core.apps.tickets.models import BadgeModel + + +class BaseBadgeSerializer(serializers.ModelSerializer): + class Meta: + model = BadgeModel + fields = [ + "id", + "name", + "color", + ] + + +class ListBadgeSerializer(BaseBadgeSerializer): + class Meta(BaseBadgeSerializer.Meta): ... + + +class RetrieveBadgeSerializer(BaseBadgeSerializer): + class Meta(BaseBadgeSerializer.Meta): ... + + +class CreateBadgeSerializer(BaseBadgeSerializer): + class Meta(BaseBadgeSerializer.Meta): + fields = [ + "id", + "name", + ] diff --git a/core/apps/tickets/serializers/tickets/ticketorder.py b/core/apps/tickets/serializers/tickets/ticketorder.py index e0943b5..5e598c0 100644 --- a/core/apps/tickets/serializers/tickets/ticketorder.py +++ b/core/apps/tickets/serializers/tickets/ticketorder.py @@ -8,7 +8,6 @@ class BaseTicketorderSerializer(serializers.ModelSerializer): model = TicketorderModel fields = [ "id", - "name", ] @@ -24,5 +23,4 @@ class CreateTicketorderSerializer(BaseTicketorderSerializer): class Meta(BaseTicketorderSerializer.Meta): fields = [ "id", - "name", ] diff --git a/core/apps/tickets/serializers/tickets/tickets.py b/core/apps/tickets/serializers/tickets/tickets.py index 560a90a..aa67b38 100644 --- a/core/apps/tickets/serializers/tickets/tickets.py +++ b/core/apps/tickets/serializers/tickets/tickets.py @@ -3,9 +3,10 @@ from core.apps.tickets.models import TicketsModel, TicketsImagesModel, TicketsAm TicketsIncludedServicesModel, TicketsItineraryModel, TicketsItineraryImagesModel, TicketsItineraryDestinationsModel, \ TicketsHotelMealsModel, TicketsCommentsModel from core.apps.accounts.models import User - from core.apps.accounts.serializers.user import UserSerializer from core.apps.tickets.models.tariff import TariffModel +from core.apps.tickets.serializers.badge.badge import ListBadgeSerializer + class TicketsTariffSerializer(serializers.ModelSerializer): @@ -108,7 +109,34 @@ class BaseTicketsSerializer(serializers.ModelSerializer): class ListTicketsSerializer(BaseTicketsSerializer): - class Meta(BaseTicketsSerializer.Meta): ... + ticket_images = serializers.SerializerMethodField() + ticket_amenities = TicketsAmenitiesSerializer(many=True, read_only=True) + badge = ListBadgeSerializer(many=True, read_only=True) + + class Meta: + model = TicketsModel + fields = [ + "id", + "title", + "price", + "departure_date", + "departure", + "passenger_count", + "rating", + "duration_days", + "destination", + "ticket_images", + "ticket_amenities", + "passenger_count", + "badge", + "visa_required" + ] + + def get_ticket_images(self, obj): + image = obj.ticket_images.first() + if image: + return TicketsImageSerializer(image).data + return None class RetrieveTicketsSerializer(BaseTicketsSerializer): diff --git a/core/apps/tickets/signals/__init__.py b/core/apps/tickets/signals/__init__.py index a9ccb1e..90c5d47 100644 --- a/core/apps/tickets/signals/__init__.py +++ b/core/apps/tickets/signals/__init__.py @@ -1,3 +1,4 @@ +from .badge import * # noqa from .extra_services import * # noqa from .hotel import * # noqa from .tariff import * # noqa diff --git a/core/apps/tickets/signals/badge.py b/core/apps/tickets/signals/badge.py new file mode 100644 index 0000000..f271d4c --- /dev/null +++ b/core/apps/tickets/signals/badge.py @@ -0,0 +1,8 @@ +from django.db.models.signals import post_save +from django.dispatch import receiver + +from core.apps.tickets.models import BadgeModel + + +@receiver(post_save, sender=BadgeModel) +def BadgeSignal(sender, instance, created, **kwargs): ... diff --git a/core/apps/tickets/tests/__init__.py b/core/apps/tickets/tests/__init__.py index 4f4ee37..9d82c14 100644 --- a/core/apps/tickets/tests/__init__.py +++ b/core/apps/tickets/tests/__init__.py @@ -1,3 +1,4 @@ +from .test_badge import * # noqa from .test_extra_services import * # noqa from .test_hotel import * # noqa from .test_paid_services import * # noqa diff --git a/core/apps/tickets/tests/test_badge.py b/core/apps/tickets/tests/test_badge.py new file mode 100644 index 0000000..1f0b654 --- /dev/null +++ b/core/apps/tickets/tests/test_badge.py @@ -0,0 +1,47 @@ +from django.test import TestCase +from django.urls import reverse +from rest_framework.test import APIClient + +from core.apps.tickets.models import BadgeModel + + +class BadgeTest(TestCase): + + def _create_data(self): + return BadgeModel._create_fake() + + def setUp(self): + self.client = APIClient() + self.instance = self._create_data() + self.urls = { + "list": reverse("badge-list"), + "retrieve": reverse("badge-detail", kwargs={"pk": self.instance.pk}), + "retrieve-not-found": reverse("badge-detail", kwargs={"pk": 1000}), + } + + def test_create(self): + self.assertTrue(True) + + def test_update(self): + self.assertTrue(True) + + def test_partial_update(self): + self.assertTrue(True) + + def test_destroy(self): + self.assertTrue(True) + + def test_list(self): + response = self.client.get(self.urls["list"]) + self.assertTrue(response.json()["status"]) + self.assertEqual(response.status_code, 200) + + def test_retrieve(self): + response = self.client.get(self.urls["retrieve"]) + self.assertTrue(response.json()["status"]) + self.assertEqual(response.status_code, 200) + + def test_retrieve_not_found(self): + response = self.client.get(self.urls["retrieve-not-found"]) + self.assertFalse(response.json()["status"]) + self.assertEqual(response.status_code, 404) diff --git a/core/apps/tickets/tests/test_extra_services.py b/core/apps/tickets/tests/test_extra_services.py index bc72990..b349021 100644 --- a/core/apps/tickets/tests/test_extra_services.py +++ b/core/apps/tickets/tests/test_extra_services.py @@ -14,9 +14,9 @@ class ExtraServicesTest(TestCase): self.client = APIClient() self.instance = self._create_data() self.urls = { - "list": reverse("extra_servoces-list"), - "retrieve": reverse("extra_servoces-detail", kwargs={"pk": self.instance.pk}), - "retrieve-not-found": reverse("extra_servoces-detail", kwargs={"pk": 1000}), + "list": reverse("extra_services-list"), + "retrieve": reverse("extra_services-detail", kwargs={"pk": self.instance.pk}), + "retrieve-not-found": reverse("extra_services-detail", kwargs={"pk": 1000}), } def test_create(self): diff --git a/core/apps/tickets/translation/__init__.py b/core/apps/tickets/translation/__init__.py index a9ccb1e..90c5d47 100644 --- a/core/apps/tickets/translation/__init__.py +++ b/core/apps/tickets/translation/__init__.py @@ -1,3 +1,4 @@ +from .badge import * # noqa from .extra_services import * # noqa from .hotel import * # noqa from .tariff import * # noqa diff --git a/core/apps/tickets/translation/badge.py b/core/apps/tickets/translation/badge.py new file mode 100644 index 0000000..275cb28 --- /dev/null +++ b/core/apps/tickets/translation/badge.py @@ -0,0 +1,8 @@ +from modeltranslation.translator import TranslationOptions, register + +from core.apps.tickets.models import BadgeModel + + +@register(BadgeModel) +class BadgeTranslation(TranslationOptions): + fields = [] diff --git a/core/apps/tickets/urls.py b/core/apps/tickets/urls.py index 35d80a4..8163b0c 100644 --- a/core/apps/tickets/urls.py +++ b/core/apps/tickets/urls.py @@ -1,11 +1,12 @@ from django.urls import include, path from rest_framework.routers import DefaultRouter -from .views import ExtraServicesView, PaidServicesView, TariffView, TicketorderView +from .views import BadgeView, ExtraServicesView, PaidServicesView, TariffView, TicketorderView from .views.hotel import HotelView from .views.tickets import TicketsView router = DefaultRouter() +router.register("badge", BadgeView, basename="badge") router.register("ticketorder", TicketorderView, basename="ticketorder") router.register("paid_services", PaidServicesView, basename="paid_services") router.register("extra_services", ExtraServicesView, basename="extra_services") diff --git a/core/apps/tickets/validators/__init__.py b/core/apps/tickets/validators/__init__.py index a9ccb1e..90c5d47 100644 --- a/core/apps/tickets/validators/__init__.py +++ b/core/apps/tickets/validators/__init__.py @@ -1,3 +1,4 @@ +from .badge import * # noqa from .extra_services import * # noqa from .hotel import * # noqa from .tariff import * # noqa diff --git a/core/apps/tickets/validators/badge.py b/core/apps/tickets/validators/badge.py new file mode 100644 index 0000000..d21e58f --- /dev/null +++ b/core/apps/tickets/validators/badge.py @@ -0,0 +1,8 @@ +# from django.core.exceptions import ValidationError + + +class BadgeValidator: + def __init__(self): ... + + def __call__(self): + return True diff --git a/core/apps/tickets/views/__init__.py b/core/apps/tickets/views/__init__.py index a9ccb1e..90c5d47 100644 --- a/core/apps/tickets/views/__init__.py +++ b/core/apps/tickets/views/__init__.py @@ -1,3 +1,4 @@ +from .badge import * # noqa from .extra_services import * # noqa from .hotel import * # noqa from .tariff import * # noqa diff --git a/core/apps/tickets/views/badge.py b/core/apps/tickets/views/badge.py new file mode 100644 index 0000000..0d675fa --- /dev/null +++ b/core/apps/tickets/views/badge.py @@ -0,0 +1,21 @@ +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.tickets.models import BadgeModel +from core.apps.tickets.serializers.badge import CreateBadgeSerializer, ListBadgeSerializer, RetrieveBadgeSerializer + + +@extend_schema(tags=["badge"]) +class BadgeView(BaseViewSetMixin, ReadOnlyModelViewSet): + queryset = BadgeModel.objects.all() + serializer_class = ListBadgeSerializer + permission_classes = [AllowAny] + + action_permission_classes = {} + action_serializer_class = { + "list": ListBadgeSerializer, + "retrieve": RetrieveBadgeSerializer, + "create": CreateBadgeSerializer, + } diff --git a/core/apps/tickets/views/extra_services.py b/core/apps/tickets/views/extra_services.py index 312f4f7..6ef46c3 100644 --- a/core/apps/tickets/views/extra_services.py +++ b/core/apps/tickets/views/extra_services.py @@ -14,7 +14,7 @@ from core.apps.tickets.serializers.extra_services import ( ) -@extend_schema(tags=["extra_servoces"]) +@extend_schema(tags=["extra_services"]) class ExtraServicesView(BaseViewSetMixin, ReadOnlyModelViewSet): queryset = ExtraServicesModel.objects.all() serializer_class = ListExtraServicesSerializer diff --git a/core/apps/tickets/views/tickets.py b/core/apps/tickets/views/tickets.py index dccfdc5..a5fec1b 100644 --- a/core/apps/tickets/views/tickets.py +++ b/core/apps/tickets/views/tickets.py @@ -2,7 +2,9 @@ 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 django_filters.rest_framework import DjangoFilterBackend +from core.apps.tickets.filters import TicketsFilter from core.apps.tickets.models import TicketorderModel, TicketsModel from core.apps.tickets.serializers.tickets import ( CreateTicketorderSerializer, @@ -16,8 +18,10 @@ from core.apps.tickets.serializers.tickets import ( @extend_schema(tags=["tickets"]) class TicketsView(BaseViewSetMixin, ReadOnlyModelViewSet): - queryset = TicketsModel.objects.all() + queryset = TicketsModel.objects.all().order_by("-id") serializer_class = ListTicketsSerializer + filterset_class = TicketsFilter + filter_backends = [DjangoFilterBackend] permission_classes = [AllowAny] action_permission_classes = {}