I'm using the Froala Django Editor in some forms in my Django REST Framework backend, such as this
# resources/forms.py
from django import forms
from froala_editor.widgets import FroalaEditor
from .models import Resource
class ResourceForm(forms.ModelForm):
class Meta:
model = Resource
fields = '__all__'
widgets = {
'content': FroalaEditor(
options={
'heightMin': 256
}
)
}
When I try to upload an image (or a video, or any file, but one thing at a time) in the Froala editor I get an error:
In the console I have:
GET https://{some-id}.cloudfront.net/uploads/froala_editor/images/Nights.of.Cabiria.jpg [HTTP/2 403 Forbidden 15ms]
The error above made me wonder that perhaps the image is being uploaded correctly, but the Froala editor can't get it after uploading in order to display it.
The application is being hosted in AWS and the uploaded files stored in S3 buckets.
And in fact, I checked in the S3 dashboard, and the images are there, so they have uploaded correctly.
Even though I'm using all default FROALA_EDITOR_OPTIONS. I'm aware there are specific options for S3 storage (I've tried them) but I'm not using them and it is uploading fine.
Still looking at that error, I remembered that in other models in the project I have ImageFields, for example
# users/models.py
class User(AbstractUser):
name = models.CharField(_('First name'), db_index=True, max_length=255)
image = models.ImageField(upload_to=user_image_bucket, verbose_name=_('Image'))
def signed_image_url(self):
try:
return sign_cloudfront_url(self.image.url)
except ValueError:
return None
and that the serializers for these models always return the signed url, not the original url of the image
# users/serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (
'id',
'name',
'signed_image_url',
)
I don't understand much about AWS S3, but I suppose that the images stored there are not publicly accessible, and providing a signed url to an image grants access to it.
Knowing this, I believe that what I need to do is to apply the same sign_cloudfront_url function to the images uploaded via the Froala Editor.
According to the Froala docs, you can set some events listeners on the Froala Editor options, such as image.uploaded, and I think this is where I should get the url of the uploaded image and return a signed url, but I'm not being able to set these events.
If I do this:
# resources/forms.py
from django import forms
from froala_editor.widgets import FroalaEditor
from .models import Resource
class ResourceForm(forms.ModelForm):
class Meta:
model = Resource
fields = '__all__'
def uploaded():
print("hello world")
widgets = {
'content': FroalaEditor(
options={
'heightMin': 256,
'events': {
'image.uploaded': uploaded,
}
}
)
}
I get a very expected Object of type function is not JSON serializable error.
Any idea how I should handle this?
Related
Understand I can add a validator to Django's ImageField validators to restrict file extension types like below. But in terms of the error messages which are displayed via upload on Admin -- I'm still seeing the standard file type list (via PIL allowed types), if I upload a non-image type. If I upload an image type which is not in my custom allowed_extensions below, I see my custom message. How can I override Django's default ImageField handling, and show my custom error message no matter what type of file is uploaded (e.g. when any file other than .png is uploaded per below example)?
class MM(models.Model):
file_extension_validator = FileExtensionValidator(
allowed_extensions=['png'],
message='File extension not allowed. Allowed extensions include .png'
)
image = models.ImageField(
help_text='Upload images only (.png).',
validators=[file_extension_validator],
max_length=255,
blank=False,
null=False
)
The problem is not the model field, but the form field. The form field has a default validator that lists all the extensions PIL supports.
You can make a special form field ModifiedImageField and specify that for the ModelForm that will be used by the MyModelAdmin in this case:
from django.contrib import admin
from django.core.validators import FileExtensionValidator
from django import forms
image_validator = FileExtensionValidator(
allowed_extensions=['png'],
message='File extension not allowed. Allowed extensions include .png'
)
class ModifiedImageField(forms.ImageField):
default_validators = [image_validator]
class MyModelAdminForm(forms.ModelForm):
imagefield = ModifiedImageField()
class MyModelAdmin(admin.ModelAdmin):
form = MyModelAdminForm
where imagefield is the name of the ImageField for which you want to replace the validator.
I mostly work with Node.js & MongoDB and I am pretty new to SQL dbs especially postgreSQL I am writing an application that makes use of django-rest-framework & postgreSQL as a DB.
This is how my data structure as .json should look like.
{
id: "19eea956-34e5-11eb-adc1-0242ac120002"
picture: [{
url: "",
mimeType: ""
},
{
url: "",
mimeType: ""
}]
}
For the above data I am currently writing models.py which looks like as follows.
from django.db import models
from django.contrib.postgres.fields import ArrayField
class Picture(models.Model):
url = models.CharField()
mimeType = models.CharField()
class A(models.Model):
id = models.CharField(max_length=120, primary_key=True)
picture = ArrayField(Picture)
def __str__(self):
return self.id
What I am trying to do in my models.py is to have picture as an Array of Objects or in python terminology List of Dictionaries.
I read about ArrayField in postgreSQL but unable to find any example about how to define Array of Objects in models.py, any help here would be appreciated.
Thanks :)
In relational databases relations are defined by Foreign Keys and different tables. Tables are represented by Django's models, but the programmer should work from the model side of things and think of the database as the object persistence (storage of the state of an object).
Fields should as a rule be single values, not containers. Explaining why distracts too much from the problem at hand, but here's the in-depth info.
In this case, you have two entities, let's call A "Gallery" for clarity. A Gallery object has 1 or more pictures. A picture can be associated with 1 gallery (business rule). There are 2 properties associated with the image: url and mime type.
Now there's several ways to deal with images and that depends whether the image is uploaded or really a URL to a remote image.
I'm going to pick the second option for brevity:
import uuid
from django.db import models
class Gallery(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
name = models.CharField(max_length=40)
class Picture(models.Model):
url = models.URLField()
mime_type = models.CharField(max_length=25)
gallery = models.ForeignKey(Gallery, on_delete=models.CASCADE, related_name='pictures')
This creates the correct relation for the image in a way that is preferred by both Django and relational databases.
Now we need to serialize the picture to just the url and mime type field:
from rest_framework import serializers
from .models import Picture, Gallery
class PictureSerializer(serializers.ModelSerializer):
class Meta:
model = Picture
fields = ['mime_type', 'url']
Continuing, we need to nest the pictures into the gallery:
class GallerySerializer(serializers.ModelSerializer):
pictures = PictureSerializer(many=True)
class Meta:
model = Gallery
fields = ['id', 'pictures']
And this should do the trick.
The reason people downvoted is most likely because this is a Q&A site and your scope as demonstrated by my answer is far too big for that. I've given you some handles to work with, but it's best you hit the Django tutorial to get a basic sense of models, followed by the DRF counterpart.
I have a blog on django on which any public can post. In post content I am using django-ckeditor RichTextUploadingField.
There is button Browse server for images in ckeditor, that let users browse images of server's upload directory and embed images in post.
But i want to restrict public from browsing images on server when they make post. They should be able upload images only, not browse every image on server that is uploaded.
Here is my models.py
class Article(models.Model):
title = models.CharField(max_length = 200)
content = RichTextUploadingField()
author = models.ForeignKey(User, on_delete= models.CASCADE, null=True)
def __str__(self):
return self.title
Forms.py
class ArticleForm(ModelForm):
class Meta:
model = Article
widgets = {
'content': RichTextUploadingField()
}
A direct setting to remove this functionality isnt provided but CKEDITOR_RESTRICT_BY_USER = True could be used to achieve the same.
Reference from the documentation:
Set the CKEDITOR_RESTRICT_BY_USER setting to True in the project's
settings.py file (default False). This restricts access to uploaded
images to the uploading user (e.g. each user only sees and uploads
their own images). Upload paths are prefixed by the string returned by
get_username. If CKEDITOR_RESTRICT_BY_USER is set to a string, the
named property is used instead. Superusers can still see all images.
NOTE: This restriction is only enforced within the CKEditor media
browser.
I am new to using Django. And I would like to customize TinyMCE editor for myself. I downloaded it and added to the project as a third part library, did not install it through pip. As you know, there is no free local file uploader in TinyMCE. And I'd like to do 3 things: local image uploder, local audio/video uploader, and local file uploader(with any extension(.pdf, .c, .cpp), this is like how you add a file at the end of a post so that users can download it). And during the realization I had the following issues.
I implemented the local image uploader with TinyMCE file_picker_callback(), and everything works fine. I can upload and edit photos locally, and all of this is displayed on the view page template. The path of each image is recorded in the textarea field in MySQL DB as src atribute. Whether each image should be uploaded(copied) to the MEDIA folder of the site or in a separate field in the MySQL DB. And how it can be implemented, how to write and call the python handler in the js file?
And I still do not download audio / video files. It seems for this in js file, after pressing the button it is necessary to wrap them in the appropriate HTML5 audio/video tags. Then, like the images, copy to the database or Media folder. I also don’t know how to write a Python handler and call it in js.
To upload files, I made my custom plugin and added it to TinyMCE. In plugin I created an input element and stopped there.
Now I have been suffering from it for a month, but I really want to do it. Because having made one full-featured text editor, you can use it many times in other projects. And I think that it needs to many people. If there are interested, then we could realize it together.
There are php handlers on the Internet. But Python handlers for this purpose, I did not find. Any help and tips are welcome. I use Django 2.0.8 and python 3.6. The editor is in the admin panel.
My models.py:
class Post(models.Model):
title = models.CharField(max_length=150)
slug = models.SlugField(unique=True)
description = models.TextField()
content = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
tags = TaggableManager(blank=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, default=1, on_delete=models.CASCADE, related_name="post_author")
class Meta:
ordering = ["-created", "-updated"]
admin.py:
class PostModelAdmin(admin.ModelAdmin):
list_display = ["title", "updated", "created"]
list_display_links = ["title"]
list_filter = ["created", "tags"]
search_fields = ["title", "content",]
form = MyTextForm
class Meta:
model = Post
class Media:
js = ('js/tinymce/tinymce.js', 'js/init-tinymce.js',
'//ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js',)
admin.site.register(Post, PostModelAdmin)
forms.py
class MyTextForm(forms.ModelForm):
class Meta:
fields = '__all__'
model = Post
widgets = {
'content': forms.Textarea(attrs={'class': 'tinymce', 'label' : 'Content'}),
}
And in the DB images stored as(into the content field):
<p><img src="data:image/jpeg;base64,/9j/4AAQSkZJRgH/2Q==" alt="" width="439" height="604"/></p>
I have checked many uploaders for django image field. But I am unable to get a simple clear way of doing multiple image uploads in Django.
My requirement is
Class Foo(models.Model):
images = SomeImageField(upload_to = "/path/")
This should allow me to upload multiple images. Now django-photologue allows Gallery upload, but this is only in zip format. I want something similar. Is there any such app available ?
django-filer will allow you to upload multiple images via a separate interface (not via a model field, but via the django admin), but you will only be able to select one of those uploaded image per image field. What you need to do is implement a django admin StackedInline or something similar
# models.py
from django.db import models
from filer.fields.imagefields import FilerImageField
class MyObject(models.Model):
name = models.CharField(...)
class Image(models.Model):
image_file = FilerImageField()
obj = models.ForeignKey(MyObject, ...)
# admin.py
from django.contrib import admin
from models import Image, MyObject
class ImageInline(admin.StackedInline):
model = Image
class MyObjectAdmin(admin.ModelAdmin):
inlines = [ImageInline, ]
...
now you will be able to easily attach multiple images to a single instance of your object via the admin.
I don't know of any apps that allow for a single field to manage multiple images.