Implemented the UploadedFile mode to replace UploadedDocument and UploadedImage

- Rebase of #8085
pull/11577/head
advik 2024-01-31 01:42:46 +05:30 zatwierdzone przez LB (Ben Johnston)
rodzic 58ebfe1fb1
commit e6aebc65a8
17 zmienionych plików z 216 dodań i 125 usunięć

Wyświetl plik

@ -23,6 +23,7 @@ Changelog
* Maintenance: Rename the React `Button` that only renders links (a element) to `Link` and remove unused prop & behavior that was non-compliant for aria role usage (Advik Kabra)
* Maintenance: Set up an `wagtail.models.AbstractWorkflow` model to support future customisations around workflows (Hossein)
* Maintenance: Improve `classnames` template tag to handle nested lists of strings, use template tag for admin `body` element (LB (Ben) Johnston)
* Maintenance: Merge `UploadedDocument` and `UploadedImage` into new `UploadedFile` model for easier shared code usage (Advik Kabra, Karl Hobley)
6.0 (07.02.2024)

Wyświetl plik

@ -44,6 +44,7 @@ depth: 1
* Rename the React `Button` that only renders links (a element) to `Link` and remove unused prop & behavior that was non-compliant for aria role usage (Advik Kabra)
* Set up an `wagtail.models.AbstractWorkflow` model to support future customisations around workflows (Hossein)
* Improve `classnames` template tag to handle nested lists of strings, use template tag for admin `body` element (LB (Ben) Johnston)
* Merge `UploadedDocument` and `UploadedImage` into new `UploadedFile` model for easier shared code usage (Advik Kabra, Karl Hobley)
## Upgrade considerations

Wyświetl plik

