first commit
This commit is contained in:
0
portfolio/__init__.py
Normal file
0
portfolio/__init__.py
Normal file
BIN
portfolio/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
portfolio/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
BIN
portfolio/__pycache__/admin.cpython-314.pyc
Normal file
BIN
portfolio/__pycache__/admin.cpython-314.pyc
Normal file
Binary file not shown.
BIN
portfolio/__pycache__/apps.cpython-314.pyc
Normal file
BIN
portfolio/__pycache__/apps.cpython-314.pyc
Normal file
Binary file not shown.
BIN
portfolio/__pycache__/models.cpython-314.pyc
Normal file
BIN
portfolio/__pycache__/models.cpython-314.pyc
Normal file
Binary file not shown.
BIN
portfolio/__pycache__/serializers.cpython-314.pyc
Normal file
BIN
portfolio/__pycache__/serializers.cpython-314.pyc
Normal file
Binary file not shown.
BIN
portfolio/__pycache__/signals.cpython-314.pyc
Normal file
BIN
portfolio/__pycache__/signals.cpython-314.pyc
Normal file
Binary file not shown.
BIN
portfolio/__pycache__/urls.cpython-314.pyc
Normal file
BIN
portfolio/__pycache__/urls.cpython-314.pyc
Normal file
Binary file not shown.
BIN
portfolio/__pycache__/views.cpython-314.pyc
Normal file
BIN
portfolio/__pycache__/views.cpython-314.pyc
Normal file
Binary file not shown.
114
portfolio/admin.py
Normal file
114
portfolio/admin.py
Normal file
@@ -0,0 +1,114 @@
|
||||
from django.contrib import admin
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from portfolio.models import Portfolio, Category
|
||||
|
||||
|
||||
# Register your models here.
|
||||
class CategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ('title', 'parent_category', 'category_image', 'is_active', 'order', 'slug', 'created_at')
|
||||
list_filter = ('is_active', 'created_at', 'parent')
|
||||
search_fields = ('title', 'slug', 'keywords', 'description')
|
||||
list_editable = ('is_active', 'order')
|
||||
readonly_fields = ('created_at', 'updated_at')
|
||||
prepopulated_fields = {'slug': ('title',)}
|
||||
|
||||
fieldsets = (
|
||||
('Genel Bilgiler', {
|
||||
'fields': ('title', 'parent', 'slug')
|
||||
}),
|
||||
('SEO & Açıklama', {
|
||||
'fields': ('keywords', 'description')
|
||||
}),
|
||||
('Görsel', {
|
||||
'fields': ('image',)
|
||||
}),
|
||||
('Ayarlar', {
|
||||
'fields': ('order', 'is_active')
|
||||
}),
|
||||
('Tarihler', {
|
||||
'fields': ('created_at', 'updated_at'),
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Category
|
||||
|
||||
def parent_category(self, obj):
|
||||
if obj.parent:
|
||||
return obj.parent.title
|
||||
return "Ana Kategori"
|
||||
|
||||
parent_category.short_description = 'Üst Kategori'
|
||||
|
||||
def category_image(self, obj):
|
||||
if obj.image:
|
||||
return mark_safe(
|
||||
'<img src="{}" width="50" height="50" style="object-fit: cover; border-radius: 5px;" title="{}" />'.format(
|
||||
obj.image.url, obj.title))
|
||||
return mark_safe('<span style="color: #999;">Resim Yok</span>')
|
||||
|
||||
category_image.short_description = 'Görsel'
|
||||
|
||||
|
||||
admin.site.register(Category, CategoryAdmin)
|
||||
|
||||
|
||||
class PortfolioAdmin(admin.ModelAdmin):
|
||||
list_display = ('get_portfolio_title', 'portfolio_image', 'portfolio_categories', 'is_active', 'created_at')
|
||||
list_filter = ('is_active', 'created_at', 'categories')
|
||||
search_fields = ('url',)
|
||||
list_editable = ('is_active',)
|
||||
readonly_fields = ('created_at', 'updated_at')
|
||||
filter_horizontal = ('categories',)
|
||||
|
||||
fieldsets = (
|
||||
('Portfolio Bilgileri', {
|
||||
'fields': ('url', 'categories')
|
||||
}),
|
||||
('Görsel', {
|
||||
'fields': ('image',)
|
||||
}),
|
||||
('Ayarlar', {
|
||||
'fields': ('is_active',)
|
||||
}),
|
||||
('Tarihler', {
|
||||
'fields': ('created_at', 'updated_at'),
|
||||
'classes': ('collapse',)
|
||||
}),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Portfolio
|
||||
|
||||
def get_portfolio_title(self, obj):
|
||||
if obj.url:
|
||||
return obj.url[:50] + '...' if len(obj.url) > 50 else obj.url
|
||||
return f"Portfolio #{obj.id}"
|
||||
|
||||
get_portfolio_title.short_description = 'Portfolio'
|
||||
|
||||
def portfolio_image(self, obj):
|
||||
if obj.image:
|
||||
return mark_safe(
|
||||
'<a href="{}" target="_blank"><img src="{}" width="80" height="60" style="object-fit: cover; border-radius: 5px; cursor: pointer;" title="Büyük görseli görmek için tıklayın" /></a>'.format(
|
||||
obj.image.url, obj.image.url))
|
||||
return mark_safe('<span style="color: #999;">Resim Yok</span>')
|
||||
|
||||
portfolio_image.short_description = 'Görsel'
|
||||
|
||||
def portfolio_categories(self, obj):
|
||||
categories = obj.categories.all()
|
||||
if categories:
|
||||
html = '<ul style="margin: 0; padding-left: 20px;">'
|
||||
for category in categories:
|
||||
html += f'<li>{category.title}</li>'
|
||||
html += '</ul>'
|
||||
return mark_safe(html)
|
||||
return mark_safe('<span style="color: #999;">Kategori Yok</span>')
|
||||
|
||||
portfolio_categories.short_description = 'Kategoriler'
|
||||
|
||||
|
||||
admin.site.register(Portfolio, PortfolioAdmin)
|
||||
8
portfolio/apps.py
Normal file
8
portfolio/apps.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PortfolioConfig(AppConfig):
|
||||
name = 'portfolio'
|
||||
|
||||
def ready(self):
|
||||
import portfolio.signals
|
||||
63
portfolio/management/commands/create_fake_portfolios.py
Normal file
63
portfolio/management/commands/create_fake_portfolios.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import random
|
||||
import io
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.core.files.base import ContentFile
|
||||
from faker import Faker
|
||||
from PIL import Image, ImageDraw
|
||||
from portfolio.models import Portfolio, Category
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Creates fake portfolio items with images using existing categories'
|
||||
|
||||
def generate_image(self, width, height, format='PNG'):
|
||||
"""Generates a random image."""
|
||||
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
||||
image = Image.new('RGB', (width, height), color)
|
||||
draw = ImageDraw.Draw(image)
|
||||
|
||||
# Draw some random shapes
|
||||
for _ in range(10):
|
||||
shape_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
||||
x1 = random.randint(0, width)
|
||||
y1 = random.randint(0, height)
|
||||
x2 = random.randint(0, width)
|
||||
y2 = random.randint(0, height)
|
||||
# Ensure coordinates are in the correct order (x0, y0, x1, y1)
|
||||
draw.rectangle(
|
||||
[min(x1, x2), min(y1, y2), max(x1, x2), max(y1, y2)],
|
||||
fill=shape_color,
|
||||
outline=None
|
||||
)
|
||||
|
||||
img_io = io.BytesIO()
|
||||
image.save(img_io, format=format)
|
||||
return ContentFile(img_io.getvalue(), name=f'fake_image.{format.lower()}')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
fake = Faker()
|
||||
|
||||
# Fetch existing categories
|
||||
categories = list(Category.objects.all())
|
||||
|
||||
if not categories:
|
||||
self.stdout.write(self.style.WARNING('No categories found. Please create some categories first.'))
|
||||
return
|
||||
|
||||
self.stdout.write(f'Found {len(categories)} categories. Creating portfolios...')
|
||||
|
||||
for i in range(20):
|
||||
portfolio = Portfolio(
|
||||
url=fake.url(),
|
||||
is_active=True,
|
||||
)
|
||||
# Portfolio image: 640x481 (saving as PNG, model might convert to avif)
|
||||
image_content = self.generate_image(640, 481, 'PNG')
|
||||
portfolio.image.save(f'port_{i}.png', image_content, save=False)
|
||||
portfolio.save()
|
||||
|
||||
# Assign random existing categories
|
||||
# Ensure we don't try to sample more categories than exist
|
||||
num_categories = min(len(categories), random.randint(1, 3))
|
||||
portfolio.categories.set(random.sample(categories, k=num_categories))
|
||||
|
||||
self.stdout.write(self.style.SUCCESS('Successfully created fake portfolio items with images using existing categories.'))
|
||||
60
portfolio/migrations/0001_initial.py
Normal file
60
portfolio/migrations/0001_initial.py
Normal file
@@ -0,0 +1,60 @@
|
||||
# Generated by Django 6.0 on 2026-01-14 10:41
|
||||
|
||||
import autoslug.fields
|
||||
import core.utils
|
||||
import django.db.models.deletion
|
||||
import imagekit.models.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Category',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=254, verbose_name='Kategori')),
|
||||
('keywords', models.CharField(max_length=254, verbose_name='Seo Kelimeleri Aralarına Virgül Koyunuz')),
|
||||
('description', models.CharField(max_length=254, verbose_name='Açıklama')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Oluşturulma Tarihi')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Güncelleme Tarihi')),
|
||||
('is_active', models.BooleanField(choices=[(True, 'Evet'), (False, 'Hayır')], default=True, verbose_name='Yayındamı')),
|
||||
('order', models.IntegerField(db_index=True, default=1, verbose_name='Görüntülenme Sırası')),
|
||||
('slug', autoslug.fields.AutoSlugField(blank=True, editable=True, max_length=250, populate_from='title', unique=True)),
|
||||
('image', imagekit.models.fields.ProcessedImageField(blank=True, null=True, upload_to=core.utils.UniquePathAndRename('uploads/category'), verbose_name='Resim 630 x 653 Olmali ve Transparan PNG Olmali')),
|
||||
('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='child', to='portfolio.category', verbose_name='Üst Kategorisi')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Portfolio Kategori',
|
||||
'verbose_name_plural': 'Portfolio Kategorilerileri',
|
||||
'db_table': 'p_categories',
|
||||
'ordering': ['order'],
|
||||
'unique_together': {('slug', 'parent')},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Portfolio',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('url', models.URLField(blank=True, null=True, verbose_name='Portfolio Url')),
|
||||
('image', imagekit.models.fields.ProcessedImageField(blank=True, null=True, upload_to=core.utils.UniquePathAndRename('uploads/portfolio'))),
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Oluşturulma Tarihi')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Güncelleme Tarihi')),
|
||||
('is_active', models.BooleanField(choices=[(True, 'Evet'), (False, 'Hayır')], default=True, verbose_name='Yayındamı ?')),
|
||||
('categories', models.ManyToManyField(related_name='portfolio_categories', to='portfolio.category', verbose_name='Post Kategorisi')),
|
||||
('parent', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='child', to='portfolio.portfolio', verbose_name='Konular')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Portfolio',
|
||||
'verbose_name_plural': 'Portfolio',
|
||||
'db_table': 'portfolios',
|
||||
'ordering': ['created_at'],
|
||||
},
|
||||
),
|
||||
]
|
||||
0
portfolio/migrations/__init__.py
Normal file
0
portfolio/migrations/__init__.py
Normal file
BIN
portfolio/migrations/__pycache__/0001_initial.cpython-314.pyc
Normal file
BIN
portfolio/migrations/__pycache__/0001_initial.cpython-314.pyc
Normal file
Binary file not shown.
BIN
portfolio/migrations/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
portfolio/migrations/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
79
portfolio/models.py
Normal file
79
portfolio/models.py
Normal file
@@ -0,0 +1,79 @@
|
||||
from autoslug import AutoSlugField
|
||||
from django.db import models
|
||||
from imagekit.models import ProcessedImageField
|
||||
|
||||
from core.utils import image_optimizer
|
||||
|
||||
|
||||
# Create your models here.
|
||||
class Category(models.Model):
|
||||
aktif = (
|
||||
(True, 'Evet'),
|
||||
(False, 'Hayır'),
|
||||
)
|
||||
title = models.CharField(max_length=254, verbose_name="Kategori")
|
||||
keywords = models.CharField(max_length=254, verbose_name="Seo Kelimeleri Aralarına Virgül Koyunuz")
|
||||
description = models.CharField(max_length=254, verbose_name="Açıklama")
|
||||
created_at = models.DateTimeField(auto_now_add=True, editable=False, verbose_name="Oluşturulma Tarihi")
|
||||
updated_at = models.DateTimeField(auto_now=True, editable=False, verbose_name="Güncelleme Tarihi")
|
||||
is_active = models.BooleanField(default=True, verbose_name='Yayındamı', choices=aktif)
|
||||
order = models.IntegerField(verbose_name='Görüntülenme Sırası', default=1, db_index=True)
|
||||
slug = AutoSlugField(populate_from='title', null=False, unique=True, editable=True, db_index=True, max_length=250,
|
||||
blank=True)
|
||||
parent = models.ForeignKey('self', related_name='child', on_delete=models.CASCADE, blank=True, null=True,
|
||||
verbose_name='Üst Kategorisi')
|
||||
image = ProcessedImageField(**image_optimizer('uploads/category', 300, 300, 85, 'PNG'),
|
||||
verbose_name='Resim 630 x 653 Olmali ve Transparan PNG Olmali', blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ["order"]
|
||||
db_table = 'p_categories'
|
||||
verbose_name_plural = "Portfolio Kategorilerileri"
|
||||
verbose_name = "Portfolio Kategori"
|
||||
unique_together = ('slug', 'parent',)
|
||||
|
||||
def get_slug(self):
|
||||
slug = self.title.replace('ı', "i").replace('İ', 'i')
|
||||
number = 1
|
||||
while Category.objects.filter(slug=slug).exists():
|
||||
slug = '{}-{}'.format(slug, number)
|
||||
number += 1
|
||||
return slug
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug:
|
||||
self.slug = self.get_slug()
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
full_path = [self.title]
|
||||
k = self.parent
|
||||
while k is not None:
|
||||
full_path.append(k.title)
|
||||
k = k.parent
|
||||
return ' -> '.join(full_path[::-1])
|
||||
|
||||
class Portfolio(models.Model):
|
||||
aktif = (
|
||||
(True, 'Evet'),
|
||||
(False, 'Hayır'),
|
||||
)
|
||||
|
||||
url = models.URLField(verbose_name="Portfolio Url", null=True, blank=True)
|
||||
categories = models.ManyToManyField(Category, verbose_name="Post Kategorisi", related_name='portfolio_categories')
|
||||
image = ProcessedImageField(**image_optimizer('uploads/portfolio', 640, 481, 85, 'avif'), null=True, blank=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True, editable=False, verbose_name="Oluşturulma Tarihi")
|
||||
updated_at = models.DateTimeField(auto_now=True, editable=False, verbose_name="Güncelleme Tarihi")
|
||||
is_active = models.BooleanField(default=True, verbose_name='Yayındamı ?', choices=aktif)
|
||||
parent = models.ForeignKey('self', related_name='child', on_delete=models.CASCADE, blank=True, null=True,
|
||||
editable=False,
|
||||
verbose_name='Konular')
|
||||
|
||||
class Meta:
|
||||
ordering = ["created_at"]
|
||||
db_table = 'portfolios'
|
||||
verbose_name_plural = "Portfolio"
|
||||
verbose_name = "Portfolio"
|
||||
|
||||
def __str__(self):
|
||||
return f"Portfolio: {self.url if self.url else f'ID: {self.id}'}"
|
||||
58
portfolio/serializers.py
Normal file
58
portfolio/serializers.py
Normal file
@@ -0,0 +1,58 @@
|
||||
from rest_framework import serializers
|
||||
from django.conf import settings
|
||||
|
||||
from portfolio.models import Category, Portfolio
|
||||
|
||||
|
||||
class PortfolioCateSerializer(serializers.ModelSerializer):
|
||||
image = serializers.SerializerMethodField()
|
||||
parent = serializers.StringRelatedField()
|
||||
|
||||
class Meta:
|
||||
model = Portfolio
|
||||
fields = ['id', 'url', 'image', 'parent', 'created_at', 'updated_at', 'is_active']
|
||||
|
||||
def get_image(self, obj):
|
||||
if obj.image:
|
||||
# Sadece path döndür, domain olmadan
|
||||
return obj.image.url
|
||||
return None
|
||||
|
||||
|
||||
class CategorySerializer(serializers.ModelSerializer):
|
||||
parent = serializers.StringRelatedField() # ID yerine __str__ metodundaki değeri döndürür
|
||||
image = serializers.SerializerMethodField()
|
||||
portfolio_categories = serializers.SerializerMethodField() # ManyToMany ilişkisi üzerinden portfolio'ları getir
|
||||
|
||||
class Meta:
|
||||
model = Category
|
||||
fields = ['id', 'title', 'parent', 'is_active', 'created_at', 'updated_at', 'order', 'slug', 'image',
|
||||
'keywords', 'description', 'portfolio_categories']
|
||||
|
||||
def get_image(self, obj):
|
||||
if obj.image:
|
||||
# Sadece path döndür, domain olmadan
|
||||
return obj.image.url
|
||||
return None
|
||||
|
||||
def get_portfolio_categories(self, obj):
|
||||
"""Category'ye ait portfolio'ları döndürür"""
|
||||
portfolios = obj.portfolio_categories.filter(is_active=True).all()
|
||||
# Circular import'u önlemek için PortfolioCateSerializer kullanıyoruz
|
||||
return PortfolioCateSerializer(portfolios, many=True, context=self.context).data
|
||||
|
||||
|
||||
class PortfolioSerializer(serializers.ModelSerializer):
|
||||
categories = CategorySerializer(read_only=True, many=True)
|
||||
image = serializers.SerializerMethodField()
|
||||
parent = serializers.StringRelatedField()
|
||||
|
||||
class Meta:
|
||||
model = Portfolio
|
||||
fields = ['id', 'url', 'categories', 'image', 'parent', 'created_at', 'updated_at', 'is_active']
|
||||
|
||||
def get_image(self, obj):
|
||||
if obj.image:
|
||||
# Sadece path döndür, domain olmadan
|
||||
return obj.image.url
|
||||
return None
|
||||
38
portfolio/signals.py
Normal file
38
portfolio/signals.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from django.core.cache import cache
|
||||
from django.db.models.signals import post_save, post_delete, m2m_changed
|
||||
from django.dispatch import receiver
|
||||
|
||||
from portfolio.models import Category, Portfolio
|
||||
|
||||
CATEGORY_LIST_CACHE_KEY = 'portfolio:category_list'
|
||||
PORTFOLIO_LIST_CACHE_KEY = 'portfolio:portfolio_list'
|
||||
|
||||
|
||||
def clear_category_cache(slug=None):
|
||||
cache.delete(CATEGORY_LIST_CACHE_KEY)
|
||||
if slug:
|
||||
cache.delete(f"portfolio:category_detail:{slug}")
|
||||
|
||||
|
||||
def clear_portfolio_cache(pk=None):
|
||||
cache.delete(PORTFOLIO_LIST_CACHE_KEY)
|
||||
if pk:
|
||||
cache.delete(f"portfolio:portfolio_detail:{pk}")
|
||||
|
||||
|
||||
@receiver(post_save, sender=Category)
|
||||
@receiver(post_delete, sender=Category)
|
||||
def clear_category_cache_on_change(sender, instance, **kwargs):
|
||||
clear_category_cache(slug=instance.slug)
|
||||
|
||||
|
||||
@receiver(post_save, sender=Portfolio)
|
||||
@receiver(post_delete, sender=Portfolio)
|
||||
def clear_portfolio_cache_on_change(sender, instance, **kwargs):
|
||||
clear_portfolio_cache(pk=instance.pk)
|
||||
|
||||
|
||||
@receiver(m2m_changed, sender=Portfolio.categories.through)
|
||||
def clear_portfolio_cache_on_category_change(sender, instance, action, **kwargs):
|
||||
if action in {"post_add", "post_remove", "post_clear"}:
|
||||
clear_portfolio_cache(pk=instance.pk)
|
||||
3
portfolio/tests.py
Normal file
3
portfolio/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
11
portfolio/urls.py
Normal file
11
portfolio/urls.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from django.urls import path
|
||||
|
||||
from portfolio.views import CategoryList, CategoryDetail, PortfolioList, PortfolioDetail
|
||||
|
||||
urlpatterns = [
|
||||
path('categories/', CategoryList.as_view(), name='categories.list'),
|
||||
path('categories/<slug:slug>/', CategoryDetail.as_view(), name='categories.details'),
|
||||
path('portfolio/', PortfolioList.as_view(), name='portfolio.list'),
|
||||
path('portfolio/<int:pk>/', PortfolioDetail.as_view(), name='portfolio.details'),
|
||||
|
||||
]
|
||||
82
portfolio/views.py
Normal file
82
portfolio/views.py
Normal file
@@ -0,0 +1,82 @@
|
||||
from django.core.cache import cache
|
||||
from rest_framework.generics import ListAPIView, RetrieveAPIView
|
||||
from rest_framework.response import Response
|
||||
|
||||
from core.Permission import ReadOnly
|
||||
from portfolio.models import Portfolio, Category
|
||||
from portfolio.serializers import PortfolioSerializer, CategorySerializer
|
||||
|
||||
CACHE_TTL_SECONDS = 60 * 5
|
||||
|
||||
|
||||
class CategoryList(ListAPIView):
|
||||
permission_classes = [ReadOnly]
|
||||
queryset = Category.objects.order_by('order').filter(is_active=True, parent__isnull=True).all()
|
||||
# serializer_class = ParentSerializer
|
||||
serializer_class = CategorySerializer
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
cache_key = 'portfolio:category_list'
|
||||
cached_data = cache.get(cache_key)
|
||||
if cached_data:
|
||||
return Response(cached_data)
|
||||
|
||||
response = super().list(request, *args, **kwargs)
|
||||
cache.set(cache_key, response.data, timeout=CACHE_TTL_SECONDS)
|
||||
return response
|
||||
|
||||
|
||||
class CategoryDetail(RetrieveAPIView):
|
||||
permission_classes = [ReadOnly]
|
||||
queryset = Category.objects.order_by('order').filter(is_active=True).all()
|
||||
serializer_class = CategorySerializer
|
||||
lookup_field = 'slug' # Slug ile arama yapılacak
|
||||
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
cache_key = f"portfolio:category_detail:{kwargs.get('slug')}"
|
||||
cached_data = cache.get(cache_key)
|
||||
if cached_data:
|
||||
return Response(cached_data)
|
||||
|
||||
response = super().retrieve(request, *args, **kwargs)
|
||||
cache.set(cache_key, response.data, timeout=CACHE_TTL_SECONDS)
|
||||
return response
|
||||
|
||||
def get_serializer_context(self):
|
||||
context = super().get_serializer_context()
|
||||
return context
|
||||
|
||||
|
||||
# Create your views here.
|
||||
class PortfolioList(ListAPIView):
|
||||
permission_classes = [ReadOnly]
|
||||
queryset = Portfolio.objects.all()
|
||||
serializer_class = PortfolioSerializer
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
cache_key = 'portfolio:portfolio_list'
|
||||
cached_data = cache.get(cache_key)
|
||||
if cached_data:
|
||||
return Response(cached_data)
|
||||
|
||||
response = super().list(request, *args, **kwargs)
|
||||
cache.set(cache_key, response.data, timeout=CACHE_TTL_SECONDS)
|
||||
return response
|
||||
|
||||
|
||||
|
||||
class PortfolioDetail(RetrieveAPIView):
|
||||
permission_classes = [ReadOnly]
|
||||
queryset = Portfolio.objects.all()
|
||||
serializer_class = PortfolioSerializer
|
||||
lookup_field = 'pk' # Portfolio modelinde slug olmadığı için pk kullanılıyor
|
||||
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
cache_key = f"portfolio:portfolio_detail:{kwargs.get('pk')}"
|
||||
cached_data = cache.get(cache_key)
|
||||
if cached_data:
|
||||
return Response(cached_data)
|
||||
|
||||
response = super().retrieve(request, *args, **kwargs)
|
||||
cache.set(cache_key, response.data, timeout=CACHE_TTL_SECONDS)
|
||||
return response
|
||||
Reference in New Issue
Block a user