class PortfolioPageGalleryImage(Orderable): page = ParentalKey(PortfolioPage, on_delete=models.CASCADE, related_name='gallery_images') image = models.ForeignKey('wagtailimages.Image', on_delete=models.CASCADE, related_name='+') caption = models.CharField(blank=True, max_length=250) api_fields = [ APIField('image'), APIField('caption'), APIField('page'), APIField('image_thumbnail', serializer=ImageRenditionField('fill-100x100', source='image')), APIField('image_medium', serializer=ImageRenditionField('max-300x300', source='image')), APIField('image_banner', serializer=ImageRenditionField('fill-500x400', source='image')), APIField('image_full', serializer=ImageRenditionField('max-800x800', source='image')) ] panels = [ ImageChooserPanel('image'), FieldPanel('caption'), ]
class BlogPost(Page): # author = models.ForeignKey('users.User', related_name='blogposts', on_delete=models.SET_NULL, null=True, blank=True) subtitle = models.CharField(max_length=255, blank=True) banner = models.ForeignKey(CustomImage, on_delete=models.SET_NULL, null=True) date = models.DateField("Post date") body = StreamField([ # ('heading', blocks.CharBlock(classname="full title")), ('paragraph', blocks.RichTextBlock()), ('image', APIImageChooserBlock()), ('key_quote', blocks.CharBlock(icon='openquote')), ]) welcome_quote = RichTextField(blank=True, features=['bold', 'link']) welcome_quote_image = models.ForeignKey( CustomImage, on_delete=models.SET_NULL, null=True, blank=True, related_name='blog_welcome_quote_img') categories = ParentalManyToManyField('blog.BlogCategory', blank=True) # author_object = User.objects.get(id=author) # author_name = author_object.get_full_name() content_panels = Page.content_panels + [ # FieldPanel('author'), FieldPanel('subtitle'), FieldPanel('date'), ImageChooserPanel('banner'), StreamFieldPanel('body', classname='collapsible'), FieldPanel('welcome_quote'), ImageChooserPanel('welcome_quote_image'), FieldPanel('categories', widget=django.forms.CheckboxSelectMultiple), ] api_fields = [ APIField('banner'), APIField('banner_resized', serializer=ImageRenditionField('width-1800|jpegquality-80', source='banner')), APIField('thumbnail', serializer=ImageRenditionField('fill-160x160|jpegquality-80', source='banner')), APIField('owner.get_full_name', serializer=serializers.StringRelatedField()), APIField('owner.bio', serializer=serializers.StringRelatedField()), APIField('date'), APIField('subtitle'), APIField('body'), APIField('slug'), APIField('welcome_quote'), APIField( 'welcome_quote_image', serializer=CustomImageRenditionField('width-1200|jpegquality-80')), APIField('categories', serializer=serializers.StringRelatedField(many=True)), ] parent_page_types = ['BlogIndex']
def test_api_representation(self): rendition = self.image.get_rendition("width-400") representation = ImageRenditionField("width-400").to_representation(self.image) self.assertEqual(set(representation.keys()), {"url", "width", "height", "alt"}) self.assertEqual(representation["url"], rendition.url) self.assertEqual(representation["width"], rendition.width) self.assertEqual(representation["height"], rendition.height) self.assertEqual(representation["alt"], rendition.alt)
def test_api_representation(self): rendition = self.image.get_rendition('width-400') representation = ImageRenditionField('width-400').to_representation( self.image) self.assertEqual(set(representation.keys()), {'url', 'width', 'height', 'alt'}) self.assertEqual(representation['url'], rendition.url) self.assertEqual(representation['width'], rendition.width) self.assertEqual(representation['height'], rendition.height) self.assertEqual(representation['alt'], rendition.alt)
class BasePage(BasePageMixin, Page): description = RichTextField(default='') meta_description = models.CharField(max_length=120, blank=True, null=True) og_description = models.CharField(max_length=300, blank=True, null=True) og_image = models.ForeignKey(get_image_model_string(), null=True, on_delete=models.SET_NULL, related_name='+') content_panels = Page.content_panels + [ FieldPanel('description', classname='full'), ] promote_panels = Page.promote_panels + [ MultiFieldPanel([ FieldPanel('meta_description', help_text='in browser text: max chars 120'), FieldPanel('og_description', help_text='social media text: max chars 300'), ImageChooserPanel('og_image'), ], 'Open Graph Content'), ] api_fields = [ APIField('description'), APIField('og_image_400', serializer=ImageRenditionField('width-400', source='og_image')), APIField('og_image_800', serializer=ImageRenditionField('width-800', source='og_image')), APIField('og_image_1920', serializer=ImageRenditionField('width-1920', source='og_image')) ] def save(self, *args, **kwargs): result = super().save(*args, **kwargs) if len(self.title) > 60: raise ValidationError('Must be at least 60 or less chars.') if self.og_description == '': self.og_description = self.meta_description return result class Meta: abstract = True verbose_name = _('basepage') verbose_name_plural = _('basepages')
def get_single(self, obj): desktop_renderition = getattr(settings, 'IMAGE_LARGE_RENDERITION', 'width-1280') mobile_renderition = getattr(settings, 'IMAGE_SMALL_RENDERITION', 'width-480') return { 'large': ImageRenditionField(desktop_renderition).to_representation( obj.image), 'small': ImageRenditionField(mobile_renderition).to_representation( obj.image), 'text': obj.text }
class NewsPage(HeadlessPreviewMixin, Page): date = models.DateField("Post date") intro = models.CharField(max_length=250) body = StreamField([ ("heading", blocks.CharBlock(classname="full title", icon="title")), ("paragraph", blocks.RichTextBlock(icon="pilcrow")), ("image", ImageChooserBlock(icon="image")), ]) image = models.ForeignKey("wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL) content_panels = Page.content_panels + [ FieldPanel("date"), FieldPanel("intro"), ImageChooserPanel("image"), StreamFieldPanel("body", classname="full"), ] api_fields = [ APIField("date"), APIField("intro"), APIField("body"), APIField( "image_thumbnail", serializer=ImageRenditionField("fill-300x300", source="image"), ), ]
class DirectoryEntrySerializer(serializers.ModelSerializer): organization_logo = ImageRenditionField('max-1500x1500') directory_url = serializers.CharField(source='full_url') languages = serializers.SlugRelatedField(slug_field='title', read_only=True, many=True) topics = serializers.SlugRelatedField(slug_field='title', read_only=True, many=True) countries = serializers.SlugRelatedField(slug_field='title', read_only=True, many=True) class Meta: model = DirectoryEntry fields = [ 'title', 'slug', 'directory_url', 'first_published_at', 'landing_page_url', 'onion_address', 'organization_logo', 'organization_description', 'languages', 'topics', 'countries', ]
class SubjectIndexPage(Page): parent_page_types = ['home.HomePage'] subpage_types = ['SubjectArticlePage'] max_count = 1 text = models.TextField(verbose_name='Описание раздела', max_length=800, blank=True) subject_pages = StreamField([ ('subject_page', SubjectPageChooserBlock()), ], blank=True) banner = models.ForeignKey( 'wagtailimages.Image', on_delete=models.SET_NULL, related_name='+', null=True ) api_fields = [ APIField('text'), APIField('subject_pages'), APIField('banner', serializer=ImageRenditionField(BANNER_SIZE)) ] content_panels = Page.content_panels + [ FieldPanel('text', heading='Описание раздела'), StreamFieldPanel('subject_pages', heading='Основные страницы сюжетов'), ImageChooserPanel('banner') ] def get_sitemap_urls(self, request): return [{ 'location': self.full_url[:-1], 'lastmod': self.last_published_at, }] class Meta: verbose_name = 'Индексная сюжета'
class FakeNewsPage(Page): parent_page_types = ["fakenews.FakeNewsIndexPage"] year = models.IntegerField("Year") author = models.CharField(max_length=250, blank=True) image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL ) introduction = models.TextField(blank=True) body = StreamField( [ ("heading", blocks.CharBlock(icon="title")), ("paragraph", blocks.RichTextBlock(icon="pilcrow")), ] ) content_panels = Page.content_panels + [ FieldPanel("year"), FieldPanel("author"), ImageChooserPanel("image"), FieldPanel("introduction"), StreamFieldPanel("body"), ] api_fields = [ APIField("year"), APIField("author"), APIField("image"), APIField( "image_thumbnail", serializer=ImageRenditionField("width-400", source="image"), ), APIField("introduction"), APIField("body"), ]
class BlogEntryPage(Page): page_ptr = models.OneToOneField(Page, parent_link=True, related_name='+', on_delete=models.CASCADE) body = RichTextField() tags = ClusterTaggableManager(through='BlogEntryPageTag', blank=True) date = models.DateField("Post date") feed_image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+' ) api_fields = ( APIField('body'), APIField('tags'), APIField('date'), APIField('feed_image'), APIField('feed_image_thumbnail', serializer=ImageRenditionField('fill-300x300', source='feed_image')), APIField('carousel_items'), APIField('related_links'), ) search_fields = Page.search_fields + [ index.SearchField('body'), ] def get_blog_index(self): # Find closest ancestor which is a blog index return BlogIndexPage.ancestor_of(self).last()
class BlogAuthorsOrderable(Orderable): """us to select one or more blog authors from Snippet""" page = ParentalKey("BlogDetailPage", related_name="blog_authors") author = models.ForeignKey("BlogAuthor", on_delete=models.CASCADE) panels = [SnippetChooserPanel("author")] @property def author_name(self): return self.author.name @property def author_website(self): return self.author.website @property def author_image(self): return self.author.image api_fields = [ APIField("author_name"), APIField("author_website"), # This is using a custom django rest framework serializer APIField("author_image", serializer=ImageSerializedField()), # The below APIField is using a Wagtail-built DRF Serializer that supports # custom image rendition sizes APIField("image", serializer=ImageRenditionField('fill-200x250', source="author_image")), ]
class BlogAuthorOrderable(Orderable): """ This allows us to select one or more authors to a post """ page = ParentalKey('blog.BlogDetailPage', related_name='blog_authors') author = models.ForeignKey( 'blog.BlogAuthor', on_delete=models.CASCADE, ) panels = [ SnippetChooserPanel('author'), ] @property def author_name(self): return self.author.name @property def author_website(self): return self.author.website @property def author_image(self): return self.author.image api_fields = [ APIField('author_name'), APIField('author_website'), #APIField('author_image', serializer=ImageSerializedField()), APIField('image', serializer=ImageRenditionField('fill-200x250', source='author_image')), ]
class MoviesIndexPage(Page): """Movies index page""" template = "movie/movies_index.html" sub_title = models.CharField(blank=False, null=False, max_length=255) hero = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) api_fields = [ APIField('sub_title'), APIField('hero', serializer=ImageRenditionField('fill-1920x780')), ] content_panels = Page.content_panels + [ MultiFieldPanel([ FieldPanel('sub_title'), ImageChooserPanel('hero'), ], heading="Header") ] subpage_types = ['movie.MoviePage'] def get_context(self, request, *args, **kwargs): context = super().get_context(request, *args, **kwargs) context["movies"] = MoviePage.objects.live().public() return context def __str__(self): return self.title
class SeriesIndexPage(Page): """Series index page""" template = "series/series_index.html" sub_title = models.CharField(blank=False, null=False, max_length=255) hero = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) api_fields = [ APIField('sub_title'), APIField('hero', serializer=ImageRenditionField('fill-1920x780')), ] content_panels = Page.content_panels + [ MultiFieldPanel([ FieldPanel('sub_title'), ImageChooserPanel('hero'), ], heading="Header"), ] parent_page_types = ['home.HomePage'] subpage_types = ['series.SeriesIndexPage', 'series.SeriesPage'] def get_context(self, request, *args, **kwargs): """Adding custom stuff to our context.""" context = super().get_context(request, *args, **kwargs) context["series"] = SeriesPage.objects.live().public() return context
class NewsPage(HeadlessPreviewMixin, Page): intro = models.CharField(max_length=250) body = StreamField([ ('heading', blocks.CharBlock(classname="full title")), ('paragraph', blocks.RichTextBlock()), ('image', ImageChooserBlock()), ]) image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL ) content_panels = Page.content_panels + [ FieldPanel('intro'), ImageChooserPanel('image'), StreamFieldPanel('body'), ] api_fields = [ APIField('intro'), APIField('body'), APIField('image_thumbnail', serializer=ImageRenditionField('fill-300x300', source='image')), ]
class LegislationIndexPage(Page): parent_page_types = ['home.HomePage'] subpage_types = ['legislation.LawsSectionPage'] max_count = 1 banner = models.ForeignKey('wagtailimages.Image', on_delete=models.SET_NULL, related_name='+', null=True) @property def sections(self): return [{ 'id': child.id, 'title': child.title, 'url': child.url } for child in self.get_children()] content_panels = Page.content_panels + [ ImageChooserPanel('banner', heading='Иллюстрация') ] api_fields = [ APIField('banner', serializer=ImageRenditionField(BANNER_SIZE)), APIField('sections') ] def get_sitemap_urls(self, request): return [] class Meta: verbose_name = 'Страница Законодательства'
class AllBlogsListingPage(Page): """ Главная всех блогов """ max_count = 1 subpage_types = ['blog.BlogIndexPage'] banner = models.ForeignKey('wagtailimages.Image', on_delete=models.SET_NULL, related_name='+', null=True) api_fields = [ APIField('banner', serializer=ImageRenditionField(BANNER_SIZE)) ] content_panels = Page.content_panels + [ ImageChooserPanel('banner', heading='Иллюстрация') ] def get_sitemap_urls(self, request): return [{ 'location': self.full_url[:-1], 'lastmod': self.last_published_at, }] class Meta: verbose_name = 'Индексная всех блогов'
class WorkPage(Page): """Each individual blog post goes here""" job_title = models.CharField(max_length=100, blank=False, null=True) work_image = models.ForeignKey( "wagtailimages.Image", null=True, blank=False, on_delete=models.SET_NULL, related_name="+", ) work_skills = ClusterTaggableManager(through=WorkSkill, blank=True) api_fields = [ APIField("job_title"), APIField( "work_image", serializer=ImageRenditionField("max-500x500"), ), APIField("work_skills"), ] content_panels = Page.content_panels + [ FieldPanel("job_title"), ImageChooserPanel("work_image"), FieldPanel("work_skills"), ] pass
class BlogIndex(Page): banner = models.ForeignKey(CustomImage, on_delete=models.SET_NULL, null=True) intro = models.TextField(blank=True) subheading = models.CharField(max_length=120, blank=True) categories = BlogCategory.objects.all() content_panels = Page.content_panels + [ ImageChooserPanel('banner'), FieldPanel('subheading'), FieldPanel('intro', classname='full'), ] api_fields = [ APIField('banner'), APIField('banner_resized', serializer=ImageRenditionField('width-1800|jpegquality-80', source='banner')), APIField('intro'), APIField('subheading'), APIField('categories', serializer=serializers.StringRelatedField(many=True)) ] parent_page_types = ['home.HomePage'] max_count = 1
class StandardPage(BasePage): template = 'patterns/pages/standardpages/information_page.html' subpage_types = ['standardpages.StandardPage'] introduction = models.TextField(blank=True) body = StreamField(StoryBlock()) featured_image = models.ForeignKey('images.CustomImage', null=True, blank=True, related_name='+', on_delete=models.SET_NULL) featured_image_caption = models.CharField( blank=True, max_length=250, ) biography = models.CharField( help_text="Use this field to override the author's biography " "on this page.", max_length=255, blank=True) search_fields = BasePage.search_fields + [ index.SearchField('introduction'), index.SearchField('body'), ] content_panels = BasePage.content_panels + [ FieldPanel('introduction'), MultiFieldPanel( [ ImageChooserPanel('featured_image'), FieldPanel('featured_image_caption'), ], heading="Featured Image", ), StreamFieldPanel('body'), InlinePanel('authors', label="Authors"), ] # Export fields over REST API api_fields = [ APIField('introduction'), APIField('body'), APIField('featured_image', serializer=ImageRenditionField('fill-1920x1080')), APIField('featured_image_caption'), ] # Export fields over GraphQL graphql_fields = [ GraphQLString("introduction"), GraphQLStreamfield("body"), GraphQLImage("featured_image"), GraphQLString("featured_image_caption"), ] class Meta: verbose_name = "Standard Page"
def create_image(self, data): model = get_image_model() image = model.objects.get(id=data['id']) large_renderition = getattr(settings, 'IMAGE_LARGE_RENDERITION', 'width-1280') small_renderition = getattr(settings, 'IMAGE_BANNER_RENDERITION', 'fill-300x200') return { 'id': data['id'], 'title': image.title, 'caption': image.caption, 'large': ImageRenditionField(large_renderition).to_representation(image), 'small': ImageRenditionField(small_renderition).to_representation(image), }
class GuidelineAuthorsOrderable(Orderable): """ Выбор одного или нескольких авторов памятки """ page = ParentalKey("guidelines.GuidelinePage", related_name="guideline_authors") author = models.ForeignKey( "base.Author", on_delete=models.CASCADE, ) panels = [ SnippetChooserPanel("author"), ] @property def full_name(self): return self.author.full_name @property def inner_link(self): return self.author.inner_link @property def outer_link(self): return self.author.outer_link @property def short_name(self): return self.author.short_name @property def author_image(self): return self.author.image @property def ava(self): return self.author.ava @property def alias(self): return self.author.alias @property def profession(self): return self.author.profession api_fields = [ APIField('full_name'), APIField('short_name'), APIField('inner_link'), APIField('outer_link'), APIField('ava', serializer=ImageRenditionField('fill-24x24')) ]
class PostPage(Page): """ Model of the PostPage Parameters : parent_page_types: List of the accepted parent type page subpage_types: List of the accepted child page type header_image: Front image of the post body: StreamField using BodyBlock blocks tags: tags of the post relations to Tag model through PostPage model content_panels: specify witch attributs will be display in Admin Page api_fields : Specify witch attribut will be displayed for API """ parent_page_types = ["blog.BlogPage"] subpage_types = [] # This object (page) can not create child pages header_image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) body = StreamField(BodyBlock(), blank=True) tags = ClusterTaggableManager(through="blog.PostPageTag", blank=True) # Used to display the field in wagtail admin content_panels = Page.content_panels + [ ImageChooserPanel("header_image"), # The categories relationship is already defined in PostPageBlogCategory.page.related_name InlinePanel("categories", label="category"), FieldPanel("tags"), StreamFieldPanel("body"), ] # API Fields that will be dissplay in RestAPI api_fields = ( APIField( "header_image_url", serializer=ImageRenditionField( "max-1000x800", # We use ImageRenditionField to control the headers_image size source="header_image"), ), "body", APIField("owner"), APIField("api_tags", serializer=TagField(source="tags")), APIField("pub_date", serializer=serializers.DateTimeField( format="%d %B %Y", source="last_published_at")), APIField("api_categories", serializer=CategoryField(source="categories")), )
class BannerSerializer(serializers.Serializer): spec = getattr(settings, 'IMAGE_BANNER_RENDERITION', 'fill-300x200') title = serializers.CharField(source='banner_title', required=False) subtitle = serializers.CharField(source='banner_subtitle', required=False) image = ImageRenditionField(spec, source='banner_image') class Meta: fields = [ 'title', 'subtitle', 'image', ]
class HomePage(Page): """Home page model""" max_count = 1 name = models.CharField(max_length=30, blank=False, null=True) about_me_summary = RichTextField() about_me_headshot = models.ForeignKey( "wagtailimages.Image", null=True, blank=False, on_delete=models.SET_NULL, related_name="+", ) content_panels = Page.content_panels + [ FieldPanel("name"), FieldPanel("about_me_summary"), ImageChooserPanel("about_me_headshot"), ] api_fields = [ APIField("name"), APIField("about_me_summary"), APIField( "headshot_500_x_500", serializer=ImageRenditionField("max-500x500", source="about_me_headshot"), ), APIField( "headshot_200_x_200", serializer=ImageRenditionField("max-200x200", source="about_me_headshot"), ), ] # @property # def get_child_pages(self): # return self.get_children().public().live() pass
class PostPage(BasePage): header_image = models.ForeignKey( "wagtailimages.Image", null=True, blank=True, on_delete=models.SET_NULL, related_name="+", ) body = StreamField(BodyBlock(), blank=True) tags = ClusterTaggableManager(through="blog.PostPageTag", blank=True) content_panels = Page.content_panels + [ ImageChooserPanel("header_image"), InlinePanel("categories", label="category"), FieldPanel("tags"), StreamFieldPanel("body"), ] api_fields = ( APIField( "header_image_url", serializer=ImageRenditionField("max-1000x800", source="header_image"), ), "body", APIField("owner"), APIField("api_tags", serializer=TagField(source="tags")), APIField("api_categories", serializer=CategoryField(source="categories")), APIField( "pub_date", serializer=DateTimeField(format="%d %B %Y", source="last_published_at"), ), ) def get_preview_url(self, token): return urllib.parse.urljoin( self.get_client_root_url(), f"post/{self.pk}/" + "?" + urllib.parse.urlencode({ "content_type": self.get_content_type_str(), "token": token }), ) def serve(self, request, *args, **kwargs): return HttpResponseRedirect( urllib.parse.urljoin(self.get_client_root_url(), f"/post/{self.pk}"))
class SamplesIndexPage(Page): parent_page_types = ['home.HomePage'] subpage_types = ['samples.SamplePage'] max_count = 1 banner = models.ForeignKey( 'wagtailimages.Image', on_delete=models.SET_NULL, related_name='+', null=True, blank=True, ) @property def tags_menu(self): sample_pages = self.get_children() tags_menu = list() for sample in sample_pages: for tag in sample.specific.tags.all(): tags_item = {'name': tag.name, 'slug': tag.slug} if tags_item not in tags_menu: tags_menu.append(tags_item) tags_menu = sorted(tags_menu, key=lambda tag: ord(tag['name'][0].lower())) return tags_menu @property def breadcrumbs(self): breadcrumbs = [] for page in self.get_ancestors()[2:]: breadcrumbs.append({'title': page.title, 'url': page.url}) return breadcrumbs api_fields = [ APIField('breadcrumbs'), APIField('tags_menu'), APIField('banner', serializer=ImageRenditionField(BANNER_SIZE)) ] content_panels = Page.content_panels + [ ImageChooserPanel('banner', heading='Иллюстрация') ] def get_sitemap_urls(self, request): return [{ 'location': self.full_url[:-1], 'lastmod': self.last_published_at, }] class Meta: verbose_name = 'Все образцы документов'
class ProjectsPage(Page): # db fields project_h_one = models.CharField(max_length=250, default="Project Name") project_h_two = models.CharField(max_length=250, default="Project Description") project_intro_p = models.TextField(blank=True) project_p = models.CharField(max_length=250, default="Project Launch Date") project_tech_stack_description = RichTextField(blank=True, features=["ul"]) project_url = models.URLField(max_length=200, default="Project URL") project_image = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') # Search index configuration search_fields = Page.search_fields + [ index.SearchField('project_h_one'), index.FilterField('project_h_two'), index.FilterField('project_intro_p'), index.FilterField('project_p'), index.FilterField('project_tech_stack_description'), ] # Editor panels configuration content_panels = Page.content_panels + [ FieldPanel('project_h_one'), FieldPanel('project_h_two', classname="full"), FieldPanel('project_intro_p', classname="full"), FieldPanel('project_p', classname="full"), FieldPanel('project_tech_stack_description', classname="full"), FieldPanel('project_url', classname="full"), ImageChooserPanel('project_image'), ] promote_panels = [ MultiFieldPanel(Page.promote_panels, "Common page configuration"), ] # API configuration api_fields = [ APIField('project_h_one'), APIField('project_h_two'), APIField('project_intro_p'), APIField('project_p'), APIField('project_tech_stack_description'), APIField('project_url'), APIField('project_image'), APIField('project_image_url', serializer=ImageRenditionField('fill-700x700', source='project_image')), ]
def to_representation(self, paragraph): value = paragraph.value paragraph = value['paragraph'] dic = { 'paragraph': paragraph.source, } keys = value.keys() if 'title' in keys: dic['title'] = value['title'] if 'image' in keys: dic['image'] = ImageRenditionField( 'fill-2000x2000-c80|jpegquality-100').to_representation( value['image']) return dic