Banner api lari #10

Merged
admin merged 3 commits from feat/banner into main 2025-11-27 07:06:56 +00:00
21 changed files with 9428 additions and 53 deletions
Showing only changes of commit 900f23e5f6 - Show all commits

View File

@@ -1,4 +1,4 @@
#type: ignore
# type: ignore
import os
import pathlib
from typing import List, Union
@@ -37,19 +37,19 @@ PASSWORD_HASHERS = [
]
INSTALLED_APPS = [
"modeltranslation",
"unfold",
"unfold.contrib.filters",
"unfold.contrib.forms",
"unfold.contrib.guardian",
"unfold.contrib.simple_history",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
] + APPS
"modeltranslation",
"unfold",
"unfold.contrib.filters",
"unfold.contrib.forms",
"unfold.contrib.guardian",
"unfold.contrib.simple_history",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
] + APPS
MODULES = [app for app in MODULES if isinstance(app, str)]
@@ -72,7 +72,6 @@ if env.bool("SILK_ENABLED", False):
"silk.middleware.SilkyMiddleware",
]
ROOT_URLCONF = "config.urls"
TEMPLATES = [
@@ -119,7 +118,6 @@ DATE_FORMAT = "d.m.y"
TIME_FORMAT = "H:i:s"
DATE_INPUT_FORMATS = ["%d.%m.%Y", "%Y.%d.%m", "%Y.%d.%m"]
SEEDERS = ["core.apps.accounts.seeder.UserSeeder"]
STATICFILES_DIRS = [
@@ -156,8 +154,6 @@ SILKY_PYTHON_PROFILER = True
MODELTRANSLATION_LANGUAGES = ("uz", "ru", "en")
MODELTRANSLATION_DEFAULT_LANGUAGE = "uz"
JST_LANGUAGES = [
{
"code": "uz",

View File

@@ -1,7 +1,7 @@
from django.contrib import admin
from unfold.admin import ModelAdmin
from core.apps.accounts.models import SearchHistory
from core.apps.accounts.models import SearchHistory, UserLike
@admin.register(SearchHistory)
@@ -10,3 +10,11 @@ class SearchHistoryAdmin(ModelAdmin):
"id",
"__str__",
)
@admin.register(UserLike)
class UserLikeAdmin(ModelAdmin):
list_display = (
"id",
"__str__",
)

View File

@@ -0,0 +1,31 @@
# Generated by Django 5.2.7 on 2025-11-26 10:04
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0004_business_searchhistory'),
('api', '0013_alter_feedback_comment'),
]
operations = [
migrations.CreateModel(
name='UserLike',
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)),
('ad', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='likes', to='api.admodel', verbose_name='Ad')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='likes', to=settings.AUTH_USER_MODEL, verbose_name='User')),
],
options={
'verbose_name': 'User Like',
'verbose_name_plural': 'User Likes',
'db_table': 'user_like',
},
),
]

View File

@@ -0,0 +1,28 @@
# Generated by Django 5.2.7 on 2025-11-26 10:06
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('accounts', '0005_userlike'),
]
operations = [
migrations.RenameField(
model_name='business',
old_name='address_name',
new_name='address',
),
migrations.RenameField(
model_name='business',
old_name='latitude',
new_name='lat',
),
migrations.RenameField(
model_name='business',
old_name='longitude',
new_name='long',
),
]

View File

@@ -13,9 +13,9 @@ class Business(AbstractBaseModel):
facebook = models.CharField(max_length=255, verbose_name=_('Facebook'))
telegram = models.CharField(max_length=255, verbose_name=_('Telegram'))
bio = models.TextField(verbose_name=_('Bio'))
address_name = models.CharField(max_length=255, verbose_name=_('Address Name'))
longitude = models.FloatField(verbose_name=_('Longitude'))
latitude = models.FloatField(verbose_name=_('Latitude'))
address = models.CharField(max_length=255, verbose_name=_('Address Name'))
long = models.FloatField(verbose_name=_('Longitude'))
lat = models.FloatField(verbose_name=_('Latitude'))
def __str__(self):
return str(self.pk)

View File

@@ -3,6 +3,7 @@ from django.db import models
from ..choices import RoleChoice, AccountType
from ..managers import UserManager
from model_bakery import baker
class User(auth_models.AbstractUser):
@@ -22,5 +23,9 @@ class User(auth_models.AbstractUser):
USERNAME_FIELD = "phone"
objects = UserManager()
@classmethod
def _baker(cls):
return baker.make(cls)
def __str__(self):
return self.phone

View File

@@ -0,0 +1,23 @@
from django.contrib.auth import get_user_model
from django.db import models
from django_core.models.base import AbstractBaseModel
from django.utils.translation import gettext_lazy as _
from core.apps.api.models import AdModel
from model_bakery import baker
class UserLike(AbstractBaseModel):
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, verbose_name=_("User"), related_name="likes")
ad = models.ForeignKey(AdModel, on_delete=models.CASCADE, verbose_name=_("Ad"), related_name="likes")
@classmethod
def _baker(cls):
return baker.make(cls)
def __str__(self):
return str(self.pk)
class Meta:
db_table = "user_like"
verbose_name = _("User Like")
verbose_name_plural = _("User Likes")

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.2.7 on 2025-11-26 10:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0012_rename_command_feedback_comment'),
]
operations = [
migrations.AlterField(
model_name='feedback',
name='comment',
field=models.CharField(max_length=255, verbose_name='Comment'),
),
]

