Skip to content
This repository has been archived by the owner on Mar 1, 2024. It is now read-only.

Implement file upload and display #53

Merged
merged 5 commits into from
Sep 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions django_material_demo/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,13 @@ POSTGRES_USER=postgres
POSTGRES_PASSWORD=GENERATE_SECRET[postgres_password]
POSTGRES_HOST=db
POSTGRES_PORT=5432

FILE_STORAGE_IMPL=local_storage

AWS_STORAGE_BUCKET_NAME=django-material-demo
AWS_S3_REGION_NAME=[AWS_S3_REGION_NAME]
AWS_S3_ACCESS_KEY_ID=[AWS_S3_ACCESS_KEY_ID]
AWS_S3_SECRET_ACCESS_KEY=[AWS_S3_SECRET_ACCESS_KEY]

AWS_S3_FILE_OVERWRITE=true
AWS_LOCATION=media
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{% comment %} https://materializecss.com/sidenav.html {% endcomment %}
<ul>
<li><a href="{% url 'polls:user_list' %}">User List</a></li>
<li><a href="{% url 'polls:file_list' %}">File List</a></li>
<li><a href="{% url 'polls:question_list' %}">Question List</a></li>
<li><a href="{% url 'polls:vote_list' %}">Vote List</a></li>
<li>
Expand Down
3 changes: 1 addition & 2 deletions django_material_demo/cms/polls/urls.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .views import file, question, user, vote
from .views import question, user, vote
from django.urls import include, path
from django.views.generic.base import RedirectView

Expand All @@ -12,7 +12,6 @@
user.PasswordChangeDoneView.as_view(),
name="password_change_done",),

path('file/', include(file.FileViewSet().urls)),
path('question/', include(question.QuestionViewSet().urls)),
path('vote/', include(vote.VoteViewSet().urls)),
]
13 changes: 0 additions & 13 deletions django_material_demo/cms/polls/views/file.py

This file was deleted.

50 changes: 46 additions & 4 deletions django_material_demo/cms/polls/views/question.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
from django import forms
from django.conf import settings
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
from django.forms import BaseInlineFormSet, BooleanField, ModelForm
from django.forms import (BaseInlineFormSet, BooleanField, FileField,
ImageField, ModelForm)
from django.forms.widgets import CheckboxInput
from django.utils.safestring import mark_safe
from django_filters import CharFilter
from library.django_superform import InlineFormSetField, SuperModelForm
from material import Fieldset, Layout, Row
from material.frontend.views import (CreateModelView, ListModelView,
ModelViewSet, UpdateModelView)
from material.frontend.views import (CreateModelView, DetailModelView,
ListModelView, ModelViewSet,
UpdateModelView)
from polls.models import Attachment, Choice, Question, QuestionFollower

from ...utils import (FieldDataMixin, FormSetForm, GetParamAsFormDataMixin,
ListFilterView, NestedModelFormField, SearchAndFilterSet)
ListFilterView, NestedModelFormField, SearchAndFilterSet,
get_html_list)


class AttachmentsForm(FormSetForm):
file = FileField(label="Attachment",
max_length=settings.FILE_UPLOAD_MAX_MEMORY_SIZE)

layout = Layout('file')
parent_instance_field = 'question'

Expand Down Expand Up @@ -91,6 +99,8 @@ class Media:


class QuestionForm(SuperModelForm):
thumbnail = ImageField(required=False, label='Thumbnail',
max_length=settings.FILE_UPLOAD_MAX_MEMORY_SIZE)
max_vote_count_control = NestedModelFormField(MaxVoteCountForm)

# Formset fields
Expand Down Expand Up @@ -267,8 +277,40 @@ class QuestionListView(ListModelView, ListFilterView):
filterset_class = QuestionFilter


class QuestionDetailView(DetailModelView):
def get_object_data(self):
question = super().get_object()
thumbnail_name = Question._meta.get_field('thumbnail')
thumbnail_name = thumbnail_name.verbose_name.title()
for item in super().get_object_data():
if item[0] == thumbnail_name:
# Skip if no image
if item[1]:
#TODO: replace with template
image_html = mark_safe(
f"<img class='thumbnail' src='{item[1].url}' "
f"alt='{item[1].name}'>")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls render it in a separate html template file instead of inline html in python.

yield (item[0], image_html)
else:
yield (item[0], 'None')
else:
yield item

attachments = question.attachment_set.all()
if len(attachments):
#TODO: replace with template
attachments = [
mark_safe(f"<a href='{x.file.url}'>{x.file.name}</a>")
for x in attachments]
html_list = get_html_list(attachments)
yield ('Attachments', html_list)
else:
yield ('Attachments', 'None')


class QuestionViewSet(ModelViewSet):
model = Question
create_view_class = QuestionCreateView
update_view_class = QuestionUpdateView
list_view_class = QuestionListView
detail_view_class = QuestionDetailView
13 changes: 10 additions & 3 deletions django_material_demo/cms/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
from .modules import ModuleNamespaceMixin
from .views import ListFilterView, SearchAndFilterSet, get_html_list

__all__ = [('FieldDataMixin', 'FormSetForm', 'GetParamAsFormDataMixin',
'NestedModelFormField', 'ModuleNamespaceMixin',
'ListFilterView', 'SearchAndFilterSet', 'get_html_list')]
__all__ = (
'FieldDataMixin',
'FormSetForm',
'GetParamAsFormDataMixin',
'NestedModelFormField',
'ModuleNamespaceMixin',
'ListFilterView',
'SearchAndFilterSet',
'get_html_list',
)
1 change: 1 addition & 0 deletions django_material_demo/cms/utils/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def get_html_list(arr):
if len(arr) == 0:
return ''

