Wagtail generic gallery implementation and OneToOneField - wagtail

http://docs.wagtail.io/en/v1.13.1/getting_started/tutorial.html
The wagtail getting_started tutorial intros a blog gallery feature, implements as below:
class BlogPage(Page):
...
class BlogPageGalleryImage(Orderable)
page = ParentalKey(BlogPage, related_name='gallery_images')
image = ...
This way works, however BlogPageGalleryImage couples with BlogPage model. My intention is to make a generic gallery model which can be embbed with any model(page). The idea is using an intermediate Gallery model:
class BlogPage(Page):
gallery = models.OneToOneField(Gallery, on_delete=models.SET_NULL, null=True)
...
class Gallery(Page):
pass
class GalleryImage(Orderable):
gallery = ParentalKey(Gallery, related_name='images')
Then in code, we can get the images via blog.gallery.images.
My question is how to get it work with wagtail admin interface to inline create/edit the gallery object (OneToOneField) when editing the blog page object.

One way to do this is via a more generic relationship for your Page-Image connection, relating this to the Page model, rather than a specific BlogPage model.
This means that any page can have gallery images, you just need to expose the field to content panels via an InlinePanel.
You can also create a Mixin class to make some helpful methods available without rewriting them each time.
Here is an example:
from django.db import models
from wagtail.admin.edit_handlers import InlinePanel
from wagtail.core.models import Orderable, Page
from wagtail.images.edit_handlers import ImageChooserPanel
class ImageGalleryRelationship(Orderable, models.Model):
""" Relationship between any `Page` and `Image` for an image gallery."""
page = ParentalKey(Page, related_name='gallery_page')
image = models.ForeignKey('wagtailimages.Image', related_name='gallery_image')
panels = [ImageChooserPanel('image')]
class PageGalleryMixin():
def gallery_images(self):
images = [g.image for g in self.gallery_page.all()]
return images
class BlogPage(Page, PageGalleryMixin):
# all page fields, gallery does not need to be defined here
content_panels = Page.content_panels + [
InlinePanel('gallery_page', label='Image Gallery'),
#...
]
Note: This is not a OneToOne connection, InlinePanel requires a ParentalKey relationship. There is no real 'Gallery' model in this solution just a set of orderable relationships.

In general app (or wherever), models.py
class PageGalleryImage(Orderable):
page = ParentalKey(Page,
on_delete=models.CASCADE,
related_name='image_gallery')
image = models.ForeignKey('wagtailimages.Image',
on_delete=models.CASCADE,
related_name='page_gallery_image')
caption = models.CharField(blank=True, max_length=250)
panels = [
ImageChooserPanel('image'),
FieldPanel('caption'),
]
Other apps as blog, models.py:
class BlogPage(Page):
content_panels = Page.content_panels + [
...
InlinePanel('image_gallery', label="Gallery images"),
]
This provides one app = one gallery.

Related

How to combine django crispy form layout and quill JS?

