4 changed files with 153 additions and 10 deletions
-
74backend/ads/migrations/0001_initial.py
-
51backend/ads/serializers.py
-
11backend/ads/urls.py
-
27backend/ads/views.py
@ -0,0 +1,74 @@ |
|||
# Generated by Django 6.0.8 on 2026-08-08 07:53 |
|||
|
|||
import django.db.models.deletion |
|||
import uuid |
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
initial = True |
|||
|
|||
dependencies = [ |
|||
('crawler', '0001_initial'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.CreateModel( |
|||
name='Ad', |
|||
fields=[ |
|||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), |
|||
('divar_token', models.CharField(max_length=50, unique=True)), |
|||
('title', models.CharField(max_length=255)), |
|||
('description', models.TextField()), |
|||
('price', models.CharField(blank=True, max_length=100, null=True)), |
|||
('category', models.CharField(blank=True, max_length=100, null=True)), |
|||
('images', models.JSONField(default=list)), |
|||
('url', models.URLField()), |
|||
('created_at', models.DateTimeField(auto_now_add=True)), |
|||
('published_at', models.DateTimeField(blank=True, null=True)), |
|||
], |
|||
options={ |
|||
'indexes': [models.Index(fields=['created_at'], name='ads_ad_created_9f5b83_idx')], |
|||
}, |
|||
), |
|||
migrations.CreateModel( |
|||
name='AdEvaluation', |
|||
fields=[ |
|||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), |
|||
('is_flagged', models.BooleanField(default=False)), |
|||
('reason', models.TextField(blank=True, null=True)), |
|||
('confidence', models.FloatField(blank=True, null=True)), |
|||
('extracted_fields', models.JSONField(default=dict)), |
|||
('evaluated_at', models.DateTimeField(auto_now_add=True)), |
|||
('ad', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='evaluations', to='ads.ad')), |
|||
('crawl_task', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='evaluations', to='crawler.crawltask')), |
|||
], |
|||
), |
|||
migrations.CreateModel( |
|||
name='NotificationLog', |
|||
fields=[ |
|||
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), |
|||
('channel_id', models.CharField(max_length=100)), |
|||
('sent_at', models.DateTimeField(auto_now_add=True)), |
|||
('status', models.CharField(choices=[('SENT', 'Sent'), ('FAILED', 'Failed')], max_length=20)), |
|||
('error_message', models.TextField(blank=True, null=True)), |
|||
('evaluation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', to='ads.adevaluation')), |
|||
], |
|||
options={ |
|||
'abstract': False, |
|||
}, |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='adevaluation', |
|||
index=models.Index(fields=['is_flagged'], name='ads_adevalu_is_flag_1e9b55_idx'), |
|||
), |
|||
migrations.AddIndex( |
|||
model_name='adevaluation', |
|||
index=models.Index(fields=['evaluated_at'], name='ads_adevalu_evaluat_9e55c2_idx'), |
|||
), |
|||
migrations.AddConstraint( |
|||
model_name='adevaluation', |
|||
constraint=models.UniqueConstraint(fields=('crawl_task', 'ad'), name='unique_crawl_task_ad'), |
|||
), |
|||
] |
|||
@ -0,0 +1,51 @@ |
|||
from rest_framework import serializers |
|||
from .models import Ad, AdEvaluation, NotificationLog |
|||
|
|||
class AdSerializer(serializers.ModelSerializer): |
|||
class Meta: |
|||
model = Ad |
|||
fields = [ |
|||
'id', |
|||
'divar_token', |
|||
'title', |
|||
'description', |
|||
'price', |
|||
'category', |
|||
'images', |
|||
'url', |
|||
'created_at', |
|||
'published_at', |
|||
] |
|||
read_only_fields = ['id', 'created_at'] |
|||
|
|||
|
|||
class AdEvaluationSerializer(serializers.ModelSerializer): |
|||
ad = AdSerializer(read_only=True) |
|||
|
|||
class Meta: |
|||
model = AdEvaluation |
|||
fields = [ |
|||
'id', |
|||
'crawl_task', |
|||
'ad', |
|||
'is_flagged', |
|||
'reason', |
|||
'confidence', |
|||
'extracted_fields', |
|||
'evaluated_at', |
|||
] |
|||
read_only_fields = ['id', 'evaluated_at'] |
|||
|
|||
|
|||
class NotificationLogSerializer(serializers.ModelSerializer): |
|||
class Meta: |
|||
model = NotificationLog |
|||
fields = [ |
|||
'id', |
|||
'evaluation', |
|||
'channel_id', |
|||
'sent_at', |
|||
'status', |
|||
'error_message', |
|||
] |
|||
read_only_fields = ['id', 'sent_at'] |
|||
@ -1,6 +1,11 @@ |
|||
from django.urls import path |
|||
from .views import AdsView |
|||
from django.urls import path, include |
|||
from rest_framework.routers import DefaultRouter |
|||
from .views import AdEvaluationViewSet |
|||
|
|||
router = DefaultRouter() |
|||
router.register(r'', AdEvaluationViewSet, basename='ads') |
|||
|
|||
urlpatterns = [ |
|||
path('', AdsView.as_view()), |
|||
path('', include(router.urls)), |
|||
] |
|||
|
|||
@ -1,10 +1,23 @@ |
|||
from django.shortcuts import render |
|||
from rest_framework.views import APIView |
|||
from rest_framework.response import Response |
|||
from rest_framework import viewsets |
|||
from .models import AdEvaluation |
|||
from .serializers import AdEvaluationSerializer |
|||
|
|||
# Create your views here. |
|||
class AdEvaluationViewSet(viewsets.ReadOnlyModelViewSet): |
|||
""" |
|||
ViewSet for listing and viewing Ad Evaluations. |
|||
Supports filtering by crawl_task (UUID) and is_flagged (boolean). |
|||
""" |
|||
serializer_class = AdEvaluationSerializer |
|||
|
|||
class AdsView(APIView): |
|||
def get(self, request): |
|||
return Response({'message': 'Hello from Ads'}) |
|||
def get_queryset(self): |
|||
queryset = AdEvaluation.objects.all().select_related('ad', 'crawl_task').order_by('-evaluated_at') |
|||
crawl_task_id = self.request.query_params.get('crawl_task') |
|||
is_flagged = self.request.query_params.get('is_flagged') |
|||
|
|||
if crawl_task_id: |
|||
queryset = queryset.filter(crawl_task_id=crawl_task_id) |
|||
if is_flagged is not None: |
|||
is_flagged_bool = is_flagged.lower() in ('true', '1', 't') |
|||
queryset = queryset.filter(is_flagged=is_flagged_bool) |
|||
|
|||
return queryset |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue