22 changed files with 572 additions and 9 deletions
-
17apps/account/migrations/0007_user_user_agent.py
-
22apps/account/migrations/0008_loginhistory_device_os_loginhistory_user_agent.py
-
17apps/account/migrations/0009_user_client_ip.py
-
21apps/account/migrations/0010_alter_user_device_os.py
-
9apps/account/models/user.py
-
17apps/account/serializers/user.py
-
1apps/account/urls.py
-
98apps/account/views/user.py
-
2apps/article/views.py
-
1apps/blog/views.py
-
22apps/hadis/migrations/0005_auto_20251209_1620.py
-
14apps/hadis/serializers/category.py
-
41apps/hadis/serializers/hadis.py
-
59apps/hadis/serializers/reference.py
-
11apps/hadis/urls.py
-
18apps/hadis/views/category.py
-
35apps/hadis/views/reference.py
-
17apps/hadis/views/transmitter.py
-
3apps/video/views.py
-
55fix_db.py
-
41fix_transmitter_opinion.py
-
60test_serializer.py
@ -0,0 +1,17 @@ |
|||||
|
# Generated by Django 5.2.9 on 2025-12-09 15:13 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
dependencies = [ |
||||
|
("account", "0006_auto_20251006_1101"), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name="user", |
||||
|
name="user_agent", |
||||
|
field=models.TextField(blank=True, null=True, verbose_name="user agent"), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,22 @@ |
|||||
|
# Generated by Django 5.2.9 on 2025-12-09 15:13 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
dependencies = [ |
||||
|
("account", "0007_user_user_agent"), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name="loginhistory", |
||||
|
name="device_os", |
||||
|
field=models.CharField(blank=True, max_length=16, null=True), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name="loginhistory", |
||||
|
name="user_agent", |
||||
|
field=models.TextField(blank=True, null=True, verbose_name="user agent"), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,17 @@ |
|||||
|
# Generated by Django 5.2.9 on 2025-12-09 15:37 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
dependencies = [ |
||||
|
("account", "0008_loginhistory_device_os_loginhistory_user_agent"), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name="user", |
||||
|
name="client_ip", |
||||
|
field=models.TextField(blank=True, null=True, verbose_name="client ip"), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,21 @@ |
|||||
|
# Generated by Django 5.2.9 on 2025-12-09 15:52 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
dependencies = [ |
||||
|
("account", "0009_user_client_ip"), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name="user", |
||||
|
name="device_os", |
||||
|
field=models.CharField( |
||||
|
choices=[("android", "android"), ("apple", "apple"), ("web", "web")], |
||||
|
max_length=16, |
||||
|
null=True, |
||||
|
), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,22 @@ |
|||||
|
# Generated by Django 5.2.9 on 2025-12-09 16:20 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
dependencies = [ |
||||
|
("hadis", "0004_hadiscollection_hadisincollection"), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='hadiscategory', |
||||
|
name='description', |
||||
|
field=models.TextField(blank=True, null=True, verbose_name='Description'), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='hadissect', |
||||
|
name='description', |
||||
|
field=models.TextField(blank=True, null=True, verbose_name='Description'), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,59 @@ |
|||||
|
from rest_framework import serializers |
||||
|
|
||||
|
from ..serializers import HadisListSerializer |
||||
|
from ..models import BookReference , BookAuthor , BookReferenceImage |
||||
|
|
||||
|
class BookAuthorSerializer(serializers.ModelSerializer): |
||||
|
class Meta: |
||||
|
model = BookAuthor |
||||
|
fields = '__all__' |
||||
|
|
||||
|
class BookReferenceImageSerializer(serializers.ModelSerializer): |
||||
|
class Meta: |
||||
|
model = BookReferenceImage |
||||
|
fields = '__all__' |
||||
|
|
||||
|
class BookReferenceSerializer(serializers.ModelSerializer): |
||||
|
image = BookReferenceImageSerializer( |
||||
|
many= True , |
||||
|
read_only = True , |
||||
|
source = 'bookreference_set' |
||||
|
) |
||||
|
volume_count = serializers.SerializerMethodField() |
||||
|
class Meta: |
||||
|
model = BookReference |
||||
|
fields = ['id','title','description','rate','image','volume_count'] |
||||
|
def get_volume_count(self,obj): |
||||
|
request = self.context.get('request') |
||||
|
return BookReference.objects.filter(title=obj.title).count() |
||||
|
|
||||
|
class BookDetailSerializer(serializers.ModelSerializer): |
||||
|
|
||||
|
author = BookAuthorSerializer( |
||||
|
read_only = True , |
||||
|
source = 'bookauthor_set' |
||||
|
) |
||||
|
image = BookReferenceImageSerializer( |
||||
|
many= True , |
||||
|
read_only = True , |
||||
|
source = 'bookreference_set' |
||||
|
) |
||||
|
volume_count = serializers.SerializerMethodField() |
||||
|
|
||||
|
hadis = HadisListSerializer( |
||||
|
many=True, |
||||
|
read_only=True, |
||||
|
source='hadisreference_set' |
||||
|
) |
||||
|
|
||||
|
class Meta: |
||||
|
model = BookReference |
||||
|
fields = '__all__' |
||||
|
def get_volume_count(self,obj): |
||||
|
request = self.context.get('request') |
||||
|
return BookReference.objects.filter(title=obj.title).count() |
||||
|
|
||||
|
# def create(self , validated_data): |
||||
|
# author = validated_data.pop('author') |
||||
|
# book = BookReference.objects.create(**validated_data) |
||||
|
# for author in author |
||||
@ -0,0 +1,35 @@ |
|||||
|
from rest_framework.generics import ListAPIView, RetrieveAPIView |
||||
|
from ..models import BookReference , BookAuthor , BookReferenceImage |
||||
|
from ..serializers.reference import BookAuthorSerializer, BookDetailSerializer , BookReferenceSerializer |
||||
|
from utils.pagination import NoPagination |
||||
|
|
||||
|
|
||||
|
|
||||
|
class BookReferencesView(ListAPIView): |
||||
|
queryset = BookReference.objects.all() |
||||
|
serializer_class = BookReferenceSerializer |
||||
|
pagination_class = NoPagination |
||||
|
|
||||
|
|
||||
|
class BookAuthorView(ListAPIView): |
||||
|
queryset = BookAuthor.objects.all() |
||||
|
serializer_class = BookAuthorSerializer |
||||
|
pagination_class = NoPagination |
||||
|
|
||||
|
class BookDetailView(RetrieveAPIView): |
||||
|
serializer_class = BookDetailSerializer |
||||
|
lookup_field = 'id' |
||||
|
lookup_url_kwarg = 'bookreference_id' |
||||
|
|
||||
|
def get_queryset(self): |
||||
|
return BookReference.objects.all().prefetch_related( |
||||
|
'bookauthor_set__name', |
||||
|
'bookreferenceimage_set__image', |
||||
|
) |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
# class BookReferencesView(ListAPIView): |
||||
|
# pass |
||||
@ -0,0 +1,17 @@ |
|||||
|
from django.contrib.admin.utils import lookup_field |
||||
|
from rest_framework.generics import ListAPIView , RetrieveAPIView |
||||
|
from ..models import Transmitters , TransmitterOpinion |
||||
|
from ..serializers import TransmitterSerializer , TransmitterDetailSerializer |
||||
|
from utils.pagination import NoPagination |
||||
|
class TransmitterView(ListAPIView): |
||||
|
queryset = Transmitters.objects.all() |
||||
|
serializer_class = TransmitterSerializer |
||||
|
pagination_class = NoPagination |
||||
|
|
||||
|
class TransmitterDetailView(RetrieveAPIView): |
||||
|
serializer_class = TransmitterDetailSerializer |
||||
|
lookup_field = 'id' |
||||
|
lookup_url_kwarg = 'transmitters_id' |
||||
|
def get_queryset(self): |
||||
|
input = self.kwargs['transmitters_id'] |
||||
|
return Transmitters.objects.filter(id=input) |
||||
@ -0,0 +1,55 @@ |
|||||
|
#!/usr/bin/env python |
||||
|
import psycopg2 |
||||
|
|
||||
|
# Connect directly to the database |
||||
|
try: |
||||
|
conn = psycopg2.connect( |
||||
|
dbname="imam_javad_db", |
||||
|
user="postgres", |
||||
|
password="123456789", |
||||
|
host="localhost", |
||||
|
port="5432" |
||||
|
) |
||||
|
cursor = conn.cursor() |
||||
|
print("Connected to database successfully") |
||||
|
except Exception as e: |
||||
|
print(f"Failed to connect to database: {e}") |
||||
|
exit(1) |
||||
|
|
||||
|
# Add missing transmitter fields |
||||
|
fields_to_add = [ |
||||
|
('kunya', 'VARCHAR(255) NULL'), |
||||
|
('known_as', 'VARCHAR(255) NULL'), |
||||
|
('nickname', 'VARCHAR(255) NULL'), |
||||
|
('origin', 'VARCHAR(255) NULL'), |
||||
|
('lived_in', 'VARCHAR(255) NULL'), |
||||
|
('died_in', 'VARCHAR(255) NULL'), |
||||
|
('age_at_death', 'INTEGER NULL'), |
||||
|
('reliability', "VARCHAR(20) DEFAULT 'unknown'"), |
||||
|
('madhhab', "VARCHAR(20) DEFAULT 'unknown'"), |
||||
|
('in_sahih_bukhari', 'BOOLEAN DEFAULT FALSE'), |
||||
|
('in_sahih_muslim', 'BOOLEAN DEFAULT FALSE'), |
||||
|
('created_at', 'TIMESTAMP WITH TIME ZONE DEFAULT NOW()'), |
||||
|
('updated_at', 'TIMESTAMP WITH TIME ZONE DEFAULT NOW()'), |
||||
|
] |
||||
|
|
||||
|
print("Adding missing transmitter fields...") |
||||
|
for field_name, field_type in fields_to_add: |
||||
|
try: |
||||
|
cursor.execute(f'ALTER TABLE hadis_transmitters ADD COLUMN IF NOT EXISTS {field_name} {field_type};') |
||||
|
print(f'✓ Added column: {field_name}') |
||||
|
except Exception as e: |
||||
|
print(f'✗ Error adding {field_name}: {e}') |
||||
|
|
||||
|
conn.commit() |
||||
|
print('All missing transmitter fields added successfully!') |
||||
|
|
||||
|
# Test if the fields exist |
||||
|
cursor.execute("SELECT column_name FROM information_schema.columns WHERE table_name = 'hadis_transmitters' AND column_name = 'kunya';") |
||||
|
result = cursor.fetchone() |
||||
|
if result: |
||||
|
print('✓ kunya column exists in database') |
||||
|
else: |
||||
|
print('✗ kunya column not found') |
||||
|
|
||||
|
conn.close() |
||||
@ -0,0 +1,41 @@ |
|||||
|
#!/usr/bin/env python |
||||
|
import psycopg2 |
||||
|
|
||||
|
# Connect directly to the database |
||||
|
try: |
||||
|
conn = psycopg2.connect( |
||||
|
dbname="imam_javad_db", |
||||
|
user="postgres", |
||||
|
password="123456789", |
||||
|
host="localhost", |
||||
|
port="5432" |
||||
|
) |
||||
|
cursor = conn.cursor() |
||||
|
print("Connected to database successfully") |
||||
|
except Exception as e: |
||||
|
print(f"Failed to connect to database: {e}") |
||||
|
exit(1) |
||||
|
|
||||
|
# Create the missing TransmitterOpinion table |
||||
|
sql = """ |
||||
|
CREATE TABLE IF NOT EXISTS hadis_transmitteropinion ( |
||||
|
id BIGSERIAL PRIMARY KEY, |
||||
|
scholar_name VARCHAR(255) NOT NULL, |
||||
|
opinion_text TEXT NOT NULL, |
||||
|
status VARCHAR(20) DEFAULT 'confirmed', |
||||
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), |
||||
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), |
||||
|
transmitter_id BIGINT REFERENCES hadis_transmitters(id) ON DELETE CASCADE |
||||
|
); |
||||
|
""" |
||||
|
|
||||
|
try: |
||||
|
cursor.execute(sql) |
||||
|
print("✓ Created hadis_transmitteropinion table") |
||||
|
except Exception as e: |
||||
|
print(f"✗ Error creating table: {e}") |
||||
|
|
||||
|
conn.commit() |
||||
|
conn.close() |
||||
|
|
||||
|
print("TransmitterOpinion table creation completed!") |
||||
@ -0,0 +1,60 @@ |
|||||
|
#!/usr/bin/env python |
||||
|
import os |
||||
|
import sys |
||||
|
import django |
||||
|
from pathlib import Path |
||||
|
|
||||
|
# Set up Django environment manually |
||||
|
sys.path.insert(0, str(Path(__file__).parent)) |
||||
|
|
||||
|
try: |
||||
|
# Try to avoid the environ import issue |
||||
|
import importlib |
||||
|
sys.modules['environ'] = importlib.util.spec_from_loader('environ', None) |
||||
|
|
||||
|
from django.conf import settings |
||||
|
if not settings.configured: |
||||
|
settings.configure( |
||||
|
DATABASES={ |
||||
|
'default': { |
||||
|
'ENGINE': 'django.db.backends.postgresql', |
||||
|
'NAME': 'imam_javad_db', |
||||
|
'USER': 'postgres', |
||||
|
'PASSWORD': '123456789', |
||||
|
'HOST': 'localhost', |
||||
|
'PORT': '5432', |
||||
|
} |
||||
|
}, |
||||
|
INSTALLED_APPS=[ |
||||
|
'django.contrib.contenttypes', |
||||
|
'django.contrib.auth', |
||||
|
'apps.hadis', |
||||
|
], |
||||
|
USE_TZ=True, |
||||
|
SECRET_KEY='temp-key-for-test', |
||||
|
) |
||||
|
|
||||
|
django.setup() |
||||
|
|
||||
|
from apps.hadis.models import Transmitters |
||||
|
from apps.hadis.serializers.hadis import TransmitterDetailSerializer |
||||
|
|
||||
|
transmitter = Transmitters.objects.first() |
||||
|
if transmitter: |
||||
|
serializer = TransmitterDetailSerializer(transmitter) |
||||
|
data = serializer.data |
||||
|
print('✓ Serializer works!') |
||||
|
print(f'Has opinions field: {"opinions" in data}') |
||||
|
print(f'Has hadis_transmissions field: {"hadis_transmissions" in data}') |
||||
|
if 'opinions' in data: |
||||
|
print(f'Opinions count: {len(data["opinions"])}') |
||||
|
if 'hadis_transmissions' in data: |
||||
|
print(f'Hadis transmissions count: {len(data["hadis_transmissions"])}') |
||||
|
print('Test completed successfully!') |
||||
|
else: |
||||
|
print('No transmitters found') |
||||
|
|
||||
|
except Exception as e: |
||||
|
print(f'✗ Error: {e}') |
||||
|
import traceback |
||||
|
traceback.print_exc() |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue