file uploads
This commit is contained in:
parent
151cd89b88
commit
85e674e6d6
@ -1,12 +1,34 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
from django_softdelete.models import SoftDeleteModel
|
from django_softdelete.models import SoftDeleteModel
|
||||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
from PIL import Image
|
||||||
|
|
||||||
|
def validate_image_size(image):
|
||||||
|
if image.size > 1 * 1024 * 1024:
|
||||||
|
raise ValidationError("File size exceeds 1MB.")
|
||||||
|
|
||||||
|
def validate_image_ext(image):
|
||||||
|
allowed_extensions = ['png']
|
||||||
|
ext = image.name.split('.')[-1].lower()
|
||||||
|
if ext not in allowed_extensions:
|
||||||
|
raise ValidationError("Invalid file type. Only PNG allowed.")
|
||||||
|
|
||||||
|
def validate_image(image):
|
||||||
|
try:
|
||||||
|
img = Image.open(image)
|
||||||
|
img.verify()
|
||||||
|
except Exception:
|
||||||
|
raise ValidationError("Invalid image file.")
|
||||||
|
|
||||||
class ContentTheme(SoftDeleteModel):
|
class ContentTheme(SoftDeleteModel):
|
||||||
theme = models.CharField(max_length=255, null=False)
|
theme = models.CharField(max_length=255, null=False)
|
||||||
description = models.CharField(max_length=1000)
|
description = models.CharField(max_length=1000)
|
||||||
|
|
||||||
featured_image = models.CharField(max_length=1000)
|
featured_image = models.ImageField(
|
||||||
|
max_length=255,
|
||||||
|
upload_to="uploads/content_themes/",
|
||||||
|
validators=[validate_image_size, validate_image_ext, validate_image],
|
||||||
|
null=False, blank=False)
|
||||||
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
@ -18,7 +40,11 @@ class ContentTopic(SoftDeleteModel):
|
|||||||
topic = models.CharField(max_length=255, null=False)
|
topic = models.CharField(max_length=255, null=False)
|
||||||
description = models.CharField(max_length=1000)
|
description = models.CharField(max_length=1000)
|
||||||
|
|
||||||
featured_image = models.CharField(max_length=1000)
|
featured_image = models.ImageField(
|
||||||
|
max_length=255,
|
||||||
|
upload_to="uploads/content_topics/",
|
||||||
|
validators=[validate_image_size, validate_image_ext, validate_image],
|
||||||
|
null=False, blank=False)
|
||||||
|
|
||||||
theme = models.ForeignKey(ContentTheme, on_delete=models.CASCADE, null=False)
|
theme = models.ForeignKey(ContentTheme, on_delete=models.CASCADE, null=False)
|
||||||
|
|
||||||
@ -48,7 +74,11 @@ class Content(SoftDeleteModel):
|
|||||||
title = models.CharField(max_length=255, null=False)
|
title = models.CharField(max_length=255, null=False)
|
||||||
slug = models.SlugField(max_length=255)
|
slug = models.SlugField(max_length=255)
|
||||||
|
|
||||||
featured_image = models.CharField(max_length=1000)
|
featured_image = models.ImageField(
|
||||||
|
max_length=255,
|
||||||
|
upload_to="uploads/contents/",
|
||||||
|
validators=[validate_image_size, validate_image_ext, validate_image],
|
||||||
|
null=False, blank=False)
|
||||||
|
|
||||||
theme = models.ForeignKey(ContentTheme, on_delete=models.CASCADE, null=False)
|
theme = models.ForeignKey(ContentTheme, on_delete=models.CASCADE, null=False)
|
||||||
topic = models.ForeignKey(ContentTopic, on_delete=models.CASCADE, null=False)
|
topic = models.ForeignKey(ContentTopic, on_delete=models.CASCADE, null=False)
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
|
from django.forms import ImageField
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from content import models
|
from content import models
|
||||||
|
|
||||||
class ContentThemeSerializer(serializers.ModelSerializer):
|
class ContentThemeSerializer(serializers.ModelSerializer):
|
||||||
|
featured_image = ImageField(max_length=255, allow_empty_file=False)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.ContentTheme
|
model = models.ContentTheme
|
||||||
fields = ['id', 'theme', 'description', 'featured_image']
|
fields = ['id', 'theme', 'description', 'featured_image']
|
||||||
|
|
||||||
class ContentTopicSerializer(serializers.ModelSerializer):
|
class ContentTopicSerializer(serializers.ModelSerializer):
|
||||||
|
featured_image = ImageField(max_length=255, allow_empty_file=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.ContentTopic
|
model = models.ContentTopic
|
||||||
@ -14,12 +17,15 @@ class ContentTopicSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
class ContentTopicDetailSerializer(serializers.ModelSerializer):
|
class ContentTopicDetailSerializer(serializers.ModelSerializer):
|
||||||
theme = ContentThemeSerializer(read_only=True)
|
theme = ContentThemeSerializer(read_only=True)
|
||||||
|
featured_image = ImageField(max_length=255, allow_empty_file=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.ContentTopic
|
model = models.ContentTopic
|
||||||
fields = ['id', 'topic', 'description', 'featured_image', 'theme']
|
fields = ['id', 'topic', 'description', 'featured_image', 'theme']
|
||||||
|
|
||||||
class ContentSerializer(serializers.ModelSerializer):
|
class ContentSerializer(serializers.ModelSerializer):
|
||||||
|
featured_image = ImageField(max_length=255, allow_empty_file=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Content
|
model = models.Content
|
||||||
fields = ['id', 'title', 'slug', 'featured_image', 'theme', 'topic', 'format', 'content', 'point', 'coin', 'data', 'grades']
|
fields = ['id', 'title', 'slug', 'featured_image', 'theme', 'topic', 'format', 'content', 'point', 'coin', 'data', 'grades']
|
||||||
@ -27,6 +33,7 @@ class ContentSerializer(serializers.ModelSerializer):
|
|||||||
class ContentDetailSerializer(serializers.ModelSerializer):
|
class ContentDetailSerializer(serializers.ModelSerializer):
|
||||||
theme = ContentThemeSerializer(read_only=True)
|
theme = ContentThemeSerializer(read_only=True)
|
||||||
topic = ContentTopicDetailSerializer(read_only=True)
|
topic = ContentTopicDetailSerializer(read_only=True)
|
||||||
|
featured_image = ImageField(max_length=255, allow_empty_file=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Content
|
model = models.Content
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
from rest_framework import generics, filters
|
from rest_framework import generics, filters, parsers
|
||||||
from django_filters.rest_framework import DjangoFilterBackend, FilterSet, CharFilter, ChoiceFilter
|
from django_filters.rest_framework import DjangoFilterBackend, FilterSet, CharFilter, ChoiceFilter
|
||||||
|
|
||||||
from content import models, serializers
|
from content import models, serializers
|
||||||
|
|||||||
@ -12,6 +12,7 @@ https://docs.djangoproject.com/en/5.1/ref/settings/
|
|||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from decouple import config
|
from decouple import config
|
||||||
|
import os
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
@ -184,3 +185,8 @@ DJOSER = {
|
|||||||
INTERNAL_IPS = [
|
INTERNAL_IPS = [
|
||||||
'127.0.0.1',
|
'127.0.0.1',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||||
|
MEDIA_URL = '/media/'
|
||||||
|
|
||||||
|
DATA_UPLOAD_MAX_MEMORY_SIZE = 2 * 1024 * 1024 # 5MB
|
||||||
|
|||||||
@ -18,6 +18,8 @@ from django.contrib import admin
|
|||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from oauth2_provider import urls as oauth2_urls
|
from oauth2_provider import urls as oauth2_urls
|
||||||
from debug_toolbar.toolbar import debug_toolbar_urls
|
from debug_toolbar.toolbar import debug_toolbar_urls
|
||||||
|
from django.conf import settings
|
||||||
|
from django.conf.urls.static import static
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# path('admin/', admin.site.urls),
|
# path('admin/', admin.site.urls),
|
||||||
@ -28,4 +30,4 @@ urlpatterns = [
|
|||||||
path('core/', include('core.urls')),
|
path('core/', include('core.urls')),
|
||||||
path('content/', include('content.urls')),
|
path('content/', include('content.urls')),
|
||||||
path('character/', include('character.urls')),
|
path('character/', include('character.urls')),
|
||||||
]+ debug_toolbar_urls()
|
]+ debug_toolbar_urls() + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user