@ -1,5 +1,6 @@
import os.path
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseBadRequest, JsonResponse
from django.shortcuts import get_object_or_404
@ -10,13 +11,13 @@ from django.views.decorators.vary import vary_on_headers
from django.views.generic.base import TemplateView, View
from wagtail.admin.views.generic import PermissionCheckedMixin
from wagtail.models import UploadedFile
class AddView(PermissionCheckedMixin, TemplateView):
# subclasses need to provide:
# - permission_policy
# - template_name
# - upload_model
# - edit_object_url_name
# - delete_object_url_name
@ -152,10 +153,12 @@ class AddView(PermissionCheckedMixin, TemplateView):
return JsonResponse(self.get_invalid_response_data(form))
else:
# Some other field of the form has failed validation, e.g. a required metadata field
# on a custom image model. Store the object as an upload_model instance instead and
# on a custom image model. Store the object as an UploadedFile instance instead and
# present the edit form so that it will become a proper object when successfully filled in
self.upload_object = self.upload_model.objects.create(
file=self.request.FILES["files[]"], uploaded_by_user=self.request.user
self.upload_object = UploadedFile.objects.create(
for_content_type=ContentType.objects.get_for_model(self.get_model()),
file=self.request.FILES["files[]"],
uploaded_by_user=self.request.user,
)
self.object = self.model(
title=self.request.FILES["files[]"].name,
@ -297,7 +300,6 @@ class CreateFromUploadView(View):
# subclasses need to provide:
# - edit_upload_url_name
# - delete_upload_url_name
# - upload_model
# - upload_pk_url_kwarg
# - edit_upload_form_prefix
# - context_object_id_name
@ -320,7 +322,11 @@ class CreateFromUploadView(View):
self.model = self.get_model()
self.form_class = self.get_edit_form_class()
self.upload = get_object_or_404(self.upload_model, id=upload_id)
self.upload = get_object_or_404(
UploadedFile,
id=upload_id,
for_content_type=ContentType.objects.get_for_model(self.model),
)
if self.upload.uploaded_by_user != request.user:
raise PermissionDenied
@ -369,14 +375,17 @@ class CreateFromUploadView(View):
class DeleteUploadView(View):
# subclasses need to provide:
# - upload_model
# - upload_pk_url_kwarg
http_method_names = ["post"]
def post(self, request, *args, **kwargs):
upload_id = kwargs[self.upload_pk_url_kwarg]
upload = get_object_or_404(self.upload_model, id=upload_id)
upload = get_object_or_404(
UploadedFile,
id=upload_id,
for_content_type=ContentType.objects.get_for_model(self.get_model()),
)
if upload.uploaded_by_user != request.user:
raise PermissionDenied

Wyświetl plik

@ -16,7 +16,7 @@ urlpatterns = [
path("multiple/add/", multiple.AddView.as_view(), name="add_multiple"),
path("multiple/<int:doc_id>/", multiple.EditView.as_view(), name="edit_multiple"),
path(
"multiple/create_from_uploaded_document/<int:uploaded_document_id>/",
"multiple/create_from_uploaded_document/<int:uploaded_file_id>/",
multiple.CreateFromUploadedDocumentView.as_view(),
name="create_multiple_from_uploaded_document",
),
@ -26,7 +26,7 @@ urlpatterns = [
name="delete_multiple",
),
path(
"multiple/delete_upload/<int:uploaded_document_id>/",
"multiple/delete_upload/<int:uploaded_file_id>/",
multiple.DeleteUploadView.as_view(),
name="delete_upload_multiple",
),

Wyświetl plik

@ -0,0 +1,16 @@
# Generated by Django 5.0.1 on 2024-01-30 18:19
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('wagtaildocs', '0012_uploadeddocument'),
]
operations = [
migrations.DeleteModel(
name='UploadedDocument',
),
]

Wyświetl plik

@ -215,23 +215,3 @@ class Document(AbstractDocument):
# provides args: request
document_served = Signal()
class UploadedDocument(models.Model):
"""
Temporary storage for documents uploaded through the multiple doc uploader, when validation
rules (e.g. required metadata fields) prevent creating a Document object from the document file
alone. In this case, the document file is stored against this model, to be turned into a
Document object once the full form has been filled in.
"""
file = models.FileField(upload_to="uploaded_documents", max_length=200)
uploaded_by_user = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name=_("uploaded by user"),
null=True,
blank=True,
editable=False,
on_delete=models.SET_NULL,
)
uploaded_by_user.wagtail_reference_index_ignore = True

Wyświetl plik

@ -2,6 +2,7 @@ import json
from unittest import mock
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase, TransactionTestCase
from django.test.utils import override_settings
@ -12,7 +13,13 @@ from django.utils.http import urlencode
from wagtail.admin.admin_url_finder import AdminURLFinder
from wagtail.documents import get_document_model, models
from wagtail.documents.tests.utils import get_test_document_file
from wagtail.models import Collection, GroupCollectionPermission, Page, ReferenceIndex
from wagtail.models import (
Collection,
GroupCollectionPermission,
Page,
ReferenceIndex,
UploadedFile,
)
from wagtail.test.testapp.models import (
CustomDocument,
CustomDocumentWithAuthor,
@ -1277,15 +1284,16 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
def setUp(self):
super().setUp()
# Create an UploadedDocument for running tests on
self.uploaded_document = models.UploadedDocument.objects.create(
# Create an UploadedFile for running tests on
self.uploaded_document = UploadedFile.objects.create(
for_content_type=ContentType.objects.get_for_model(get_document_model()),
file=get_test_document_file(),
uploaded_by_user=self.user,
)
def test_add_post(self):
"""
This tests that a POST request to the add view saves the document as an UploadedDocument
This tests that a POST request to the add view saves the document as an UploadedFile
and returns an edit form
"""
response = self.client.post(
@ -1326,11 +1334,11 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
# Check JSON
response_json = json.loads(response.content.decode())
self.assertIn("uploaded_document_id", response_json)
self.assertIn("uploaded_file_id", response_json)
self.assertIn("form", response_json)
self.assertIn("success", response_json)
self.assertEqual(
response_json["uploaded_document_id"],
response_json["uploaded_file_id"],
response.context["uploaded_document"].id,
)
self.assertTrue(response_json["success"])
@ -1363,10 +1371,10 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
# Check JSON
response_json = json.loads(response.content.decode())
self.assertIn("uploaded_document_id", response_json)
self.assertIn("uploaded_file_id", response_json)
self.assertIn("form", response_json)
self.assertEqual(
response_json["uploaded_document_id"],
response_json["uploaded_file_id"],
response.context["uploaded_document"].id,
)
self.assertTrue(response_json["success"])
@ -1419,11 +1427,11 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
# Check JSON
response_json = json.loads(response.content.decode())
self.assertIn("uploaded_document_id", response_json)
self.assertIn("uploaded_file_id", response_json)
self.assertIn("form", response_json)
self.assertIn("success", response_json)
self.assertEqual(
response_json["uploaded_document_id"],
response_json["uploaded_file_id"],
response.context["uploaded_document"].id,
)
self.assertTrue(response_json["success"])
@ -1438,10 +1446,10 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
def test_create_from_upload_invalid_post(self):
"""
Posting an invalid form to the create_from_uploaded_document view throws a validation error
and leaves the UploadedDocument intact
and leaves the UploadedFile intact
"""
doc_count_before = CustomDocumentWithAuthor.objects.count()
uploaded_doc_count_before = models.UploadedDocument.objects.count()
uploaded_doc_count_before = UploadedFile.objects.count()
# Send request
response = self.client.post(
@ -1459,9 +1467,9 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
)
doc_count_after = CustomDocumentWithAuthor.objects.count()
uploaded_doc_count_after = models.UploadedDocument.objects.count()
uploaded_doc_count_after = UploadedFile.objects.count()
# no changes to document / UploadedDocument count
# no changes to document / UploadedFile count
self.assertEqual(doc_count_after, doc_count_before)
self.assertEqual(uploaded_doc_count_after, uploaded_doc_count_before)
@ -1497,7 +1505,7 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
Posting a valid form to the create_from_uploaded_document view will create the document
"""
doc_count_before = CustomDocumentWithAuthor.objects.count()
uploaded_doc_count_before = models.UploadedDocument.objects.count()
uploaded_doc_count_before = UploadedFile.objects.count()
# Send request
response = self.client.post(
@ -1519,7 +1527,7 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
)
doc_count_after = CustomDocumentWithAuthor.objects.count()
uploaded_doc_count_after = models.UploadedDocument.objects.count()
uploaded_doc_count_after = UploadedFile.objects.count()
# Check response
self.assertEqual(response.status_code, 200)
@ -1530,7 +1538,7 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
self.assertIn("doc_id", response_json)
self.assertTrue(response_json["success"])
# Document should have been created, UploadedDocument deleted
# Document should have been created, UploadedFile deleted
self.assertEqual(doc_count_after, doc_count_before + 1)
self.assertEqual(uploaded_doc_count_after, uploaded_doc_count_before - 1)
@ -1544,7 +1552,7 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
def test_delete_uploaded_document(self):
"""
This tests that a POST request to the delete view deletes the UploadedDocument
This tests that a POST request to the delete view deletes the UploadedFile
"""
# Send request
response = self.client.post(
@ -1559,9 +1567,7 @@ class TestMultipleCustomDocumentUploaderWithRequiredField(TestMultipleDocumentUp
# Make sure the document is deleted
self.assertFalse(
models.UploadedDocument.objects.filter(
id=self.uploaded_document.id
).exists()
UploadedFile.objects.filter(id=self.uploaded_document.id).exists()
)
# Check JSON

Wyświetl plik

@ -12,14 +12,12 @@ from wagtail.admin.views.generic.multiple_upload import EditView as BaseEditView
from .. import get_document_model
from ..forms import get_document_form, get_document_multi_form
from ..models import UploadedDocument
from ..permissions import permission_policy
class AddView(BaseAddView):
permission_policy = permission_policy
template_name = "wagtaildocs/multiple/add.html"
upload_model = UploadedDocument
edit_object_url_name = "wagtaildocs:edit_multiple"
delete_object_url_name = "wagtaildocs:delete_multiple"
@ -31,7 +29,7 @@ class AddView(BaseAddView):
delete_upload_url_name = "wagtaildocs:delete_upload_multiple"
edit_upload_form_prefix = "uploaded-document"
context_upload_name = "uploaded_document"
context_upload_id_name = "uploaded_document_id"
context_upload_id_name = "uploaded_file_id"
def get_model(self):
return get_document_model()
@ -90,8 +88,7 @@ class DeleteView(BaseDeleteView):
class CreateFromUploadedDocumentView(BaseCreateFromUploadView):
edit_upload_url_name = "wagtaildocs:create_multiple_from_uploaded_document"
delete_upload_url_name = "wagtaildocs:delete_upload_multiple"
upload_model = UploadedDocument
upload_pk_url_kwarg = "uploaded_document_id"
upload_pk_url_kwarg = "uploaded_file_id"
edit_upload_form_prefix = "uploaded-document"
context_object_id_name = "doc_id"
context_upload_name = "uploaded_document"
@ -118,5 +115,7 @@ class CreateFromUploadedDocumentView(BaseCreateFromUploadView):
class DeleteUploadView(BaseDeleteUploadView):
upload_model = UploadedDocument
upload_pk_url_kwarg = "uploaded_document_id"
upload_pk_url_kwarg = "uploaded_file_id"
def get_model(self):
return get_document_model()

Wyświetl plik

@ -24,7 +24,7 @@ urlpatterns = [
path("multiple/add/", multiple.AddView.as_view(), name="add_multiple"),
path("multiple/<int:image_id>/", multiple.EditView.as_view(), name="edit_multiple"),
path(
"multiple/create_from_uploaded_image/<int:uploaded_image_id>/",
"multiple/create_from_uploaded_image/<int:uploaded_file_id>/",
multiple.CreateFromUploadedImageView.as_view(),
name="create_multiple_from_uploaded_image",
),
@ -34,7 +34,7 @@ urlpatterns = [
name="delete_multiple",
),
path(
"multiple/delete_upload/<int:uploaded_image_id>/",
"multiple/delete_upload/<int:uploaded_file_id>/",
multiple.DeleteUploadView.as_view(),
name="delete_upload_multiple",
),

Wyświetl plik

@ -0,0 +1,16 @@
# Generated by Django 5.0.1 on 2024-01-30 18:19
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('wagtailimages', '0025_alter_image_file_alter_rendition_file'),
]
operations = [
migrations.DeleteModel(
name='UploadedImage',
),
]

Wyświetl plik

@ -1331,23 +1331,3 @@ class Rendition(AbstractRendition):
class Meta:
unique_together = (("image", "filter_spec", "focal_point_key"),)
class UploadedImage(models.Model):
"""
Temporary storage for images uploaded through the multiple image uploader, when validation rules (e.g.
required metadata fields) prevent creating an Image object from the image file alone. In this case,
the image file is stored against this model, to be turned into an Image object once the full form
has been filled in.
"""
file = models.ImageField(upload_to="uploaded_images", max_length=200)
uploaded_by_user = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name=_("uploaded by user"),
null=True,
blank=True,
editable=False,
on_delete=models.SET_NULL,
)
uploaded_by_user.wagtail_reference_index_ignore = True

Wyświetl plik

@ -4,6 +4,7 @@ import urllib
from django.conf import settings
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.core.files.uploadedfile import SimpleUploadedFile, TemporaryUploadedFile
from django.template.defaultfilters import filesizeformat
from django.template.loader import render_to_string
@ -16,12 +17,12 @@ from django.utils.safestring import mark_safe
from wagtail.admin.admin_url_finder import AdminURLFinder
from wagtail.images import get_image_model
from wagtail.images.models import UploadedImage
from wagtail.images.utils import generate_signature
from wagtail.models import (
Collection,
GroupCollectionPermission,
Page,
UploadedFile,
get_root_collection_id,
)
from wagtail.test.testapp.models import (
@ -2886,7 +2887,7 @@ class TestMultipleImageUploaderWithCustomImageModel(WagtailTestUtils, TestCase):
def test_unique_together_validation_error(self):
"""
If unique_together validation fails, create an UploadedImage and return a form so the
If unique_together validation fails, create an UploadedFile and return a form so the
user can fix it
"""
root_collection = Collection.get_first_root_node()
@ -2895,7 +2896,7 @@ class TestMultipleImageUploaderWithCustomImageModel(WagtailTestUtils, TestCase):
self.image.save()
image_count_before = CustomImage.objects.count()
uploaded_image_count_before = UploadedImage.objects.count()
uploaded_image_count_before = UploadedFile.objects.count()
response = self.client.post(
reverse("wagtailimages:add_multiple"),
@ -2908,9 +2909,9 @@ class TestMultipleImageUploaderWithCustomImageModel(WagtailTestUtils, TestCase):
)
image_count_after = CustomImage.objects.count()
uploaded_image_count_after = UploadedImage.objects.count()
uploaded_image_count_after = UploadedFile.objects.count()
# an UploadedImage should have been created now, but not a CustomImage
# an UploadedFile should have been created now, but not a CustomImage
self.assertEqual(image_count_after, image_count_before)
self.assertEqual(uploaded_image_count_after, uploaded_image_count_before + 1)
@ -3034,8 +3035,9 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
def setUp(self):
self.user = self.login()
# Create an UploadedImage for running tests on
self.uploaded_image = UploadedImage.objects.create(
# Create an UploadedFile for running tests on
self.uploaded_image = UploadedFile.objects.create(
for_content_type=ContentType.objects.get_for_model(get_image_model()),
file=get_test_image_file(),
uploaded_by_user=self.user,
)
@ -3053,11 +3055,11 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
def test_add_post(self):
"""
A POST request to the add view should create an UploadedImage rather than an image,
A POST request to the add view should create an UploadedFile rather than an image,
as we do not have enough data to pass CustomImageWithAuthor's validation yet
"""
image_count_before = CustomImageWithAuthor.objects.count()
uploaded_image_count_before = UploadedImage.objects.count()
uploaded_image_count_before = UploadedFile.objects.count()
response = self.client.post(
reverse("wagtailimages:add_multiple"),
@ -3069,9 +3071,9 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
)
image_count_after = CustomImageWithAuthor.objects.count()
uploaded_image_count_after = UploadedImage.objects.count()
uploaded_image_count_after = UploadedFile.objects.count()
# an UploadedImage should have been created now, but not a CustomImageWithAuthor
# an UploadedFile should have been created now, but not a CustomImageWithAuthor
self.assertEqual(image_count_after, image_count_before)
self.assertEqual(uploaded_image_count_after, uploaded_image_count_before + 1)
@ -3137,10 +3139,10 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
def test_create_from_upload_invalid_post(self):
"""
Posting an invalid form to the create_from_uploaded_image view throws a validation error and leaves the
UploadedImage intact
UploadedFile intact
"""
image_count_before = CustomImageWithAuthor.objects.count()
uploaded_image_count_before = UploadedImage.objects.count()
uploaded_image_count_before = UploadedFile.objects.count()
# Send request
response = self.client.post(
@ -3156,9 +3158,9 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
)
image_count_after = CustomImageWithAuthor.objects.count()
uploaded_image_count_after = UploadedImage.objects.count()
uploaded_image_count_after = UploadedFile.objects.count()
# no changes to image / UploadedImage count
# no changes to image / UploadedFile count
self.assertEqual(image_count_after, image_count_before)
self.assertEqual(uploaded_image_count_after, uploaded_image_count_before)
@ -3194,7 +3196,7 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
Posting a valid form to the create_from_uploaded_image view will create the image
"""
image_count_before = CustomImageWithAuthor.objects.count()
uploaded_image_count_before = UploadedImage.objects.count()
uploaded_image_count_before = UploadedFile.objects.count()
# Send request
response = self.client.post(
@ -3212,7 +3214,7 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
)
image_count_after = CustomImageWithAuthor.objects.count()
uploaded_image_count_after = UploadedImage.objects.count()
uploaded_image_count_after = UploadedFile.objects.count()
# Check response
self.assertEqual(response.status_code, 200)
@ -3223,7 +3225,7 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
self.assertIn("image_id", response_json)
self.assertTrue(response_json["success"])
# Image should have been created, UploadedImage deleted
# Image should have been created, UploadedFile deleted
self.assertEqual(image_count_after, image_count_before + 1)
self.assertEqual(uploaded_image_count_after, uploaded_image_count_before - 1)
@ -3239,7 +3241,7 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
def test_delete_uploaded_image(self):
"""
This tests that a POST request to the delete view deletes the UploadedImage
This tests that a POST request to the delete view deletes the UploadedFile
"""
# Send request
response = self.client.post(
@ -3254,7 +3256,7 @@ class TestMultipleImageUploaderWithCustomRequiredFields(WagtailTestUtils, TestCa
# Make sure the image is deleted
self.assertFalse(
UploadedImage.objects.filter(id=self.uploaded_image.id).exists()
UploadedFile.objects.filter(id=self.uploaded_image.id).exists()
)
# Check JSON

Wyświetl plik

@ -15,7 +15,6 @@ from wagtail.admin.views.generic.multiple_upload import EditView as BaseEditView
from wagtail.images import get_image_model
from wagtail.images.fields import get_allowed_image_extensions
from wagtail.images.forms import get_image_form, get_image_multi_form
from wagtail.images.models import UploadedImage
from wagtail.images.permissions import ImagesPermissionPolicyGetter, permission_policy
from wagtail.images.utils import find_image_duplicates
@ -23,7 +22,6 @@ from wagtail.images.utils import find_image_duplicates
class AddView(BaseAddView):
permission_policy = ImagesPermissionPolicyGetter()
template_name = "wagtailimages/multiple/add.html"
upload_model = UploadedImage
edit_object_url_name = "wagtailimages:edit_multiple"
delete_object_url_name = "wagtailimages:delete_multiple"
@ -35,7 +33,7 @@ class AddView(BaseAddView):
delete_upload_url_name = "wagtailimages:delete_upload_multiple"
edit_upload_form_prefix = "uploaded-image"
context_upload_name = "uploaded_image"
context_upload_id_name = "uploaded_image_id"
context_upload_id_name = "uploaded_file_id"
def get_model(self):
return get_image_model()
@ -131,8 +129,7 @@ class DeleteView(BaseDeleteView):
class CreateFromUploadedImageView(BaseCreateFromUploadView):
edit_upload_url_name = "wagtailimages:create_multiple_from_uploaded_image"
delete_upload_url_name = "wagtailimages:delete_upload_multiple"
upload_model = UploadedImage
upload_pk_url_kwarg = "uploaded_image_id"
upload_pk_url_kwarg = "uploaded_file_id"
edit_upload_form_prefix = "uploaded-image"
context_object_id_name = "image_id"
context_upload_name = "uploaded_image"
@ -160,5 +157,7 @@ class CreateFromUploadedImageView(BaseCreateFromUploadView):
class DeleteUploadView(BaseDeleteUploadView):
upload_model = UploadedImage
upload_pk_url_kwarg = "uploaded_image_id"
upload_pk_url_kwarg = "uploaded_file_id"
def get_model(self):
return get_image_model()

Wyświetl plik

@ -0,0 +1,53 @@
# Generated by Django 4.2.7 on 2024-02-12 21:04
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("contenttypes", "0002_remove_content_type_name"),
("wagtailcore", "0092_alter_collectionviewrestriction_password_and_more"),
]
operations = [
migrations.CreateModel(
name="UploadedFile",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("file", models.FileField(max_length=200, upload_to="wagtail_uploads")),
(
"for_content_type",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="uploads",
to="contenttypes.contenttype",
verbose_name="for content type",
),
),
(
"uploaded_by_user",
models.ForeignKey(
blank=True,
editable=False,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL,
verbose_name="uploaded by user",
),
),
],
),
]

Wyświetl plik

@ -100,16 +100,6 @@ from .audit_log import ( # noqa: F401
LogEntryQuerySet,
ModelLogEntry,
)
from .collections import ( # noqa: F401
BaseCollectionManager,
Collection,
CollectionManager,
CollectionMember,
CollectionViewRestriction,
GroupCollectionPermission,
GroupCollectionPermissionManager,
get_root_collection_id,
)
from .copying import _copy, _copy_m2m_relations, _extract_field_data # noqa: F401
from .i18n import ( # noqa: F401
BootstrapTranslatableMixin,
@ -120,6 +110,17 @@ from .i18n import ( # noqa: F401
bootstrap_translatable_model,
get_translatable_models,
)
from .media import ( # noqa: F401
BaseCollectionManager,
Collection,
CollectionManager,
CollectionMember,
CollectionViewRestriction,
GroupCollectionPermission,
GroupCollectionPermissionManager,
UploadedFile,
get_root_collection_id,
)
from .reference_index import ReferenceIndex # noqa: F401
from .sites import Site, SiteManager, SiteRootPath # noqa: F401
from .specific import SpecificMixin

Wyświetl plik

@ -1,4 +1,6 @@
from django.conf import settings
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils.html import format_html
from django.utils.safestring import mark_safe
@ -188,3 +190,29 @@ class GroupCollectionPermission(models.Model):
unique_together = ("group", "collection", "permission")
verbose_name = _("group collection permission")
verbose_name_plural = _("group collection permissions")
class UploadedFile(models.Model):
"""
Temporary storage for media fields uploaded through the multiple image/document uploader.
When validation rules (e.g. required metadata fields) prevent creating an Image/Document object from the file alone.
In this case, the file is stored against this model, to be turned into an Image/Document object once the full form
has been filled in.
"""
for_content_type = models.ForeignKey(
ContentType,
verbose_name=_("for content type"),
related_name="uploads",
on_delete=models.CASCADE,
null=True,
)
file = models.FileField(upload_to="wagtail_uploads", max_length=200)
uploaded_by_user = models.ForeignKey(
settings.AUTH_USER_MODEL,
verbose_name=_("uploaded by user"),
null=True,
blank=True,
editable=False,
on_delete=models.SET_NULL,
)

Wyświetl plik

@ -15,7 +15,7 @@ import wagtail.contrib.table_block.blocks
import wagtail.fields
import wagtail.images.blocks
import wagtail.images.models
import wagtail.models.collections
import wagtail.models.media
import wagtail.search.index
import wagtail.test.testapp.models
@ -1043,7 +1043,7 @@ class Migration(migrations.Migration):
(
"collection",
models.ForeignKey(
default=wagtail.models.collections.get_root_collection_id,
default=wagtail.models.media.get_root_collection_id,
on_delete=django.db.models.deletion.CASCADE,
related_name="+",
to="wagtailcore.collection",
@ -2244,7 +2244,7 @@ class Migration(migrations.Migration):
(
"collection",
models.ForeignKey(
default=wagtail.models.collections.get_root_collection_id,
default=wagtail.models.media.get_root_collection_id,
on_delete=django.db.models.deletion.CASCADE,
related_name="+",
to="wagtailcore.collection",
@ -2341,7 +2341,7 @@ class Migration(migrations.Migration):
(
"collection",
models.ForeignKey(
default=wagtail.models.collections.get_root_collection_id,
default=wagtail.models.media.get_root_collection_id,
on_delete=django.db.models.deletion.CASCADE,
related_name="+",
to="wagtailcore.collection",
@ -2622,7 +2622,7 @@ class Migration(migrations.Migration):
(
"collection",
models.ForeignKey(
default=wagtail.models.collections.get_root_collection_id,
default=wagtail.models.media.get_root_collection_id,
on_delete=django.db.models.deletion.CASCADE,
related_name="+",
to="wagtailcore.collection",
@ -3891,7 +3891,7 @@ class Migration(migrations.Migration):
(
"collection",
models.ForeignKey(
default=wagtail.models.collections.get_root_collection_id,
default=wagtail.models.media.get_root_collection_id,
on_delete=django.db.models.deletion.CASCADE,
related_name="+",
to="wagtailcore.collection",
@ -3936,7 +3936,7 @@ class Migration(migrations.Migration):
(
"collection",
models.ForeignKey(
default=wagtail.models.collections.get_root_collection_id,
default=wagtail.models.media.get_root_collection_id,
on_delete=django.db.models.deletion.CASCADE,
related_name="+",
to="wagtailcore.collection",
@ -4055,7 +4055,7 @@ class Migration(migrations.Migration):
(
"collection",
models.ForeignKey(
default=wagtail.models.collections.get_root_collection_id,
default=wagtail.models.media.get_root_collection_id,
on_delete=django.db.models.deletion.CASCADE,
related_name="+",
to="wagtailcore.collection",