From 2d5311702dd3d30735d571919c06adb99df27211 Mon Sep 17 00:00:00 2001 From: "arvinbehbahani562@gmail.com" Date: Wed, 13 May 2026 16:46:50 +0330 Subject: [PATCH] finished the addresses app --- addresses/admin.py | 3 +- addresses/api/serializers.py | 17 +++- addresses/api/views.py | 4 +- .../management/commands/address_faker.py | 76 ++++++++++++++++++ ...{seed_address.py => seed_province_city.py} | 0 addresses/models.py | 5 +- celerybeat-schedule | Bin 16384 -> 16384 bytes requirements.txt | 58 +++++++++---- 8 files changed, 142 insertions(+), 21 deletions(-) create mode 100644 addresses/management/commands/address_faker.py rename addresses/management/commands/{seed_address.py => seed_province_city.py} (100%) diff --git a/addresses/admin.py b/addresses/admin.py index 0ee1a39..f82ff37 100644 --- a/addresses/admin.py +++ b/addresses/admin.py @@ -16,7 +16,7 @@ class CityAdmin(admin.ModelAdmin): list_display = ( "city_name", "city_local_id", - "province" + "province", ) admin.site.register(City, CityAdmin) @@ -27,6 +27,7 @@ class AddressAdmin(admin.ModelAdmin): "address_detail", "province", "city", + "user__email", ] admin.site.register(Address, AddressAdmin) \ No newline at end of file diff --git a/addresses/api/serializers.py b/addresses/api/serializers.py index e882c34..47a2245 100644 --- a/addresses/api/serializers.py +++ b/addresses/api/serializers.py @@ -17,10 +17,13 @@ class CitySerializer(serializers.ModelSerializer): class AddressSerializer(serializers.ModelSerializer): province_name = serializers.CharField(source="province.province_name", read_only=True) city_name = serializers.CharField(source="city.city_name", read_only=True) + user_email = serializers.EmailField(source="user.email", read_only=True) + absolute_url = serializers.SerializerMethodField(method_name="get_absolute_url", read_only=True) + relative_url = serializers.URLField(source="get_absolute_relative_url") class Meta: model = Address - fields = ["province", "province_name", "city", "city_name", "postal_code", "address_detail", "user", "created_at", "updated_at"] - read_only_fields = ["user", "province_name", "city_name", "created_at", "updated_at"] + fields = ["province", "province_name", "city", "city_name", "postal_code", "address_detail", "relative_url", "absolute_url", "user_email", "created_at", "updated_at"] + read_only_fields = ["user_email", "absolute_url", "province_name", "city_name", "created_at", "updated_at"] def to_representation(self, instance): rep = super().to_representation(instance) @@ -30,5 +33,13 @@ class AddressSerializer(serializers.ModelSerializer): rep.pop("city_name") rep.pop("created_at") rep.pop("updated_at") + + else: + rep.pop("absolute_url") + rep.pop("relative_url") - return rep \ No newline at end of file + return rep + + def get_absolute_url(self, obj): + request = self.context.get("request") + return request.build_absolute_uri(obj.pk) diff --git a/addresses/api/views.py b/addresses/api/views.py index 3c94de2..42d5219 100644 --- a/addresses/api/views.py +++ b/addresses/api/views.py @@ -26,8 +26,8 @@ class AddressViewSet(viewsets.ModelViewSet): serializer_class = serializers.AddressSerializer def get_queryset(self): - user_id = self.request.user.id - return Address.objects.filter(user_id=user_id) + user = self.request.user + return Address.objects.filter(user=user) def perform_create(self, serializer): serializer.save( diff --git a/addresses/management/commands/address_faker.py b/addresses/management/commands/address_faker.py new file mode 100644 index 0000000..c97ae5b --- /dev/null +++ b/addresses/management/commands/address_faker.py @@ -0,0 +1,76 @@ +from django.core.management.base import BaseCommand +from faker import Faker +from django.contrib.auth import get_user_model +from random import choice, randint +from django.db.models import Q +from ...models import Address, Province, City + +user = get_user_model() + +class Command(BaseCommand): + help = "fake address creator" + + def __init__(self, stdout=None, stderr=None, no_color=False, force_color=False): + super().__init__(stdout, stderr, no_color, force_color) + self.faker = Faker() + + def handle(self, *args, **options): + + print("creating fake users...") + + user1 = user.objects.create_user( + phone_number=self.faker.phone_number(), + email=self.faker.email(), + username=self.faker.user_name(), + password="string123", + ) + + + user2 = user.objects.create_user( + phone_number=self.faker.phone_number(), + email=self.faker.email(), + username=self.faker.user_name(), + password="string123", + ) + + print("operation successful...") + + # print(City.objects.values_list("city_local_id", flat=True)[:10]) + + print("creating fake addresses") + for _ in range(10): + province = Province.objects.get(pk=randint(0, 30)) + city_list = list(City.objects.filter(province=province).values_list( + "city_local_id", + flat=True,)) + city = City.objects.get(Q(province=province) & Q(city_local_id=choice(city_list))) + address = Address.objects.create( + user=user1, + province=province, + city=city, + postal_code=self.faker.postalcode(), + address_detail=self.faker.address(), + ) + + for _ in range(5): + province = Province.objects.get(pk=randint(0, 30)) + city_list = City.objects.filter(province=province).values_list( + "city_local_id", + flat=True, + ) + city = City.objects.get(Q(province=province) & Q(city_local_id=choice(city_list))) + address = Address.objects.create( + user=user2, + province=province, + city=city, + postal_code=self.faker.postalcode(), + address_detail=self.faker.address(), + ) + + print("operation successful...") + + self.stdout.write( + self.style.SUCCESS("fake addresses and accounts created successfully...") + ) + + diff --git a/addresses/management/commands/seed_address.py b/addresses/management/commands/seed_province_city.py similarity index 100% rename from addresses/management/commands/seed_address.py rename to addresses/management/commands/seed_province_city.py diff --git a/addresses/models.py b/addresses/models.py index 6ea3ee1..73bb344 100644 --- a/addresses/models.py +++ b/addresses/models.py @@ -1,5 +1,6 @@ from django.db import models from config.settings import AUTH_USER_MODEL +from django.urls import reverse class Province(models.Model): province_id = models.IntegerField(primary_key=True) @@ -37,4 +38,6 @@ class Address(models.Model): def __str__(self) -> str: return f"{self.address_detail[:10]}..." - \ No newline at end of file + + def get_absolute_relative_url(self): + return reverse("addresses:address-api-urls:address-viewset-detail", kwargs={"pk": self.pk}) \ No newline at end of file diff --git a/celerybeat-schedule b/celerybeat-schedule index 785d55dac1b2234304b5459dbd21a6f4ee7d4124..b83df5528cce9917ede99a7c7b31ad90e296805e 100644 GIT binary patch delta 27 jcmZo@U~Fh$+|X{!#>>FKu=Mfdj|PE^Q#Ri>R^$Nyg0Tsd delta 27 icmZo@U~Fh$+|X{!#>l|Hz!W+8qd_3!gw6Mj6?p)24hUBO diff --git a/requirements.txt b/requirements.txt index 73eeaf3..8b0939b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,14 +1,44 @@ -Django>=5.0,<5.2 -djangorestframework>=3.14,<3.16 -djangorestframework-simplejwt>=5.3,<5.4 -django-cors-headers>=4.3,<4.5 -drf-spectacular>=0.27,<0.28 -drf-spectacular-sidecar>=2024.7.1,<2025 -celery[redis]>=5.3,<5.4 -redis>=5.0,<5.1 - -mysqlclient>=2.2,<2.3 -gunicorn>=22,<23 -python-dotenv>=1.0,<1.1 -requests>=2.31,<2.33 - +amqp==5.3.1 +asgiref==3.11.1 +async-timeout==5.0.1 +attrs==26.1.0 +billiard==4.2.4 +celery==5.3.6 +certifi==2026.4.22 +charset-normalizer==3.4.7 +click==8.3.3 +click-didyoumean==0.3.1 +click-plugins==1.1.1.2 +click-repl==0.3.0 +Django==5.1.15 +django-cors-headers==4.4.0 +djangorestframework==3.15.2 +djangorestframework-simplejwt==5.3.1 +drf-spectacular==0.27.2 +drf-spectacular-sidecar==2024.12.1 +Faker==40.15.0 +gunicorn==22.0.0 +idna==3.14 +inflection==0.5.1 +jsonschema==4.26.0 +jsonschema-specifications==2025.9.1 +kombu==5.6.2 +mysqlclient==2.2.8 +packaging==26.2 +prompt_toolkit==3.0.52 +PyJWT==2.12.1 +python-dateutil==2.9.0.post0 +python-dotenv==1.0.1 +PyYAML==6.0.3 +redis==5.0.8 +referencing==0.37.0 +requests==2.32.5 +rpds-py==0.30.0 +six==1.17.0 +sqlparse==0.5.5 +typing_extensions==4.15.0 +tzdata==2026.2 +uritemplate==4.2.0 +urllib3==2.7.0 +vine==5.1.0 +wcwidth==0.7.0