#TODO: replace with template
value_list = [conditional_escape(x) for x in arr]
value_list_html = mark_safe(
'<ul>'
Expand Down
24 changes: 24 additions & 0 deletions django_material_demo/django_material_demo/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
'django.contrib.messages',
'django.contrib.staticfiles',
'django_filters',
'storages',
]

MIDDLEWARE = [
Expand Down Expand Up @@ -163,6 +164,29 @@

STATIC_URL = 'static/'

MEDIA_ROOT = 'media/'
MEDIA_URL = 'media/'

FILE_STORAGE_IMPL = str(os.getenv('FILE_STORAGE_IMPL'))

if FILE_STORAGE_IMPL.lower() == 's3':
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
else:
# use django.core.files.storage.FileSystemStorage
# as defined in django/conf/global_settings.py
pass

# Amazon S3 settings
# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html

AWS_STORAGE_BUCKET_NAME = str(os.getenv('AWS_STORAGE_BUCKET_NAME'))
AWS_S3_REGION_NAME = str(os.getenv('AWS_S3_REGION_NAME'))
AWS_S3_ACCESS_KEY_ID = str(os.getenv('AWS_S3_ACCESS_KEY_ID'))
AWS_S3_SECRET_ACCESS_KEY = str(os.getenv('AWS_S3_SECRET_ACCESS_KEY'))
AWS_S3_FILE_OVERWRITE = (str(os.getenv('AWS_S3_FILE_OVERWRITE')).lower()
in ['true', 'yes', '1'])
AWS_LOCATION = str(os.getenv('AWS_LOCATION'))

# Default primary key field type
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field

Expand Down
4 changes: 3 additions & 1 deletion django_material_demo/django_material_demo/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.contrib.auth.views import LoginView
from django.urls import include, path
Expand All @@ -29,4 +31,4 @@
# reserve `polls` namespace for polls urls in CMS
path('polls/', include('polls.urls', namespace='app_polls')),
path('cms/', include(frontend_urls)),
]
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
19 changes: 1 addition & 18 deletions django_material_demo/polls/admin.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,6 @@
from django.contrib import admin
from django.conf import settings
from django.contrib.auth import get_user_model

from .models import Attachment, Choice, File, Question, User, UserFollower, Vote


@admin.register(File)
class FileAdmin(admin.ModelAdmin):
readonly_fields = [
'file_id',
'storage_loc',
'file_name',
'file_type',
'file_size',
]

list_display = ['file_name', 'file_type', 'file_size', 'storage_loc']
list_filter = ['file_type', 'storage_loc']
search_fields = ['file_name']
from .models import Attachment, Choice, Question, User, UserFollower, Vote


class FollowedQuestion(admin.TabularInline):
Expand Down
68 changes: 68 additions & 0 deletions django_material_demo/polls/migrations/0012_add_temp_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Generated by Django 4.1 on 2022-09-22 11:17

from django.core.files.storage import get_storage_class
from django.db import migrations, models


STORAGE = get_storage_class()()
# Should match with same variable in migration 0014
DUMMY_FILE_NAME = 'DUMMY_FILE_NAME'


def copy_file_fk(apps, schema_editor):
question_model = apps.get_model('polls', 'Question')
attachment_model = apps.get_model('polls', 'Attachment')
for question in question_model.objects.all():
if question.thumbnail:
question.thumbnail_copy = question.thumbnail
question.save()
for attachment in attachment_model.objects.all():
attachment.file_copy = attachment.file
attachment.save()
pass


def delete_dummy_file(name):
STORAGE.delete(name)


def restore_file_fk(apps, schema_editor):
file_model = apps.get_model('polls', 'File')
question_model = apps.get_model('polls', 'Question')
attachment_model = apps.get_model('polls', 'Attachment')

for question in question_model.objects.all():
delete_dummy_file(str(question.thumbnail_copy.pk))
if question.thumbnail_copy.file_name == DUMMY_FILE_NAME:
question.thumbnail = None
question.thumbnail_copy = None
else:
question.thumbnail = question.thumbnail_copy
question.save()
for attachment in attachment_model.objects.all():
delete_dummy_file(str(attachment.file_copy.pk))
attachment.file = attachment.file_copy
attachment.save()


class Migration(migrations.Migration):

dependencies = [
('polls', '0011_alter_attachment_options_alter_choice_options_and_more'),
]

operations = [
migrations.AddField(
model_name='attachment',
name='file_copy',
field=models.ForeignKey(
'polls.file', on_delete=models.DO_NOTHING, null=True, blank=True),
),
migrations.AddField(
model_name='question',
name='thumbnail_copy',
field=models.ForeignKey(
'polls.file', on_delete=models.DO_NOTHING, null=True, blank=True),
),
migrations.RunPython(copy_file_fk, restore_file_fk),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.1 on 2022-09-23 09:52

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('polls', '0012_add_temp_fields'),
]

operations = [
migrations.AlterField(
model_name='attachment',
name='file',
field=models.FileField(blank=True, null=True, upload_to=''),
),
migrations.AlterField(
model_name='question',
name='thumbnail',
field=models.FileField(blank=True, null=True, upload_to=''),
),
]
Loading