I am trying to combine crispy form layout with quill js that I am using for my description field but in the dev tools it does render the quill classes and stuff but the problem is, it is not showing on the page itself. I want to add the safe filter(guess that's what is missing to it) but I don't know how. I looked at the documentation but found no answer to that particular issue.
class CreateProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = "__all__"
def __init__(self, *args, **kwargs):
super(CreateProjectForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout()
Not using any layout for now.
class Project(models.Model):
typeChoices = (
("Software Development", "Software Development"),
("Task Management", "Task Management"),
("Business Management", "Business Management"),
)
project_type = models.CharField(max_length=25, choices=typeChoices)
slug = models.SlugField(max_length=30)
key = models.CharField(max_length=7, unique=True)
project_description = QuillField(blank=True, null=True)
def __str__(self):
return self.project_name
I want to have something like this {{description|safe}} in the description field itself. Any help would be appreciated. Thanks

ImageChooserPanel wrongfully showing as Select widget

I find stack overflow very difficult to use and I am probably going to be slammed for trying but here goes.
I am trying to get an image field to bring up the standard wagtail image chooser dialog but it's displaying in wagtail admin as a Select widget with no option to upload new image.
from django.db import models
from modelcluster.fields import ParentalKey
from wagtail.core.models import Page, Orderable
from modelcluster.models import ClusterableModel
from wagtail.admin.edit_handlers import (
FieldPanel,
MultiFieldPanel,
InlinePanel,
PageChooserPanel,
)
from wagtail.images.edit_handlers import ImageChooserPanel
class HomePage(Page):
def get_context(self, request):
context = super().get_context(request)
# Add extra variables and return the updated context
context['sections'] = Sections.objects.all()
return context
class Sections(ClusterableModel):
title = models.CharField(max_length = 60, blank = False, null= True)
section_image = models.ForeignKey(
"wagtailimages.Image",
null=True,
blank=False,
on_delete=models.SET_NULL,
related_name="+",
)
panels = [
FieldPanel("title"),
ImageChooserPanel("section_image"),
InlinePanel("albums"),
]
class Albums(ClusterableModel):
title = models.CharField(max_length = 60, blank = False, null= True)
section = ParentalKey("Sections", related_name="albums")
panels = [
FieldPanel("title"),
InlinePanel("images"),
]
class GalleryImage(Orderable):
album = ParentalKey("Albums", related_name="images")
galleryimage = models.ForeignKey(
"wagtailimages.Image",
null=True,
blank=False,
on_delete=models.SET_NULL,
related_name="+",
)
panels = [
ImageChooserPanel("galleryimage"),
]
This is probably a rookie mistake and would appreciate if someone can show me why gallery image is not rendering correctly.
Unfortunately this is an open bug in Wagtail: https://github.com/wagtail/wagtail/issues/5126
Historically, nesting InlinePanels has not been well-supported in Wagtail - there are some improvements in progress which will hopefully make it into the forthcoming 2.7 release, but this particular issue is still outstanding.

Render a form with initial values in WagTail

I need to render a form, with pre-filled data but it seems to not be possible in WagTail. I'm trying to do it the "Django way" using MyForm(initial={"field_name": value}) (MyForm inherits WagtailAdminModelForm if this is necessary), but this is not possible since MyForm doesn't have a Meta.model field and, as I understand, it cannot be specified due to how WagTail is designed.
Are there any work-arounds or alternative ways to render a pre-filled form?
# models.py
from django.db import models
from wagtail.core.models import Page
from wagtail.admin.edit_handlers import FieldPanel
from wagtail.admin.forms import WagtailAdminPageForm
class BlogForm(WagtailAdminPageForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
my_field = self.fields["my_field"]
my_field.widget.attrs["value"] = "My new initial data"
class Blog(Page):
my_field = models.CharField(max_length=255, default='', blank=True)
content_panels = Page.content_panels + [
FieldPanel("my_field"),
]
base_form_class = BlogForm

How to add list filter and search field in Wagtail default admin Page

Is there any way to put a search field and list filters in a Page-derived model, without customize a ModelAdmin? I would like to use the default admin page for Page-derived model.
models.py
class FolderPage(Page):
body = StreamField([
('paragraph', blocks.RichTextBlock()),
('embedded_video', EmbedBlock(icon='media')),
('table', TableBlock()),
], null=True, blank=True, verbose_name=u'Corpo da Notícia')
search_fields = Page.search_fields + [
index.SearchField('body'),
index.SearchField('title'),
index.FilterField('live'),
]
Currently it is a feature in development, you cand see here in order to get a direction about that.

Django CreateAPIView not saving image portion of django model

I am trying to make a django rest api which allows admin users to add images which the api clients can sync and display. My view responsible for creating the Clothing model, which holds a title and an image, is not working as it only saves the title but not the image.
Here is the Clothing model:
class Clothing(models.Model):
title = models.CharField(max_length=50, blank=False)
img = models.ImageField(blank=True, null=True, upload_to='catalog/')
Here is the view:
class AddClothingView(CreateAPIView):
queryset = Clothing.objects.all()
serializer_class = ClothingSerializer
And here is the serializer:
class ClothingSerializer(ModelSerializer):
class Meta:
model = Clothing
fields = '__all__'
How can I fix this such that the images are saved in the catalog/ folder in my project?

Resources