View File

@@ -1,3 +1,4 @@
from .category import * # noqa
from .search import * # noqa
from .ad import * # noqa
from .user import * # noqa

View File

@@ -0,0 +1 @@
from .ad_like import * # noqa

View File

@@ -0,0 +1,45 @@
from rest_framework import serializers
from core.apps.accounts.models import UserLike
from core.apps.api.models import AdModel
from core.apps.api.serializers.ad.home_api import ListHomeAdSerializer
from rest_framework.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
class BaseUserLikeSerializer(serializers.ModelSerializer):
ad = ListHomeAdSerializer(many=False, read_only=True)
class Meta:
model = UserLike
fields = [
"id",
"ad",
]
class ListUserLikeSerializer(BaseUserLikeSerializer):
class Meta(BaseUserLikeSerializer.Meta): ...
class RetrieveUserLikeSerializer(BaseUserLikeSerializer):
class Meta(BaseUserLikeSerializer.Meta): ...
class CreateUserLikeSerializer(BaseUserLikeSerializer):
ad = serializers.PrimaryKeyRelatedField(queryset=AdModel.objects.all())
class Meta(BaseUserLikeSerializer.Meta): ...
def validate(self, data):
user = self.context["request"].user
ad = data["ad"]
if UserLike.objects.filter(user=user, ad=ad).exists():
raise ValidationError({"detail": _("Siz bu elonga allaqachon like bosgansiz.")})
return data
def create(self, validated_data):
validated_data['user'] = self.context['request'].user
like = UserLike.objects.create(**validated_data)
return like

View File

@@ -1,3 +1,4 @@
from .category import * # noqa
from .ad import * # noqa
from .search import * # noqa
from .user import * # noqa

View File

@@ -0,0 +1 @@
from .test_user_like import * # noqa

View File

@@ -0,0 +1,62 @@
import pytest
from django.urls import reverse
from rest_framework.test import APIClient
from core.apps.accounts.models import UserLike, AdModel
@pytest.fixture
def instance(db):
return UserLike._baker()
@pytest.fixture
def ad(db):
return AdModel._baker()
@pytest.fixture
def api_client(instance):
client = APIClient()
client.force_authenticate(user=instance.user)
return client, instance
@pytest.fixture
def data(api_client):
client, instance = api_client
return (
{
"list": reverse("user-like-list"),
"retrieve": reverse("user-like-detail", kwargs={"pk": instance.pk}),
"retrieve-not-found": reverse("user-like-detail", kwargs={"pk": 1000}),
},
client,
instance,
)
@pytest.mark.django_db
def test_list(data):
urls, client, _ = data
response = client.get(urls["list"])
data_resp = response.json()
assert response.status_code == 200
assert data_resp["status"] is True
@pytest.mark.django_db
def test_create(data,ad):
urls, client, instance = data
response = client.post(urls["list"], data={"ad": ad.pk})
data_resp = response.json()
print(data_resp)
assert response.status_code == 201
assert data_resp["status"] is True
@pytest.mark.django_db
def test_destroy(data):
urls, client, _ = data
response = client.delete(urls["retrieve"])
assert response.status_code == 204

View File

@@ -1,9 +1,11 @@
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from core.apps.api.views import CategoryHomeApiViewSet, CategoryViewSet, HomeAdApiView, SearchHistoryViewSet
from core.apps.api.views import CategoryHomeApiViewSet, CategoryViewSet, HomeAdApiView, SearchHistoryViewSet, \
UserLikeViewSet
router = DefaultRouter()
router.register("user-like", UserLikeViewSet, basename="user-like")
router.register("category", CategoryViewSet, basename="category")
router.register("category-home", CategoryHomeApiViewSet, basename="category-home")
router.register("search-history", SearchHistoryViewSet, basename="search-history")

View File

@@ -1,4 +1,4 @@
from .category import * # noqa
from .search import * # noqa
from .ad import * # noqa
from .user import * # noqa

View File

@@ -0,0 +1 @@
from .ad_like import * # noqa

View File

@@ -0,0 +1,28 @@
from rest_framework import mixins
from rest_framework.viewsets import GenericViewSet
from django_core.mixins.base import BaseViewSetMixin
from drf_spectacular.utils import extend_schema
from rest_framework.permissions import IsAuthenticated
from core.apps.accounts.models import UserLike
from core.apps.api.serializers.user.ad_like import (
ListUserLikeSerializer,
CreateUserLikeSerializer,
)
@extend_schema(tags=['User Like'])
class UserLikeViewSet(BaseViewSetMixin, mixins.ListModelMixin, mixins.CreateModelMixin,
mixins.DestroyModelMixin, GenericViewSet):
serializer_class = ListUserLikeSerializer
permission_classes = [IsAuthenticated]
http_method_names = ['get', 'post', 'delete']
action_permission_classes = {}
action_serializer_class = {
'list': ListUserLikeSerializer,
'create': CreateUserLikeSerializer,
}
def get_queryset(self):
queryset = UserLike.objects.filter(user=self.request.user).order_by('-id')
return queryset

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff