class Migration(migrations.Migration): dependencies = [ ('fluent_contents', '0001_initial'), ('cms', '0003_merge_20161207_1037'), ] operations = [ migrations.CreateModel( name='ProjectsMapContent', fields=[ ('contentitem_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='fluent_contents.ContentItem')), ('title', models.CharField(blank=True, max_length=63, null=True)), ('sub_title', models.CharField(blank=True, max_length=100, null=True)), ], options={ 'db_table': 'contentitem_cms_projectsmapcontent', 'verbose_name': 'Projects Map', }, bases=('fluent_contents.contentitem',), managers=[ ('objects', ContentItemManager()), ('base_objects', django.db.models.manager.Manager()), ], ), ]
class Migration(migrations.Migration): dependencies = [ ('fluent_contents', '0001_initial'), ('cms', '0009_merge_20161213_1047'), ] operations = [ migrations.CreateModel( name='SupportersContent', fields=[ ('contentitem_ptr', models.OneToOneField( auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='fluent_contents.ContentItem')), ('title', models.CharField(blank=True, max_length=63, null=True)), ('sub_title', models.CharField(blank=True, max_length=100, null=True)), ], options={ 'db_table': 'contentitem_cms_supporterscontent', 'verbose_name': 'Supporters', }, bases=('fluent_contents.contentitem', ), managers=[ ('objects', ContentItemManager()), ('base_objects', django.db.models.manager.Manager()), ], ), migrations.AlterField( model_name='shareresultscontent', name='share_text', field=models.CharField( default=b'', help_text= b'{amount}, {projects}, {tasks}, {hours}, {votes}, {people} will be replaced by live statistics', max_length=100), ), ]
class ContentItem( with_metaclass(ContentItemMetaClass, CachedModelMixin, PolymorphicModel)): """ A `ContentItem` represents a content part (also called pagelet in other systems) which is displayed in a :class:`Placeholder`. To use the `ContentItem`, derive it in your model class: .. code-block:: python class ExampleItem(ContentItem): # any custom fields here class Meta: verbose_name = "Example item" All standard Django model fields can be used in a `ContentItem`. Some things to note: * There are special fields for URL, WYSIWYG and file/image fields, which keep the admin styles consistent. These are the :class:`~fluent_contents.extensions.PluginFileField`, :class:`~fluent_contents.extensions.PluginHtmlField`, :class:`~fluent_contents.extensions.PluginImageField` and :class:`~fluent_contents.extensions.PluginUrlField` fields. See the :ref:`custom-model-fields` section for more details. * When adding a M2M field, make sure to override :attr:`copy_to_placeholder`, so the M2M data will be copied. When querying the objects through the ORM, the derived instances will be returned automatically. This happens because the `ContentItem` class is polymorphic: >>> from fluent_contents.models import ContentItem >>> ContentItem.objects.all() [<ArticleTextItem: Main article>, <RawHtmlItem: test>, <CodeItem: def foo(): print 1>, <AnnouncementBlockItem: Test>, <ArticleTextItem: Text in sidebar>] Note that the `django-polymorphic` application is written in such way, that this requires the least amount of queries necessary. When access to the polymorphic classes is not needed, call :func:`~polymorphic.query.PolymorphicQuerySet.non_polymorphic` on the `QuerySet` to prevent this behavior: >>> from fluent_contents.models import ContentItem >>> ContentItem.objects.all().non_polymorphic() [<ContentItem: Article text item#1 in 'Main content'>, <ContentItem: HTML code#5 in 'Main content'>, <ContentItem: Code snippet#6 in 'Main content'>, <ContentItem: Announcement block#7 in 'Main content'>, <ContentItem: Article text item#4 in 'Sidebar'>] Being polymorphic also means the base class provides some additional methods such as: * :func:`get_real_instance` * :func:`get_real_instance_class` Each `ContentItem` references both it's parent object (e.g. a page, or article), and the placeholder. While this is done mainly for internal reasons, it also provides an easy way to query all content items of a parent. The parent object is stored in a generic relation, so the `ContentItem` can be used with any custom object. By adding a :class:`~fluent_contents.models.ContentItemRelation` field to the parent model, the relation can be traversed backwards. Because the `ContentItem` references it's parent, and not the other way around, it will be cleaned up automatically by Django when the parent object is deleted. To use a `ContentItem` in the :class:`~fluent_contents.models.PlaceholderField`, register it via a plugin definition. see the :class:`~fluent_contents.extensions.ContentPlugin` class for details. The rendering of a `ContentItem` class happens in the associate :class:`~fluent_contents.extensions.ContentPlugin` class. To render content items outside the template code, use the :mod:`fluent_contents.rendering` module to render the items. """ objects = ContentItemManager() # Note the validation settings defined here are not reflected automatically # in the admin interface because it uses a custom ModelForm to handle these fields. # Track relation to parent # This makes it much easier to use it as inline. parent_type = models.ForeignKey(ContentType) parent_id = models.IntegerField( null=True ) # Need to allow Null, because Placeholder is created before parent is saved. parent = GenericForeignKey('parent_type', 'parent_id') language_code = models.CharField(max_length=15, db_index=True, editable=False, default='') # Deleting a placeholder should not remove the items, only makes them orphaned. # Also, when updating the page, the PlaceholderEditorInline first adds/deletes placeholders before the items are updated. placeholder = models.ForeignKey(Placeholder, related_name='contentitems', null=True, on_delete=models.SET_NULL) sort_order = models.IntegerField(default=1, db_index=True) @property def plugin(self): """ Access the parent plugin which renders this model. :rtype: :class:`~fluent_contents.extensions.ContentPlugin` """ from fluent_contents.extensions import plugin_pool if self.__class__ in (ContentItem, ): # Also allow a non_polymorphic() queryset to resolve the plugin. # Corresponding plugin_pool method is still private on purpose. # Not sure the utility method should be public, or how it should be named. return plugin_pool._get_plugin_by_content_type( self.polymorphic_ctype_id) else: return plugin_pool.get_plugin_by_model(self.__class__) def __str__(self): # Note this representation is optimized for the admin delete page. return u"'{type} {id:d}' in '{language} {placeholder}'".format( type=ContentType.objects.get_for_id( self.polymorphic_ctype_id).model_class()._meta.verbose_name, id=self.id or 0, language=get_language_title(self.language_code), placeholder=self.placeholder) class Meta: app_label = 'fluent_contents' # required for models subfolder ordering = ('placeholder', 'sort_order') verbose_name = _('Contentitem link') verbose_name_plural = _('Contentitem links') def get_absolute_url(self): """ Return the URL of the parent object, if it has one. This method mainly exists to refreshing cache mechanisms. """ # Allows quick debugging, and cache refreshes. parent = self.parent try: return parent.get_absolute_url() except AttributeError: return None def move_to_placeholder(self, placeholder, sort_order=None): """ .. versionadded: 1.0.2 Move this content item to a new placeholder. The object is saved afterwards. """ # Transfer parent self.placeholder = placeholder self.parent_type = placeholder.parent_type self.parent_id = placeholder.parent_id try: # Copy cache property set by GenericForeignKey (_meta.virtual_fields[0].cache_attr) setattr(self, '_parent_cache', placeholder._parent_cache) except AttributeError: pass if sort_order is not None: self.sort_order = sort_order self.save() move_to_placeholder.alters_data = True def copy_to_placeholder(self, placeholder, sort_order=None, in_place=False): """ .. versionadded: 1.0 Copy this content item to a new placeholder. Note: if you have M2M relations on the model, override this method to transfer those values. """ if in_place: copy = self else: copy = deepcopy(self) # Avoid changing 'self' # Reset Django cache copy.pk = None # reset contentitem_ptr_id copy.id = None # reset this base class. copy._state.adding = True copy.move_to_placeholder(placeholder, sort_order=sort_order) return copy copy_to_placeholder.alters_data = True def save(self, *args, **kwargs): # Fallback, make sure the object has a language. # As this costs a query per object, the admin formset already sets the language_code whenever it can. if not self.language_code: self.language_code = get_parent_language_code( self.parent ) or appsettings.FLUENT_CONTENTS_DEFAULT_LANGUAGE_CODE super(ContentItem, self).save(*args, **kwargs) save.alters_data = True def get_cache_keys(self): """ Get a list of all cache keys associated with this model. This queries the associated plugin for the cache keys it used to store the output at. """ if not self.placeholder_id: # TODO: prune old placeholder slot name? return [] # As plugins can change the output caching, # they should also return those keys where content is stored at. placeholder = self.placeholder keys = [ # Always make sure the base placeholder is cleared, # regardless whether get_output_cache_keys() is overwritten. get_placeholder_cache_key(placeholder, self.language_code), ] keys.extend(self.plugin.get_output_cache_keys( placeholder.slot, self)) # ensure list return type. return keys
class Migration(migrations.Migration): initial = True dependencies = [ ('fluent_contents', '0001_initial'), ('projects', '0015_auto_20161207_0900'), ('surveys', '0001_initial'), ] operations = [ migrations.CreateModel( name='ProjectImagesContent', fields=[ ('contentitem_ptr', models.OneToOneField( auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='fluent_contents.ContentItem')), ('title', models.CharField(blank=True, max_length=63, null=True)), ('sub_title', models.CharField(blank=True, max_length=100, null=True)), ('description', models.TextField(blank=True, null=True)), ('action_text', models.CharField(blank=True, default='Check out our projects', max_length=100, null=True)), ('action_link', models.CharField(blank=True, default=b'/projects', max_length=100, null=True)), ], options={ 'db_table': 'contentitem_cms_projectimagescontent', 'verbose_name': 'Project Images', }, bases=('fluent_contents.contentitem', ), managers=[ ('objects', ContentItemManager()), ('base_objects', django.db.models.manager.Manager()), ], ), migrations.CreateModel( name='Projects', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('projects', models.ManyToManyField(to='projects.Project')), ], ), migrations.CreateModel( name='ProjectsContent', fields=[ ('contentitem_ptr', models.OneToOneField( auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='fluent_contents.ContentItem')), ('title', models.CharField(blank=True, max_length=63, null=True)), ('sub_title', models.CharField(blank=True, max_length=100, null=True)), ('action', models.CharField(max_length=255)), ('action_text', models.CharField(max_length=255)), ('projects', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='cms.Projects')), ], options={ 'db_table': 'contentitem_cms_projectscontent', 'verbose_name': 'Projects', }, bases=('fluent_contents.contentitem', ), managers=[ ('objects', ContentItemManager()), ('base_objects', django.db.models.manager.Manager()), ], ), migrations.CreateModel( name='Quote', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=63)), ('quote', models.CharField(max_length=255)), ], ), migrations.CreateModel( name='Quotes', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ], ), migrations.CreateModel( name='QuotesContent', fields=[ ('contentitem_ptr', models.OneToOneField( auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='fluent_contents.ContentItem')), ('title', models.CharField(blank=True, max_length=63, null=True)), ('sub_title', models.CharField(blank=True, max_length=100, null=True)), ('quotes', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cms.Quotes')), ], options={ 'db_table': 'contentitem_cms_quotescontent', 'verbose_name': 'Quotes', }, bases=('fluent_contents.contentitem', ), managers=[ ('objects', ContentItemManager()), ('base_objects', django.db.models.manager.Manager()), ], ), migrations.CreateModel( name='ResultPage', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('title', models.CharField(max_length=200, verbose_name='Title')), ('slug', models.SlugField(max_length=200, verbose_name='Slug')), ('description', models.TextField(blank=True, null=True, verbose_name='Description')), ('start_date', models.DateField(blank=True, null=True)), ('end_date', models.DateField(blank=True, null=True)), ], ), migrations.CreateModel( name='Stat', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('type', models.CharField(choices=[ (b'manual', 'Manual input'), (b'people_involved', 'People involved'), (b'projects_realized', 'Projects realised'), (b'tasks_realized', 'Tasks realised'), (b'donated_total', 'Donated total'), (b'projects_online', 'Projects Online'), (b'votes_cast', 'Votes casts') ], max_length=40)), ('title', models.CharField(max_length=63)), ('value', models.CharField( blank=True, help_text= "Use this for 'manual' input or the override the calculated value.", max_length=63, null=True)), ], ), migrations.CreateModel( name='Stats', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ], ), migrations.CreateModel( name='StatsContent', fields=[ ('contentitem_ptr', models.OneToOneField( auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='fluent_contents.ContentItem')), ('title', models.CharField(blank=True, max_length=63, null=True)), ('sub_title', models.CharField(blank=True, max_length=100, null=True)), ('stats', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cms.Stats')), ], options={ 'db_table': 'contentitem_cms_statscontent', 'verbose_name': 'Platform Statistics', }, bases=('fluent_contents.contentitem', ), managers=[ ('objects', ContentItemManager()), ('base_objects', django.db.models.manager.Manager()), ], ), migrations.CreateModel( name='SurveyContent', fields=[ ('contentitem_ptr', models.OneToOneField( auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='fluent_contents.ContentItem')), ('title', models.CharField(blank=True, max_length=63, null=True)), ('sub_title', models.CharField(blank=True, max_length=100, null=True)), ('survey', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='surveys.Survey')), ], options={ 'db_table': 'contentitem_cms_surveycontent', 'verbose_name': 'Platform Results', }, bases=('fluent_contents.contentitem', ), managers=[ ('objects', ContentItemManager()), ('base_objects', django.db.models.manager.Manager()), ], ), migrations.AddField( model_name='stat', name='stats', field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to='cms.Stats'), ), migrations.AddField( model_name='quote', name='quotes', field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, to='cms.Quotes'), ), ]
class ContentItem(PolymorphicModel): """ A `ContentItem` represents a content part (also called pagelet in other systems) which is displayed in a :class:`Placeholder`. To use the `ContentItem`, derive it in your model class: .. code-block:: python class ExampleItem(ContentItem): # any custom fields here class Meta: verbose_name = "Example item" The `ContentItem` class is polymorphic; when querying the objects, the derived instances will be returned automatically: >>> from fluent_contents.models import ContentItem >>> ContentItem.objects.all() [<ArticleTextItem: Main article>, <RawHtmlItem: test>, <CodeItem: def foo(): print 1>, <AnnouncementBlockItem: Test>, <ArticleTextItem: Text in sidebar>] Note that the `django-polymorphic` application is written in such way, that this requires the least amount of queries necessary. When access to the polymorphic classes is not needed, call :func:`~polymorphic.query.PolymorphicQuerySet.non_polymorphic` on the `QuerySet` to prevent this behavior: >>> from fluent_contents.models import ContentItem >>> ContentItem.objects.all().non_polymorphic() [<ContentItem: Article text item#1 in 'Main content'>, <ContentItem: HTML code#5 in 'Main content'>, <ContentItem: Code snippet#6 in 'Main content'>, <ContentItem: Announcement block#7 in 'Main content'>, <ContentItem: Article text item#4 in 'Sidebar'>] Being polymorphic also means the base class provides some additional methods such as: * :func:`get_real_instance` * :func:`get_real_instance_class` Each `ContentItem` references both it's parent object (e.g. a page, or article), and the placeholder. While this is done mainly for internal reasons, it also provides an easy way to query all content items of a parent. The parent object is stored in a generic relation, so the `ContentItem` can be used with any custom object. By adding a :class:`~fluent_contents.models.ContentItemRelation` field to the parent model, the relation can be traversed backwards. Because the `ContentItem` references it's parent, and not the other way around, it will be cleaned up automatically by Django when the parent object is deleted. To use a `ContentItem` in the :class:`~fluent_contents.models.PlaceholderField`, register it via a plugin definition. see the :class:`~fluent_contents.extensions.ContentPlugin` class for details. The rendering of a `ContentItem` class happens in the associate :class:`~fluent_contents.extensions.ContentPlugin` class. To render content items outside the template code, use the :mod:`fluent_contents.rendering` module to render the items. """ __metaclass__ = ContentItemMetaClass objects = ContentItemManager() # Note the validation settings defined here are not reflected automatically # in the admin interface because it uses a custom ModelForm to handle these fields. # Track relation to parent # This makes it much easier to use it as inline. parent_type = models.ForeignKey(ContentType) parent_id = models.IntegerField( null=True ) # Need to allow Null, because Placeholder is created before parent is saved. parent = GenericForeignKey('parent_type', 'parent_id') # Deleting a placeholder should not remove the items, only makes them orphaned. # Also, when updating the page, the PlaceholderEditorInline first adds/deletes placeholders before the items are updated. placeholder = models.ForeignKey(Placeholder, related_name='contentitems', null=True, on_delete=models.SET_NULL) sort_order = models.IntegerField(default=1, db_index=True) @property def plugin(self): """ Access the parent plugin which renders this model. :rtype: :class:`~fluent_contents.extensions.ContentPlugin` """ from fluent_contents.extensions import plugin_pool if self.__class__ in (ContentItem, ): # Also allow a non_polymorphic() queryset to resolve the plugin. # Corresponding plugin_pool method is still private on purpose. # Not sure the utility method should be public, or how it should be named. return plugin_pool._get_plugin_by_content_type( self.polymorphic_ctype_id) else: return plugin_pool.get_plugin_by_model(self.__class__) def __unicode__(self): return u"{type} {id:d} in '{placeholder}'".format( type=self.polymorphic_ctype or self._meta.verbose_name, id=self.id or 0, placeholder=self.placeholder) class Meta: app_label = 'fluent_contents' # required for models subfolder ordering = ('placeholder', 'sort_order') verbose_name = _('Contentitem link') verbose_name_plural = _('Contentitem links') def get_absolute_url(self): """ Return the URL of the parent object, if it has one. This method mainly exists to refreshing cache mechanisms. """ # Allows quick debugging, and cache refreshes. parent = self.parent try: return self.parent.get_absolute_url() except AttributeError: return None def save(self, *args, **kwargs): super(ContentItem, self).save(*args, **kwargs) self.clear_cache() def delete(self, *args, **kwargs): super(ContentItem, self).delete(*args, **kwargs) self.clear_cache() def clear_cache(self): """ Delete the cache keys associated with this model. """ for cache_key in self.get_cache_keys(): cache.delete(cache_key) def get_cache_keys(self): """ Get a list of all cache keys associated with this model. """ if not self.placeholder_id: # TODO: prune old placeholder slot name? return [] placeholder_name = self.placeholder.slot return [get_rendering_cache_key(placeholder_name, self)]
class Migration(migrations.Migration): dependencies = [ ('fluent_contents', '0001_initial'), ('cms', '0039_auto_20171017_1708'), ] operations = [ migrations.CreateModel( name='Logo', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('image', bluebottle.utils.fields.ImageField(blank=True, max_length=255, null=True, upload_to=b'logo_images/', verbose_name='Image')), ], options={ 'abstract': False, }, bases=(models.Model, ), ), migrations.CreateModel( name='LogosContent', fields=[ ('contentitem_ptr', models.OneToOneField( auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='fluent_contents.ContentItem')), ('title', models.CharField(blank=True, max_length=40, null=True)), ('sub_title', models.CharField(blank=True, max_length=70, null=True)), ('action_text', models.CharField(max_length=40)), ], options={ 'db_table': 'contentitem_cms_logoscontent', 'verbose_name': 'Logos', }, bases=('fluent_contents.contentitem', ), managers=[ ('objects', ContentItemManager()), ('base_objects', django.db.models.manager.Manager()), ], ), migrations.AddField( model_name='logo', name='block', field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name='logos', to='cms.LogosContent'), ), ]
class Migration(migrations.Migration): dependencies = [ ('fluent_contents', '0001_initial'), ('geo', '0004_auto_20160929_0817'), ('cms', '0028_merge_20171006_1622'), ] operations = [ migrations.CreateModel( name='CategoriesContent', fields=[ ('contentitem_ptr', models.OneToOneField( auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='fluent_contents.ContentItem')), ('title', models.CharField(blank=True, max_length=40, null=True)), ('sub_title', models.CharField(blank=True, max_length=70, null=True)), ('categories', models.ManyToManyField( db_table=b'cms_categoriescontent_categories', to='categories.Category')), ], options={ 'db_table': 'contentitem_cms_categoriescontent', 'verbose_name': 'Categories', }, bases=('fluent_contents.contentitem', ), managers=[ ('objects', ContentItemManager()), ('base_objects', django.db.models.manager.Manager()), ], ), migrations.CreateModel( name='LocationsContent', fields=[ ('contentitem_ptr', models.OneToOneField( auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='fluent_contents.ContentItem')), ('title', models.CharField(blank=True, max_length=40, null=True)), ('sub_title', models.CharField(blank=True, max_length=70, null=True)), ('locations', models.ManyToManyField( db_table=b'cms_locationscontent_locations', to='geo.Location')), ], options={ 'db_table': 'contentitem_cms_locationscontent', 'verbose_name': 'Locations', }, bases=('fluent_contents.contentitem', ), managers=[ ('objects', ContentItemManager()), ('base_objects', django.db.models.manager.Manager()), ], ), migrations.CreateModel( name='Slide', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ], options={ 'abstract': False, }, bases=(models.Model, ), managers=[ ('objects', TranslatableManager()), ('base_objects', django.db.models.manager.Manager()), ], ), migrations.CreateModel( name='SlidesContent', fields=[ ('contentitem_ptr', models.OneToOneField( auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='fluent_contents.ContentItem')), ], options={ 'db_table': 'contentitem_cms_slidescontent', 'verbose_name': 'Slides', }, bases=('fluent_contents.contentitem', ), managers=[ ('objects', ContentItemManager()), ('base_objects', django.db.models.manager.Manager()), ], ), migrations.CreateModel( name='SlideTranslation', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('language_code', models.CharField(db_index=True, max_length=15, verbose_name='Language')), ('tab_text', models.CharField( help_text='This is shown on tabs beneath the banner.', max_length=100, verbose_name='Tab text')), ('title', models.CharField(blank=True, max_length=100, verbose_name='Title')), ('body', models.TextField(blank=True, verbose_name='Body text')), ('image', bluebottle.utils.fields.ImageField( blank=True, max_length=255, null=True, upload_to=b'banner_slides/', verbose_name='Image')), ('background_image', bluebottle.utils.fields.ImageField( blank=True, max_length=255, null=True, upload_to=b'banner_slides/', verbose_name='Background image')), ('video_url', models.URLField(blank=True, default=b'', max_length=100, verbose_name='Video url')), ('link_text', models.CharField( blank=True, help_text= 'This is the text on the button inside the banner.', max_length=400, verbose_name='Link text')), ('link_url', models.CharField( blank=True, help_text= 'This is the link for the button inside the banner.', max_length=400, verbose_name='Link url')), ('master', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='translations', to='cms.Slide')), ], options={ 'managed': True, 'db_table': 'cms_slide_translation', 'db_tablespace': '', 'default_permissions': (), 'verbose_name': 'slide Translation', }, ), migrations.CreateModel( name='Step', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('image', bluebottle.utils.fields.ImageField(blank=True, max_length=255, null=True, upload_to=b'step_images/', verbose_name='Image')), ], options={ 'abstract': False, }, bases=(models.Model, ), ), migrations.CreateModel( name='StepsContent', fields=[ ('contentitem_ptr', models.OneToOneField( auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='fluent_contents.ContentItem')), ('title', models.CharField(blank=True, max_length=40, null=True)), ('sub_title', models.CharField(blank=True, max_length=70, null=True)), ('action_text', models.CharField(blank=True, default='Start your own project', max_length=40, null=True)), ('action_link', models.CharField(blank=True, default=b'/start-project', max_length=100, null=True)), ], options={ 'db_table': 'contentitem_cms_stepscontent', 'verbose_name': 'Steps', }, bases=('fluent_contents.contentitem', ), managers=[ ('objects', ContentItemManager()), ('base_objects', django.db.models.manager.Manager()), ], ), migrations.CreateModel( name='StepTranslation', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('language_code', models.CharField(db_index=True, max_length=15, verbose_name='Language')), ('header', models.CharField(max_length=100, verbose_name='Header')), ('text', models.CharField(max_length=400, verbose_name='Text')), ('master', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='translations', to='cms.Step')), ], options={ 'managed': True, 'db_table': 'cms_step_translation', 'db_tablespace': '', 'default_permissions': (), 'verbose_name': 'step Translation', }, ), migrations.RemoveField( model_name='metric', name='block', ), migrations.RemoveField( model_name='metricscontent', name='contentitem_ptr', ), migrations.AlterUniqueTogether( name='metrictranslation', unique_together=set([]), ), migrations.RemoveField( model_name='metrictranslation', name='master', ), migrations.DeleteModel(name='Metric', ), migrations.DeleteModel(name='MetricsContent', ), migrations.DeleteModel(name='MetricTranslation', ), migrations.AddField( model_name='step', name='block', field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name='steps', to='cms.StepsContent'), ), migrations.AddField( model_name='slide', name='block', field=models.ForeignKey( on_delete=django.db.models.deletion.CASCADE, related_name='slides', to='cms.SlidesContent'), ), migrations.AlterUniqueTogether( name='steptranslation', unique_together=set([('language_code', 'master')]), ), migrations.AlterUniqueTogether( name='slidetranslation', unique_together=set([('language_code', 'master')]), ) ]