Features: 1) Add app_name attribute in multiple urls.py files across apps to support namespacing;

Fixes: 1) Simplify Prometheus and GraphQL path definitions in `evibes/api_urls.py`;

Extra: 1) Add line breaks across multiple files for improved code readability.
This commit is contained in:
Egor Pavlovich Gorbunov 2025-06-29 20:03:33 +03:00
parent 7ff62cea0e
commit 856f2ff516
15 changed files with 53 additions and 5 deletions

View file

@ -28,6 +28,7 @@ class Post(NiceModel):
tags (ManyToManyField): Tags associated with the post for categorization.
"""
is_publicly_visible = True
author: ForeignKey = ForeignKey(
@ -112,6 +113,7 @@ class PostTag(NiceModel):
verbose_name (str): Human-readable singular name of the PostTag model.
verbose_name_plural (str): Human-readable plural name of the PostTag model.
"""
is_publicly_visible = True
tag_name: CharField = CharField(

View file

@ -3,6 +3,8 @@ from rest_framework.routers import DefaultRouter
from blog.viewsets import PostViewSet
app_name = "blog"
payment_router = DefaultRouter()
payment_router.register(prefix=r"posts", viewset=PostViewSet, basename="posts")

View file

@ -23,6 +23,7 @@ class PostViewSet(ReadOnlyModelViewSet):
filterset_class: Defines the set of filters used for filtering Post objects.
additional: Contains additional configuration, such as specific action permissions.
"""
serializer_class = PostSerializer
permission_classes = (EvibesPermission,)
queryset = Post.objects.filter(is_active=True)

View file

@ -30,6 +30,8 @@ from core.viewsets import (
WishlistViewSet,
)
app_name = "core"
core_router = DefaultRouter()
core_router.register(r"products", ProductViewSet, basename="products")
core_router.register(r"orders", OrderViewSet, basename="orders")

View file

@ -5,6 +5,8 @@ from core.views import (
GlobalSearchView,
)
app_name = "core"
urlpatterns = [
path("search/", GlobalSearchView.as_view(), name="global_search"),
path("orders/buy_as_business/", BuyAsBusinessView.as_view(), name="request_cursed_url"),

View file

@ -106,6 +106,7 @@ class CustomGraphQLView(FileUploadGraphQLView):
----------
None
"""
def get_context(self, request):
return request
@ -120,6 +121,7 @@ class CustomSwaggerView(SpectacularSwaggerView):
This can be useful in scenarios where the script or reference
URL needs to be dynamically generated and included in the context.
"""
def get_context_data(self, **kwargs):
# noinspection PyUnresolvedReferences
context = super().get_context_data(**kwargs)
@ -137,6 +139,7 @@ class CustomRedocView(SpectacularRedocView):
for rendering ReDoc UI is required, specifically adapting the script
URL for the current request environment.
"""
def get_context_data(self, **kwargs):
# noinspection PyUnresolvedReferences
context = super().get_context_data(**kwargs)
@ -164,6 +167,7 @@ class SupportedLanguagesView(APIView):
get(self, request): Retrieves the list of supported languages.
"""
serializer_class = LanguageSerializer
permission_classes = [
AllowAny,
@ -218,6 +222,7 @@ class WebsiteParametersView(APIView):
get(request)
Handles HTTP GET requests to fetch website parameters.
"""
serializer_class = None
permission_classes = [
AllowAny,
@ -253,6 +258,7 @@ class CacheOperatorView(APIView):
post(request, *args, **kwargs): Handles HTTP POST requests to set cache
data based on the provided key and timeout.
"""
serializer_class = CacheOperatorSerializer
permission_classes = [
AllowAny,
@ -294,6 +300,7 @@ class ContactUsView(APIView):
post: Handles POST requests to process form submissions.
"""
serializer_class = ContactUsSerializer
renderer_classes = [
CamelCaseJSONRenderer,
@ -326,6 +333,7 @@ class RequestCursedURLView(APIView):
Methods:
post: Handles the POST request to validate the URL, fetch its data if valid, and returns the processed response.
"""
permission_classes = [
AllowAny,
]
@ -411,6 +419,7 @@ class BuyAsBusinessView(APIView):
post(request, *_args, **kwargs):
Handles the post request to process a business purchase.
"""
@ratelimit(key="ip", rate="2/h", block=True)
def post(self, request, *_args, **kwargs):
serializer = BuyAsBusinessOrderSerializer(data=request.data)

View file

@ -131,6 +131,7 @@ class EvibesViewSet(ModelViewSet):
Returns the serializer class for the current action or the default
serializer class from the parent ModelViewSet.
"""
action_serializer_classes: dict = {}
additional: dict = {}
permission_classes = [EvibesPermission]
@ -162,6 +163,7 @@ class AttributeGroupViewSet(EvibesViewSet):
specific serializer classes, allowing customization of serialization
behavior for certain actions.
"""
queryset = AttributeGroup.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["is_active"]
@ -193,6 +195,7 @@ class AttributeViewSet(EvibesViewSet):
specific actions, such as returning less detailed data for a `list`
action.
"""
queryset = Attribute.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["group", "value_type", "is_active"]
@ -220,6 +223,7 @@ class AttributeValueViewSet(EvibesViewSet):
action_serializer_classes (dict): A dictionary mapping action names to their corresponding
serializer classes.
"""
queryset = AttributeValue.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["attribute", "is_active"]
@ -258,6 +262,7 @@ class CategoryViewSet(EvibesViewSet):
and filtering out inactive categories for users without sufficient
permissions.
"""
queryset = Category.objects.all().prefetch_related("parent", "children", "attributes", "tags")
filter_backends = [DjangoFilterBackend]
filterset_class = CategoryFilter
@ -294,6 +299,7 @@ class BrandViewSet(EvibesViewSet):
to their corresponding serializer classes. The "list" action
uses the BrandSimpleSerializer class.
"""
queryset = Brand.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_class = BrandFilter
@ -328,6 +334,7 @@ class ProductViewSet(EvibesViewSet):
get_object: Fetches a single object based on its identifier, applying permissions.
feedbacks: Fetches feedback associated with a specific product.
"""
queryset = Product.objects.prefetch_related("tags", "attributes", "stocks", "images").all()
filter_backends = [DjangoFilterBackend]
filterset_class = ProductFilter
@ -402,6 +409,7 @@ class VendorViewSet(EvibesViewSet):
action_serializer_classes: A dictionary mapping specific actions
(e.g., "list") to custom serializer classes for those actions.
"""
queryset = Vendor.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["name", "markup_percent", "is_active"]
@ -433,6 +441,7 @@ class FeedbackViewSet(EvibesViewSet):
serializer classes. For example, the "list" action uses
`FeedbackSimpleSerializer`.
"""
queryset = Feedback.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_class = FeedbackFilter
@ -495,6 +504,7 @@ class OrderViewSet(EvibesViewSet):
bulk_remove_order_products: Removes multiple products with optional attributes from
an order.
"""
lookup_field = "lookup_value"
lookup_url_kwarg = "lookup_value"
queryset = Order.objects.prefetch_related("order_products").all()
@ -692,6 +702,7 @@ class OrderProductViewSet(EvibesViewSet):
do_feedback: Custom action to add, remove, or manage feedback for
an OrderProduct instance.
"""
queryset = OrderProduct.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["order", "product", "status", "is_active"]
@ -756,6 +767,7 @@ class ProductImageViewSet(EvibesViewSet):
serializer classes. For the "list" action, ProductImageSimpleSerializer
is used.
"""
queryset = ProductImage.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["product", "priority", "is_active"]
@ -785,6 +797,7 @@ class PromoCodeViewSet(EvibesViewSet):
action_serializer_classes: A dictionary mapping specific actions (like
"list") to their corresponding serializer classes.
"""
queryset = PromoCode.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["code", "discount_amount", "discount_percent", "start_time", "end_time", "used_on", "is_active"]
@ -812,6 +825,7 @@ class PromotionViewSet(EvibesViewSet):
queryset management, filter backends, and serializer customization for handling
different views or actions efficiently.
"""
queryset = Promotion.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["name", "discount_percent", "is_active"]
@ -842,6 +856,7 @@ class StockViewSet(EvibesViewSet):
to their respective serializers. For the "list" action,
StockSimpleSerializer is used.
"""
queryset = Stock.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["vendor", "product", "sku", "is_active"]
@ -891,6 +906,7 @@ class WishlistViewSet(EvibesViewSet):
bulk_remove_wishlist_products(request, **kwargs)
Removes multiple products from a specific wishlist.
"""
queryset = Wishlist.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["user", "is_active"]
@ -1006,6 +1022,7 @@ class AddressViewSet(EvibesViewSet):
serializer_class: Default serializer class for address objects.
additional: Dictionary of additional options for this viewset.
"""
pagination_class = None
filter_backends = [DjangoFilterBackend]
filterset_class = AddressFilter
@ -1085,6 +1102,7 @@ class ProductTagViewSet(EvibesViewSet):
'list') to custom serializers. Utilizes ProductTagSimpleSerializer
for the 'list' action.
"""
queryset = ProductTag.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ["tag_name", "is_active"]

View file

@ -18,11 +18,8 @@ from evibes.settings import SPECTACULAR_PLATFORM_SETTINGS
urlpatterns = [
path(r"health/", include("health_check.urls", namespace="health_check")),
path("prometheus/", include("django_prometheus.urls", namespace="prometheus")),
path(
r"graphql/",
csrf_exempt(CustomGraphQLView.as_view(graphiql=True, schema=schema)), name="graphql-platform"
),
path("prometheus/", include("django_prometheus.urls")),
path(r"graphql/", csrf_exempt(CustomGraphQLView.as_view(graphiql=True, schema=schema)), name="graphql-platform"),
path(
r"docs/",
SpectacularAPIView.as_view(urlconf="evibes.api_urls", custom_settings=SPECTACULAR_PLATFORM_SETTINGS),

View file

@ -4,6 +4,8 @@ from rest_framework.routers import DefaultRouter
from payments.views import CallbackAPIView, DepositView
from payments.viewsets import TransactionViewSet
app_name = "payments"
payment_router = DefaultRouter()
payment_router.register(prefix=r"transactions", viewset=TransactionViewSet, basename="transactions")

View file

@ -31,6 +31,7 @@ class DepositView(APIView):
post: Processes the deposit request, validates the request data, ensures
user authentication, and creates a transaction.
"""
def post(self, request, *args, **kwargs):
logger.debug(request.__dict__)
serializer = DepositSerializer(data=request.data)
@ -65,6 +66,7 @@ class CallbackAPIView(APIView):
based on the specified gateway. Handles exceptions gracefully by returning
a server error response if an unknown gateway or other issues occur.
"""
def post(self, request, *args, **kwargs):
logger.debug(request.__dict__)
try:

View file

@ -20,5 +20,6 @@ class TransactionViewSet(ReadOnlyModelViewSet):
the data. Includes custom permissions to restrict access based
on ownership and other criteria.
"""
serializer_class = TransactionSerializer
permission_classes = (EvibesPermission, IsOwner)

View file

@ -79,6 +79,7 @@ class User(AbstractUser, NiceModel):
verbose_name: Sets the human-readable name for singular instances of the model.
verbose_name_plural: Sets the human-readable name for multiple instances of the model.
"""
def get_uuid_as_path(self, *args):
return str(self.uuid) + "/" + args[0]
@ -173,6 +174,7 @@ class Group(BaseGroup):
Meta.verbose_name_plural (str): Human-readable plural name for the Group
model.
"""
class Meta:
proxy = True
verbose_name = _("group")
@ -194,6 +196,7 @@ class OutstandingToken(BaseOutstandingToken):
the plural form of that name.
"""
class Meta:
proxy = True
verbose_name = _("outstanding token")
@ -214,6 +217,7 @@ class BlacklistedToken(BaseBlacklistedToken):
Attributes:
None
"""
class Meta:
proxy = True
verbose_name = _("blacklisted token")

View file

@ -4,6 +4,8 @@ from rest_framework.routers import DefaultRouter
from vibes_auth.views import TokenObtainPairView, TokenRefreshView, TokenVerifyView
from vibes_auth.viewsets import UserViewSet
app_name = "vibes_auth"
auth_router = DefaultRouter()
auth_router.register(r"users", UserViewSet, basename="users")

View file

@ -46,6 +46,7 @@ class TokenObtainPairView(TokenViewBase):
post: Handles HTTP POST requests for token retrieval. This method is
subject to rate limiting depending on the global DEBUG setting.
"""
serializer_class = TokenObtainPairSerializer # type: ignore
_serializer_class = TokenObtainPairSerializer # type: ignore
@ -80,6 +81,7 @@ class TokenRefreshView(TokenViewBase):
the request. Rate limit settings are defined depending on
whether the application is in DEBUG mode or not.
"""
serializer_class = TokenRefreshSerializer # type: ignore
_serializer_class = TokenRefreshSerializer # type: ignore
@ -101,6 +103,7 @@ class TokenVerifyView(TokenViewBase):
user data can also be returned. Errors during token validation result in an appropriate
error response.
"""
serializer_class = TokenVerifySerializer # type: ignore
_serializer_class = TokenVerifySerializer # type: ignore

View file

@ -78,6 +78,7 @@ class UserViewSet(
OverflowError, TypeError:
Raised for decoding or type conversion issues.
"""
serializer_class = UserSerializer
queryset = User.objects.filter(is_active=True)
permission_classes = [AllowAny]