diff --git a/.gitignore b/.gitignore index a0a2867..da7f4a7 100644 --- a/.gitignore +++ b/.gitignore @@ -330,4 +330,4 @@ passfinder/media/ .ipython/ .env -.idea +.idea \ No newline at end of file diff --git a/config/api_router.py b/config/api_router.py index 87ceaee..fb5f751 100644 --- a/config/api_router.py +++ b/config/api_router.py @@ -1,2 +1,10 @@ +from rest_framework.routers import DefaultRouter +from passfinder.recomendations.api.views import TinderView + + +router = DefaultRouter() + +router.register('tinder', TinderView) + app_name = "api" -urlpatterns = [] +urlpatterns = router.urls \ No newline at end of file diff --git a/config/settings/base.py b/config/settings/base.py index 3a71e7a..6faa9eb 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -39,7 +39,7 @@ # DATABASES # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#databases -DATABASES = {"default": env.db("DATABASE_URL")} +DATABASES = {"default": env.db("DATABASE_URL", "postgres://postgres:Ilvas2006@localhost:5432/passfinder")} DATABASES["default"]["ATOMIC_REQUESTS"] = True # https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-DEFAULT_AUTO_FIELD DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" @@ -77,6 +77,7 @@ LOCAL_APPS = [ "passfinder.users", "passfinder.events", + "passfinder.recomendations" ] # https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS @@ -284,9 +285,9 @@ # https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-timezone CELERY_TIMEZONE = TIME_ZONE # https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-broker_url -CELERY_BROKER_URL = env("CELERY_BROKER_URL") +#CELERY_BROKER_URL = env("CELERY_BROKER_URL") # https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-result_backend -CELERY_RESULT_BACKEND = CELERY_BROKER_URL +#CELERY_RESULT_BACKEND = CELERY_BROKER_URL # https://docs.celeryq.dev/en/stable/userguide/configuration.html#result-extended CELERY_RESULT_EXTENDED = True # https://docs.celeryq.dev/en/stable/userguide/configuration.html#result-backend-always-retry diff --git a/config/settings/local.py b/config/settings/local.py index e5a3005..5b5b21e 100644 --- a/config/settings/local.py +++ b/config/settings/local.py @@ -43,11 +43,11 @@ } # https://django-debug-toolbar.readthedocs.io/en/latest/installation.html#internal-ips INTERNAL_IPS = ["127.0.0.1", "10.0.2.2"] -if env("USE_DOCKER") == "yes": - import socket +# if env("USE_DOCKER") == "yes": +# import socket - hostname, _, ips = socket.gethostbyname_ex(socket.gethostname()) - INTERNAL_IPS += [".".join(ip.split(".")[:-1] + ["1"]) for ip in ips] +# hostname, _, ips = socket.gethostbyname_ex(socket.gethostname()) +# INTERNAL_IPS += [".".join(ip.split(".")[:-1] + ["1"]) for ip in ips] # django-extensions # ------------------------------------------------------------------------------ diff --git a/passfinder/events/api/serializers.py b/passfinder/events/api/serializers.py index 3aa81e5..10d055a 100644 --- a/passfinder/events/api/serializers.py +++ b/passfinder/events/api/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from passfinder.events.models import Hotel, HotelPhone, City +from passfinder.events.models import Hotel, HotelPhone, City, Event class HotelPhoneSerializer(serializers.ModelSerializer): @@ -29,3 +29,9 @@ class MuseumSerializer(serializers.ModelSerializer): class Meta: model = Hotel exclude = "oid" + + +class EventSerializer(serializers.ModelSerializer): + class Meta: + model = Event + fields = ('type', 'title', 'description', 'city', 'oid') \ No newline at end of file diff --git a/passfinder/recomendations/__init__.py b/passfinder/recomendations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/passfinder/recomendations/admin.py b/passfinder/recomendations/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/passfinder/recomendations/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/passfinder/recomendations/api/serializers.py b/passfinder/recomendations/api/serializers.py new file mode 100644 index 0000000..bb0bc13 --- /dev/null +++ b/passfinder/recomendations/api/serializers.py @@ -0,0 +1,7 @@ +from rest_framework import serializers +from passfinder.events.api.serializers import EventSerializer + + +class TinderProceedSerializer(serializers.Serializer): + action = serializers.ChoiceField(['left', 'right'], write_only=True) + event = EventSerializer(read_only=True) \ No newline at end of file diff --git a/passfinder/recomendations/api/views.py b/passfinder/recomendations/api/views.py new file mode 100644 index 0000000..e0d9725 --- /dev/null +++ b/passfinder/recomendations/api/views.py @@ -0,0 +1,26 @@ +from typing import Any +from rest_framework import viewsets, mixins +from rest_framework.request import Request +from rest_framework.response import Response +from passfinder.events.models import Event +from passfinder.events.api.serializers import EventSerializer +from random import choice +from rest_framework.decorators import action +from rest_framework.response import Response +from .serializers import TinderProceedSerializer + + +class TinderView(viewsets.GenericViewSet): + serializer_class = EventSerializer + model = Event + queryset = Event.objects.all() + + @action(methods=['GET'], detail=False, serializer_class=EventSerializer) + def start(self, request: Request, *args: Any, **kwargs: Any): + event = EventSerializer(choice(Event.objects.all())) + return Response(data=event.data, status=200) + + @action(methods=['POST'], detail=True, serializer_class=TinderProceedSerializer) + def proceed(self, request: Request, *args: Any, **kwargs: Any): + event = EventSerializer(choice(Event.objects.all())) + return Response(data={'event': event.data}, status=200) diff --git a/passfinder/recomendations/apps.py b/passfinder/recomendations/apps.py new file mode 100644 index 0000000..6722907 --- /dev/null +++ b/passfinder/recomendations/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class RecomendationsConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "passfinder.recomendations" diff --git a/passfinder/recomendations/migrations/0001_initial.py b/passfinder/recomendations/migrations/0001_initial.py new file mode 100644 index 0000000..9bab2eb --- /dev/null +++ b/passfinder/recomendations/migrations/0001_initial.py @@ -0,0 +1,75 @@ +# Generated by Django 4.2.1 on 2023-05-21 10:36 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("events", "0011_remove_event_purchase_method_and_more"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="UserPreferences", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "preferred_concerts", + models.ManyToManyField( + related_name="preffered_users_concert", to="events.event" + ), + ), + ( + "preffered_movies", + models.ManyToManyField( + related_name="preffered_user_movie", to="events.event" + ), + ), + ( + "preffered_plays", + models.ManyToManyField( + related_name="preffered_user_play", to="events.event" + ), + ), + ( + "unpreferred_concerts", + models.ManyToManyField( + related_name="unpreffered_users_concert", to="events.event" + ), + ), + ( + "unpreffered_lays", + models.ManyToManyField( + related_name="unpreffered_users_play", to="events.event" + ), + ), + ( + "unpreffered_movies", + models.ManyToManyField( + related_name="unpreffered_user_movie", to="events.event" + ), + ), + ( + "user", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + ] diff --git a/passfinder/recomendations/migrations/__init__.py b/passfinder/recomendations/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/passfinder/recomendations/models.py b/passfinder/recomendations/models.py new file mode 100644 index 0000000..bfd0eef --- /dev/null +++ b/passfinder/recomendations/models.py @@ -0,0 +1,16 @@ +from django.db import models +from passfinder.users.models import User +from passfinder.events.models import Event + + +class UserPreferences(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + + preffered_plays = models.ManyToManyField(Event, related_name='preffered_user_play') + unpreffered_lays = models.ManyToManyField(Event, related_name='unpreffered_users_play') + + preffered_movies = models.ManyToManyField(Event, related_name='preffered_user_movie') + unpreffered_movies = models.ManyToManyField(Event, related_name='unpreffered_user_movie') + + preferred_concerts = models.ManyToManyField(Event, related_name='preffered_users_concert') + unpreferred_concerts = models.ManyToManyField(Event, related_name='unpreffered_users_concert') \ No newline at end of file diff --git a/passfinder/recomendations/service/mapping/attractions.pickle b/passfinder/recomendations/service/mapping/attractions.pickle new file mode 100644 index 0000000..423102b Binary files /dev/null and b/passfinder/recomendations/service/mapping/attractions.pickle differ diff --git a/passfinder/recomendations/service/mapping/concerts.pickle b/passfinder/recomendations/service/mapping/concerts.pickle new file mode 100644 index 0000000..73caa23 Binary files /dev/null and b/passfinder/recomendations/service/mapping/concerts.pickle differ diff --git a/passfinder/recomendations/service/mapping/excursii.pickle b/passfinder/recomendations/service/mapping/excursii.pickle new file mode 100644 index 0000000..35f27fd Binary files /dev/null and b/passfinder/recomendations/service/mapping/excursii.pickle differ diff --git a/passfinder/recomendations/service/mapping/kino.pickle b/passfinder/recomendations/service/mapping/kino.pickle new file mode 100644 index 0000000..0d40096 Binary files /dev/null and b/passfinder/recomendations/service/mapping/kino.pickle differ diff --git a/passfinder/recomendations/service/mapping/mapping.py b/passfinder/recomendations/service/mapping/mapping.py new file mode 100644 index 0000000..d1361e2 --- /dev/null +++ b/passfinder/recomendations/service/mapping/mapping.py @@ -0,0 +1,26 @@ +import pickle + +attraction_mapping = None +cinema_mapping = None +plays_mapping = None +excursion_mapping = None +concert_mapping = None + +with open('passfinder/recomendations/service/mapping/attractions.pickle', 'rb') as file: + attraction_mapping = pickle.load(file) + + +with open('passfinder/recomendations/service/mapping/kino.pickle', 'rb') as file: + cinema_mapping = pickle.load(file) + + +with open('passfinder/recomendations/service/mapping/spektakli.pickle', 'rb') as file: + plays_mapping = pickle.load(file) + + +with open('passfinder/recomendations/service/mapping/excursii.pickle', 'rb') as file: + excursion_mapping = pickle.load(file) + + +with open('passfinder/recomendations/service/mapping/concerts.pickle', 'rb') as file: + concert_mapping = pickle.load(file) \ No newline at end of file diff --git a/passfinder/recomendations/service/mapping/spektakli.pickle b/passfinder/recomendations/service/mapping/spektakli.pickle new file mode 100644 index 0000000..7d796fc Binary files /dev/null and b/passfinder/recomendations/service/mapping/spektakli.pickle differ diff --git a/passfinder/recomendations/service/models/concerts.ann b/passfinder/recomendations/service/models/concerts.ann new file mode 100644 index 0000000..acc7897 Binary files /dev/null and b/passfinder/recomendations/service/models/concerts.ann differ diff --git a/passfinder/recomendations/service/models/dost.ann b/passfinder/recomendations/service/models/dost.ann new file mode 100644 index 0000000..0a574a6 Binary files /dev/null and b/passfinder/recomendations/service/models/dost.ann differ diff --git a/passfinder/recomendations/service/models/excursii.ann b/passfinder/recomendations/service/models/excursii.ann new file mode 100644 index 0000000..d92e2da Binary files /dev/null and b/passfinder/recomendations/service/models/excursii.ann differ diff --git a/passfinder/recomendations/service/models/kino.ann b/passfinder/recomendations/service/models/kino.ann new file mode 100644 index 0000000..51665b8 Binary files /dev/null and b/passfinder/recomendations/service/models/kino.ann differ diff --git a/passfinder/recomendations/service/models/models.py b/passfinder/recomendations/service/models/models.py new file mode 100644 index 0000000..c4dcec9 --- /dev/null +++ b/passfinder/recomendations/service/models/models.py @@ -0,0 +1,22 @@ +from annoy import AnnoyIndex + +N_DIMENSIONAL = 768 + +attracion_model = AnnoyIndex(N_DIMENSIONAL, 'angular') +attracion_model.load('passfinder/recomendations/service/models/dost.ann') + + +cinema_model = AnnoyIndex(N_DIMENSIONAL, 'angular') +cinema_model.load('passfinder/recomendations/service/models/kino.ann') + + +plays_model = AnnoyIndex(N_DIMENSIONAL, 'angular') +plays_model.load('passfinder/recomendations/service/models/spektatli.ann') + + +excursion_model = AnnoyIndex(N_DIMENSIONAL, 'angular') +excursion_model.load('passfinder/recomendations/service/models/excursii.ann') + + +concert_model = AnnoyIndex(N_DIMENSIONAL, 'angular') +concert_model.load('passfinder/recomendations/service/models/concerts.ann') diff --git a/passfinder/recomendations/service/models/spektatli.ann b/passfinder/recomendations/service/models/spektatli.ann new file mode 100644 index 0000000..13f3274 Binary files /dev/null and b/passfinder/recomendations/service/models/spektatli.ann differ diff --git a/passfinder/recomendations/service/service.py b/passfinder/recomendations/service/service.py new file mode 100644 index 0000000..e7f7b43 --- /dev/null +++ b/passfinder/recomendations/service/service.py @@ -0,0 +1,39 @@ +from annoy import AnnoyIndex +from .mapping.mapping import * +from .models.models import * +from passfinder.events.models import Event + + +def get_nearest_(instance_model, model_type, mapping, nearest_n, ml_model): + how_many = len(Event.objects.filter(type=model_type)) + + index = mapping.index(instance_model.oid) + nearest = ml_model.get_nns_by_item(index, len(mapping)) + + res = [] + for i in range(how_many): + try: + res.append(Event.objects.get(oid=mapping[nearest[i]])) + except Event.DoesNotExist: ... + if len(res) == nearest_n: break + return res + + +def nearest_attraction(attraction, nearest_n): + return get_nearest_(attraction, 'attraction', attraction_mapping, nearest_n, attracion_model) + + +def nearest_movie(movie, nearest_n): + return get_nearest_(movie, 'movie', cinema_mapping, nearest_n, cinema_model) + + +def nearest_plays(play, nearest_n): + return get_nearest_(play, 'play', plays_mapping, nearest_n, plays_model) + + +def nearest_excursion(excursion, nearest_n): + return get_nearest_(excursion, 'excursion', excursion_mapping, nearest_n, excursion_model) + + +def nearest_concert(concert, nearest_n): + return get_nearest_(concert, 'concert', concert_mapping, nearest_n, concert_model) diff --git a/passfinder/recomendations/tests.py b/passfinder/recomendations/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/passfinder/recomendations/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/passfinder/recomendations/views.py b/passfinder/recomendations/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/passfinder/recomendations/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/passfinder/utils/choices.py b/passfinder/utils/choices.py index 5f986b3..e479298 100644 --- a/passfinder/utils/choices.py +++ b/passfinder/utils/choices.py @@ -3,7 +3,7 @@ from django.db.models.enums import ChoicesMeta -def count_max_length(choices: Iterable | ChoicesMeta): +def count_max_length(choices: any): if isinstance(choices, ChoicesMeta): return max([len(val) for val in choices.values]) return max([len(val) for val, _ in choices]) diff --git a/poetry.lock b/poetry.lock index f93fa27..bfb5d8e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2805,5 +2805,5 @@ files = [ [metadata] lock-version = "2.0" -python-versions = "^3.11" +python-versions = "^3.8" content-hash = "f28dac962f7703c39a58bd0f7640a1cc37af3dccd44f124e57e71d19d85278c0" diff --git a/pyproject.toml b/pyproject.toml index e7755e6..9ee5481 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = ["Alexandr Karpov "] readme = "README.md" [tool.poetry.dependencies] -python = "^3.11" +python = "^3.8" psycopg2 = "^2.9.5" pytz = "^2022.7" psutil = "^5.9.4" diff --git a/requirements.txt b/requirements.txt index d6e2ccc..bcc110a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,136 +1,134 @@ -amqp==5.1.1 ; python_version >= "3.11" and python_version < "4.0" -anyio==3.6.2 ; python_version >= "3.11" and python_version < "4.0" -appnope==0.1.3 ; python_version >= "3.11" and python_version < "4.0" and sys_platform == "darwin" -argon2-cffi-bindings==21.2.0 ; python_version >= "3.11" and python_version < "4.0" -argon2-cffi==21.3.0 ; python_version >= "3.11" and python_version < "4.0" -asgiref==3.6.0 ; python_version >= "3.11" and python_version < "4.0" -astroid==2.15.5 ; python_version >= "3.11" and python_version < "4.0" -asttokens==2.2.1 ; python_version >= "3.11" and python_version < "4.0" -async-timeout==4.0.2 ; python_version >= "3.11" and python_full_version <= "3.11.2" -attrs==23.1.0 ; python_version >= "3.11" and python_version < "4.0" -backcall==0.2.0 ; python_version >= "3.11" and python_version < "4.0" -billiard==3.6.4.0 ; python_version >= "3.11" and python_version < "4.0" -black==22.12.0 ; python_version >= "3.11" and python_version < "4.0" -celery==5.2.7 ; python_version >= "3.11" and python_version < "4.0" -celery[redis]==5.2.7 ; python_version >= "3.11" and python_version < "4.0" -certifi==2023.5.7 ; python_version >= "3.11" and python_version < "4.0" -cffi==1.15.1 ; python_version >= "3.11" and python_version < "4.0" -cfgv==3.3.1 ; python_version >= "3.11" and python_version < "4.0" -charset-normalizer==3.1.0 ; python_version >= "3.11" and python_version < "4.0" -click-didyoumean==0.3.0 ; python_version >= "3.11" and python_version < "4.0" -click-plugins==1.1.1 ; python_version >= "3.11" and python_version < "4.0" -click-repl==0.2.0 ; python_version >= "3.11" and python_version < "4.0" -click==8.1.3 ; python_version >= "3.11" and python_version < "4.0" -colorama==0.4.6 ; python_version >= "3.11" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.11" and python_version < "4.0" and platform_system == "Windows" -coverage==7.2.5 ; python_version >= "3.11" and python_version < "4.0" -cron-descriptor==1.3.0 ; python_version >= "3.11" and python_version < "4.0" -decorator==5.1.1 ; python_version >= "3.11" and python_version < "4.0" -dill==0.3.6 ; python_version >= "3.11" and python_version < "4.0" -distlib==0.3.6 ; python_version >= "3.11" and python_version < "4.0" -django-celery-beat==2.5.0 ; python_version >= "3.11" and python_version < "4.0" -django-cors-headers==3.14.0 ; python_version >= "3.11" and python_version < "4.0" -django-coverage-plugin==3.0.0 ; python_version >= "3.11" and python_version < "4.0" -django-debug-toolbar==3.8.1 ; python_version >= "3.11" and python_version < "4.0" -django-environ==0.9.0 ; python_version >= "3.11" and python_version < "4" -django-extensions==3.2.1 ; python_version >= "3.11" and python_version < "4.0" -django-ipware==5.0.0 ; python_version >= "3.11" and python_version < "4.0" -django-location-field==2.7.0 ; python_version >= "3.11" and python_version < "4.0" -django-model-utils==4.3.1 ; python_version >= "3.11" and python_version < "4.0" -django-polymorphic==3.1.0 ; python_version >= "3.11" and python_version < "4.0" -django-redis==5.2.0 ; python_version >= "3.11" and python_version < "4.0" -django-structlog==4.1.1 ; python_version >= "3.11" and python_version < "4.0" -django-stubs-ext==4.2.0 ; python_version >= "3.11" and python_version < "4.0" -django-stubs==1.16.0 ; python_version >= "3.11" and python_version < "4.0" -django-timezone-field==5.0 ; python_version >= "3.11" and python_version < "4.0" -django==4.2.1 ; python_version >= "3.11" and python_version < "4.0" -djangorestframework-stubs==1.10.0 ; python_version >= "3.11" and python_version < "4.0" -djangorestframework==3.14.0 ; python_version >= "3.11" and python_version < "4.0" -drf-spectacular==0.25.1 ; python_version >= "3.11" and python_version < "4.0" -executing==1.2.0 ; python_version >= "3.11" and python_version < "4.0" -factory-boy==3.2.1 ; python_version >= "3.11" and python_version < "4.0" -faker==18.9.0 ; python_version >= "3.11" and python_version < "4.0" -filelock==3.12.0 ; python_version >= "3.11" and python_version < "4.0" -flake8-isort==6.0.0 ; python_version >= "3.11" and python_version < "4.0" -flake8==6.0.0 ; python_version >= "3.11" and python_version < "4.0" -flower==1.2.0 ; python_version >= "3.11" and python_version < "4.0" -humanize==4.6.0 ; python_version >= "3.11" and python_version < "4.0" -identify==2.5.24 ; python_version >= "3.11" and python_version < "4.0" -idna==3.4 ; python_version >= "3.11" and python_version < "4.0" -inflection==0.5.1 ; python_version >= "3.11" and python_version < "4.0" -iniconfig==2.0.0 ; python_version >= "3.11" and python_version < "4.0" -ipdb==0.13.13 ; python_version >= "3.11" and python_version < "4.0" -ipython==8.13.2 ; python_version >= "3.11" and python_version < "4.0" -isort==5.12.0 ; python_version >= "3.11" and python_version < "4.0" -jedi==0.18.2 ; python_version >= "3.11" and python_version < "4.0" -jsonschema==4.17.3 ; python_version >= "3.11" and python_version < "4.0" -kombu==5.2.4 ; python_version >= "3.11" and python_version < "4.0" -lazy-object-proxy==1.9.0 ; python_version >= "3.11" and python_version < "4.0" -markupsafe==2.1.2 ; python_version >= "3.11" and python_version < "4.0" -matplotlib-inline==0.1.6 ; python_version >= "3.11" and python_version < "4.0" -mccabe==0.7.0 ; python_version >= "3.11" and python_version < "4.0" -mypy-extensions==1.0.0 ; python_version >= "3.11" and python_version < "4.0" -mypy==0.991 ; python_version >= "3.11" and python_version < "4.0" -nodeenv==1.8.0 ; python_version >= "3.11" and python_version < "4.0" -packaging==23.1 ; python_version >= "3.11" and python_version < "4.0" -parso==0.8.3 ; python_version >= "3.11" and python_version < "4.0" -pathspec==0.11.1 ; python_version >= "3.11" and python_version < "4.0" -pexpect==4.8.0 ; python_version >= "3.11" and python_version < "4.0" and sys_platform != "win32" -pickleshare==0.7.5 ; python_version >= "3.11" and python_version < "4.0" -pillow==9.5.0 ; python_version >= "3.11" and python_version < "4.0" -platformdirs==3.5.1 ; python_version >= "3.11" and python_version < "4.0" -pluggy==1.0.0 ; python_version >= "3.11" and python_version < "4.0" -pre-commit==2.21.0 ; python_version >= "3.11" and python_version < "4.0" -prometheus-client==0.16.0 ; python_version >= "3.11" and python_version < "4.0" -prompt-toolkit==3.0.38 ; python_version >= "3.11" and python_version < "4.0" -psutil==5.9.5 ; python_version >= "3.11" and python_version < "4.0" -psycopg2==2.9.6 ; python_version >= "3.11" and python_version < "4.0" -ptyprocess==0.7.0 ; python_version >= "3.11" and python_version < "4.0" and sys_platform != "win32" -pure-eval==0.2.2 ; python_version >= "3.11" and python_version < "4.0" -pycodestyle==2.10.0 ; python_version >= "3.11" and python_version < "4.0" -pycparser==2.21 ; python_version >= "3.11" and python_version < "4.0" -pyflakes==3.0.1 ; python_version >= "3.11" and python_version < "4.0" -pygments==2.15.1 ; python_version >= "3.11" and python_version < "4.0" -pylint-celery==0.3 ; python_version >= "3.11" and python_version < "4.0" -pylint-django==2.5.3 ; python_version >= "3.11" and python_version < "4.0" -pylint-plugin-utils==0.8.1 ; python_version >= "3.11" and python_version < "4.0" -pylint==2.17.4 ; python_version >= "3.11" and python_version < "4.0" -pyrsistent==0.19.3 ; python_version >= "3.11" and python_version < "4.0" -pytest-django==4.5.2 ; python_version >= "3.11" and python_version < "4.0" -pytest-sugar==0.9.7 ; python_version >= "3.11" and python_version < "4.0" -pytest==7.3.1 ; python_version >= "3.11" and python_version < "4.0" -python-crontab==2.7.1 ; python_version >= "3.11" and python_version < "4.0" -python-dateutil==2.8.2 ; python_version >= "3.11" and python_version < "4.0" -python-slugify==7.0.0 ; python_version >= "3.11" and python_version < "4.0" -pytz==2022.7.1 ; python_version >= "3.11" and python_version < "4.0" -pyyaml==6.0 ; python_version >= "3.11" and python_version < "4.0" -redis==4.5.5 ; python_version >= "3.11" and python_version < "4.0" -requests==2.30.0 ; python_version >= "3.11" and python_version < "4.0" -sentry-sdk==1.23.1 ; python_version >= "3.11" and python_version < "4.0" -setuptools==67.7.2 ; python_version >= "3.11" and python_version < "4.0" -six==1.16.0 ; python_version >= "3.11" and python_version < "4.0" -sniffio==1.3.0 ; python_version >= "3.11" and python_version < "4.0" -sqlparse==0.4.4 ; python_version >= "3.11" and python_version < "4.0" -stack-data==0.6.2 ; python_version >= "3.11" and python_version < "4.0" -structlog==23.1.0 ; python_version >= "3.11" and python_version < "4.0" -termcolor==2.3.0 ; python_version >= "3.11" and python_version < "4.0" -text-unidecode==1.3 ; python_version >= "3.11" and python_version < "4.0" -tomli==2.0.1 ; python_version >= "3.11" and python_version < "4.0" -tomlkit==0.11.8 ; python_version >= "3.11" and python_version < "4.0" -tornado==6.3.2 ; python_version >= "3.11" and python_version < "4.0" -traitlets==5.9.0 ; python_version >= "3.11" and python_version < "4.0" -types-pytz==2023.3.0.0 ; python_version >= "3.11" and python_version < "4.0" -types-pyyaml==6.0.12.9 ; python_version >= "3.11" and python_version < "4.0" -types-requests==2.30.0.0 ; python_version >= "3.11" and python_version < "4.0" -types-urllib3==1.26.25.13 ; python_version >= "3.11" and python_version < "4.0" -typing-extensions==4.5.0 ; python_version >= "3.11" and python_version < "4.0" -tzdata==2023.3 ; python_version >= "3.11" and python_version < "4.0" -uritemplate==4.1.1 ; python_version >= "3.11" and python_version < "4.0" -urllib3==1.26.15 ; python_version >= "3.11" and python_version < "4.0" -vine==5.0.0 ; python_version >= "3.11" and python_version < "4.0" -virtualenv==20.23.0 ; python_version >= "3.11" and python_version < "4.0" -watchdog==3.0.0 ; python_version >= "3.11" and python_version < "4.0" -watchfiles==0.18.1 ; python_version >= "3.11" and python_version < "4.0" -wcwidth==0.2.6 ; python_version >= "3.11" and python_version < "4.0" -werkzeug[watchdog]==2.3.4 ; python_version >= "3.11" and python_version < "4.0" -whitenoise==6.4.0 ; python_version >= "3.11" and python_version < "4.0" -wrapt==1.15.0 ; python_version >= "3.11" and python_version < "4.0" +amqp==5.1.1 ; python_version >= "3.9" and python_version < "4.0" +anyio==3.6.2 ; python_version >= "3.9" and python_version < "4.0" +appnope==0.1.3 ; python_version >= "3.9" and python_version < "4.0" and sys_platform == "darwin" +argon2-cffi-bindings==21.2.0 ; python_version >= "3.9" and python_version < "4.0" +argon2-cffi==21.3.0 ; python_version >= "3.9" and python_version < "4.0" +asgiref==3.6.0 ; python_version >= "3.9" and python_version < "4.0" +astroid==2.15.5 ; python_version >= "3.9" and python_version < "4.0" +asttokens==2.2.1 ; python_version >= "3.9" and python_version < "4.0" +async-timeout==4.0.2 ; python_version >= "3.9" and python_full_version <= "3.9" +attrs==23.1.0 ; python_version >= "3.9" and python_version < "4.0" +backcall==0.2.0 ; python_version >= "3.9" and python_version < "4.0" +billiard==3.6.4.0 ; python_version >= "3.9" and python_version < "4.0" +black==22.12.0 ; python_version >= "3.9" and python_version < "4.0" +celery==5.2.7 ; python_version >= "3.9" and python_version < "4.0" +celery[redis]==5.2.7 ; python_version >= "3.9" and python_version < "4.0" +certifi==2023.5.7 ; python_version >= "3.9" and python_version < "4.0" +cffi==1.15.1 ; python_version >= "3.9" and python_version < "4.0" +cfgv==3.3.1 ; python_version >= "3.9" and python_version < "4.0" +charset-normalizer==3.1.0 ; python_version >= "3.9" and python_version < "4.0" +click-didyoumean==0.3.0 ; python_version >= "3.9" and python_version < "4.0" +click-plugins==1.1.1 ; python_version >= "3.9" and python_version < "4.0" +click-repl==0.2.0 ; python_version >= "3.9" and python_version < "4.0" +click==8.1.3 ; python_version >= "3.9" and python_version < "4.0" +colorama==0.4.6 ; python_version >= "3.9" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.9" and python_version < "4.0" and platform_system == "Windows" +coverage==7.2.5 ; python_version >= "3.9" and python_version < "4.0" +cron-descriptor==1.3.0 ; python_version >= "3.9" and python_version < "4.0" +decorator==5.1.1 ; python_version >= "3.9" and python_version < "4.0" +dill==0.3.6 ; python_version >= "3.9" and python_version < "4.0" +distlib==0.3.6 ; python_version >= "3.9" and python_version < "4.0" +django-celery-beat==2.5.0 ; python_version >= "3.9" and python_version < "4.0" +django-cors-headers==3.14.0 ; python_version >= "3.9" and python_version < "4.0" +django-coverage-plugin==3.0.0 ; python_version >= "3.9" and python_version < "4.0" +django-debug-toolbar==3.8.1 ; python_version >= "3.9" and python_version < "4.0" +django-environ==0.9.0 ; python_version >= "3.9" and python_version < "4" +django-extensions==3.2.1 ; python_version >= "3.9" and python_version < "4.0" +django-ipware==5.0.0 ; python_version >= "3.9" and python_version < "4.0" +django-location-field==2.7.0 ; python_version >= "3.9" and python_version < "4.0" +django-model-utils==4.3.1 ; python_version >= "3.9" and python_version < "4.0" +django-polymorphic==3.1.0 ; python_version >= "3.9" and python_version < "4.0" +django-redis==5.2.0 ; python_version >= "3.9" and python_version < "4.0" +django-structlog==4.1.1 ; python_version >= "3.9" and python_version < "4.0" +django-stubs-ext==4.2.0 ; python_version >= "3.9" and python_version < "4.0" +django-stubs==1.16.0 ; python_version >= "3.9" and python_version < "4.0" +django-timezone-field==5.0 ; python_version >= "3.9" and python_version < "4.0" +django==4.2.1 ; python_version >= "3.9" and python_version < "4.0" +djangorestframework-stubs==1.10.0 ; python_version >= "3.9" and python_version < "4.0" +djangorestframework==3.14.0 ; python_version >= "3.9" and python_version < "4.0" +drf-spectacular==0.25.1 ; python_version >= "3.9" and python_version < "4.0" +executing==1.2.0 ; python_version >= "3.9" and python_version < "4.0" +factory-boy==3.2.1 ; python_version >= "3.9" and python_version < "4.0" +faker==18.9.0 ; python_version >= "3.9" and python_version < "4.0" +filelock==3.12.0 ; python_version >= "3.9" and python_version < "4.0" +flake8-isort==6.0.0 ; python_version >= "3.9" and python_version < "4.0" +flake8==6.0.0 ; python_version >= "3.9" and python_version < "4.0" +flower==1.2.0 ; python_version >= "3.9" and python_version < "4.0" +humanize==4.6.0 ; python_version >= "3.9" and python_version < "4.0" +identify==2.5.24 ; python_version >= "3.9" and python_version < "4.0" +idna==3.4 ; python_version >= "3.9" and python_version < "4.0" +inflection==0.5.1 ; python_version >= "3.9" and python_version < "4.0" +iniconfig==2.0.0 ; python_version >= "3.9" and python_version < "4.0" +ipdb==0.13.13 ; python_version >= "3.9" and python_version < "4.0" +ipython==8.13.2 ; python_version >= "3.9" and python_version < "4.0" +isort==5.12.0 ; python_version >= "3.9" and python_version < "4.0" +jedi==0.18.2 ; python_version >= "3.9" and python_version < "4.0" +jsonschema==4.17.3 ; python_version >= "3.9" and python_version < "4.0" +kombu==5.2.4 ; python_version >= "3.9" and python_version < "4.0" +lazy-object-proxy==1.9.0 ; python_version >= "3.9" and python_version < "4.0" +markupsafe==2.1.2 ; python_version >= "3.9" and python_version < "4.0" +matplotlib-inline==0.1.6 ; python_version >= "3.9" and python_version < "4.0" +mccabe==0.7.0 ; python_version >= "3.9" and python_version < "4.0" +mypy-extensions==1.0.0 ; python_version >= "3.9" and python_version < "4.0" +mypy==0.991 ; python_version >= "3.9" and python_version < "4.0" +nodeenv==1.8.0 ; python_version >= "3.9" and python_version < "4.0" +packaging==23.1 ; python_version >= "3.9" and python_version < "4.0" +parso==0.8.3 ; python_version >= "3.9" and python_version < "4.0" +pexpect==4.8.0 ; python_version >= "3.9" and python_version < "4.0" and sys_platform != "win32" +pickleshare==0.7.5 ; python_version >= "3.9" and python_version < "4.0" +pillow==9.5.0 ; python_version >= "3.9" and python_version < "4.0" +platformdirs==3.5.1 ; python_version >= "3.9" and python_version < "4.0" +pluggy==1.0.0 ; python_version >= "3.9" and python_version < "4.0" +pre-commit==2.21.0 ; python_version >= "3.9" and python_version < "4.0" +prometheus-client==0.16.0 ; python_version >= "3.9" and python_version < "4.0" +prompt-toolkit==3.0.38 ; python_version >= "3.9" and python_version < "4.0" +psutil==5.9.5 ; python_version >= "3.9" and python_version < "4.0" +psycopg2==2.9.6 ; python_version >= "3.9" and python_version < "4.0" +ptyprocess==0.7.0 ; python_version >= "3.9" and python_version < "4.0" and sys_platform != "win32" +pure-eval==0.2.2 ; python_version >= "3.9" and python_version < "4.0" +pycodestyle==2.10.0 ; python_version >= "3.9" and python_version < "4.0" +pycparser==2.21 ; python_version >= "3.9" and python_version < "4.0" +pyflakes==3.0.1 ; python_version >= "3.9" and python_version < "4.0" +pygments==2.15.1 ; python_version >= "3.9" and python_version < "4.0" +pylint-celery==0.3 ; python_version >= "3.9" and python_version < "4.0" +pylint-django==2.5.3 ; python_version >= "3.9" and python_version < "4.0" +pylint-plugin-utils==0.8.1 ; python_version >= "3.9" and python_version < "4.0" +pylint==2.17.4 ; python_version >= "3.9" and python_version < "4.0" +pyrsistent==0.19.3 ; python_version >= "3.9" and python_version < "4.0" +pytest-django==4.5.2 ; python_version >= "3.9" and python_version < "4.0" +pytest-sugar==0.9.7 ; python_version >= "3.9" and python_version < "4.0" +pytest==7.3.1 ; python_version >= "3.9" and python_version < "4.0" +python-crontab==2.7.1 ; python_version >= "3.9" and python_version < "4.0" +python-dateutil==2.8.2 ; python_version >= "3.9" and python_version < "4.0" +python-slugify==7.0.0 ; python_version >= "3.9" and python_version < "4.0" +pytz==2022.7.1 ; python_version >= "3.9" and python_version < "4.0" +pyyaml==6.0 ; python_version >= "3.9" and python_version < "4.0" +redis==4.5.5 ; python_version >= "3.9" and python_version < "4.0" +requests==2.30.0 ; python_version >= "3.9" and python_version < "4.0" +sentry-sdk==1.23.1 ; python_version >= "3.9" and python_version < "4.0" +setuptools==67.7.2 ; python_version >= "3.9" and python_version < "4.0" +six==1.16.0 ; python_version >= "3.9" and python_version < "4.0" +sniffio==1.3.0 ; python_version >= "3.9" and python_version < "4.0" +sqlparse==0.4.4 ; python_version >= "3.9" and python_version < "4.0" +stack-data==0.6.2 ; python_version >= "3.9" and python_version < "4.0" +structlog==23.1.0 ; python_version >= "3.9" and python_version < "4.0" +termcolor==2.3.0 ; python_version >= "3.9" and python_version < "4.0" +text-unidecode==1.3 ; python_version >= "3.9" and python_version < "4.0" +tomli==2.0.1 ; python_version >= "3.9" and python_version < "4.0" +tornado==6.3.2 ; python_version >= "3.9" and python_version < "4.0" +traitlets==5.9.0 ; python_version >= "3.9" and python_version < "4.0" +types-pytz==2023.3.0.0 ; python_version >= "3.9" and python_version < "4.0" +types-pyyaml==6.0.12.9 ; python_version >= "3.9" and python_version < "4.0" +types-requests==2.30.0.0 ; python_version >= "3.9" and python_version < "4.0" +types-urllib3==1.26.25.13 ; python_version >= "3.9" and python_version < "4.0" +typing-extensions==4.5.0 ; python_version >= "3.9" and python_version < "4.0" +tzdata==2023.3 ; python_version >= "3.9" and python_version < "4.0" +uritemplate==4.1.1 ; python_version >= "3.9" and python_version < "4.0" +urllib3==1.26.15 ; python_version >= "3.9" and python_version < "4.0" +vine==5.0.0 ; python_version >= "3.9" and python_version < "4.0" +virtualenv==20.23.0 ; python_version >= "3.9" and python_version < "4.0" +watchdog==3.0.0 ; python_version >= "3.9" and python_version < "4.0" +watchfiles==0.18.1 ; python_version >= "3.9" and python_version < "4.0" +wcwidth==0.2.6 ; python_version >= "3.9" and python_version < "4.0" +werkzeug[watchdog]==2.3.4 ; python_version >= "3.9" and python_version < "4.0" +whitenoise==6.4.0 ; python_version >= "3.9" and python_version < "4.0" +wrapt==1.15.0 ; python_version >= "3.9" and python_version < "4.0" \ No newline at end of file