I'm building a small site framework for a set of sites that are likely to have quite a few unstructured pages - meaning they have:
Slightly different layouts per page
Lots of one-off text
None/very little generated content from models
I would like to allow clients to edit the content of these pages through my admin UI (I'm using Django for this project), but with the requirement that they are not exposed to the page HTML and are only able to edit parts of the page that I've specified as fields; for example:
Titles
A few blocks of text content
Perhaps some blocks of predefined image locations
PDF files that need embedding
Where these fields vary significantly between pages.
The layout, and what fields these pages require would be specified by the developer, so there's no need to dynamically generate much for this.
The 'best' idea I've had so far is to serialise these blocks of content once they've been edited by the user and store them in a 'Pages' table/model in my relational database, or just throw MongoDB or similar at it.
Conceptually, how would you implement such pages? As mentioned, I'm using Django so any implementation suggestions specific to Django are welcome, but general high-level ideas would be great too.
I would implement a ContentBlock model, which has .kind (header, text, image, pdf) and a .data, which would house the content (if text) or path to an uploaded pdf/image/etc. Presumably then you'd hardcode the pages with the appropriate blocks defined - I'd just use hardcoded slugs, eg, 'home-title', 'home-intro', 'about-title', 'about-text', 'about-right-photo', etc.
I would suggest not using Django's admin interface. It's much more suited to editing homogenous, non-business-logic models. I'd just add an edit view that renders the appropriate form fields for the blocks instead - html editor, file upload, etc. It's possible to do that in the django admin, but in my experience it's not worth the trouble - plus, if you do your own edit view, you can have it use the same base templates as the rest of the site, which IMO is a better user experience.
Here are a couple of apps which do that for you:
django-generic-flatblocks
django-boxes
Along with django-frontendadmin, it's super cool.
Related
I'm trying to understand the best approach to create article items in my sitecore 7.2 project.
Basically I'm considering 2 options:
1 - Create an article as a page;
2 - Create an article as a Site Data Item.
1 - Create article pages under a given page (i.e. My Articles). This way each article would have a specific URL out of the box, easier to understand in Content Authors' point of view;
2 - Have a specific folder (i.e. Article Folder) under Site Data. This way we don't need to have a page for each article - I was thinking to have a single Article page that would render the article fields. However this would require more work in terms of URLs, navigation, etc.
Is there any other ideas? Am I missing something? I was also having a look at Buckets...
Thank you
I'm going to disagree with Marek and recommend you opt for option 2.
Storing your articles in folder under a Data node allows those items to be datasourced. This is the principle Sitecore was built on. You can then surface those articles in a number of interesting ways via Widgets such as Promo Panels, prompting the user to click through to read about the article without duplicating its data and requiring Content Editors to manage data multiple times.
It even supports multiple sites, so the Articles can be used in other sites you may add to your Sitecore instance in the future.
As you state it will require extra work in terms of Urls and Navigation but it can be achieved via Sitecore's Wild Card Item and you an even use a great open sourced Module from Sitecore's Marketplace to complete 90% of the work for you. See links below for more information.
You can still implement Marek's point of applying Presentation Details once on the Standard Values of the Wild Cart Item you create. If you are using Sitecore 7 and above you can store all your articles in a Bucket so if you have lots of articles they are stored and searchable in a meaningful way.
http://www.sitecore.net/learn/blogs/technical-blogs/getting-to-know-sitecore/posts/2011/09/wildcards-and-data-driven-urls.aspx
https://marketplace.sitecore.net/en/Modules/Wildcard_module.aspx
In a standard one instance setup the easiest implementation is to create articles as pages.
In Sitecore you want to limit the items in a folder to 100 or less which is best practice to keep the content editors experience optimal.
This then leads you needing a folder structure and a couple options:
Manually maintain a folder structure for your articles. For example articles/year/month/day. This gives your editors the most control over the folder structure and allow them to navigate the articles in a more traditional way via a visible folder structure.
Use a bucket which automatically generates the folder structure and hides this complexity from the content editor. This takes the manual folder creation and maintenance away from the content editor and are automatically generated based on the configuration you set out for your bucket. The folders wont be visible to the content editor so they will be forced to search in the bucket for any articles rather then navigate the folders.
Use the shared source News mover module (https://marketplace.sitecore.net/en/Modules/News_mover.aspx). This takes a different approach to the above. It works via a traditional folder structure however it generates folders and moves the item on save based on the date field in the article. So the news mover handles the generation of folders however you will still need to check your not exceeding 100 items per folder again for performance when opening folders with large amounts of items.
With all solutions you must still consider the URLs for your articles as they will include the folder structure by default. This is not always acceptable. I prefer to remove the folder structure from the URL. For this you need to create a custom linkProvider and a custom HttpRequestProcessor. Firstly the linkprovider allows you to ensure the new URL is always created and displayed in your site as you want. Next the HttpRequestProcessor ensures that when navigating to the shortened URL Sitecore recognises it as a valid URL and presents the correct page.
By excluding the folder structure from the URL it also adds the additional benefit that the URL is not dependent on the structure. This means editors can change that folder structure and not need to create redirect items to ensure SEO rankings or users bookmarks are not lost.
The cleaner data model is to use the wildcard approach for the URLs and centralize the storage of articles data in a bucket of datasources. This will give you optimum performance and reuse of the data.
However, this isn't how an author thinks about their website. When they use the system, they tend to navigate to the area where they would view articles and try to create a new one there. Authors tend to think in 'pages', so try to hide whatever data model you are using from them and give them the ability to edit the page with Experience Editor.
Some developers try to optimize too far and forget that the authoring experience is likely the most important piece of the delivered solution. The author doesn't care how efficiently you stored the data, only that they can edit it easily and publish efficiently. Whatever model supports that for your author base is how you should implement it.
My recommendation is a page-based approach where the author creates the URL structure with folders and items, something they understand. Then, if you really need to, you can have the primary article data be a datasource-driven component on the page. The user gets to use all the tools they are familiar with (Experience Editor,preview navigation) but you can still store the raw data in a centralized folder. You could then theoretically swap out the article data using DMS rules, or hide information based on authentication or membership status.
Go with approach 1: article is a page.
Define all your presentation details on Article Page template __Standard Values. All new articles will get them. And you can change some of the presentation details for your chosen articles if you want.
If you know that you'll have lot of articles, think about year/month/day folder structure, e.g. articles/2015/06/12.
Approach 2 doesn't give you anything - you still need to have an item for every article. And as you wrote, it would require additional coding which is not required.
I am a bit confused on the best way to handle this problem:
My web site needs read-only static web pages (typically the About part of a web site) with 2 simple constraints:
they need to be translated
they need to have flexible layout: to incorporate base headers/footers, floating images and/or tables, and non-interactive elements (like a bootstrap carousel).
Several solutions that I have thought about:
I can of course directly write HTML files but the translation part will be awkward (a lot of <h1>, <ul>, <li> and <p> which are of no interest to the translator).
I can use Django flatpages with some markup languages but I lose a lot of flexibility (for instance template tags are not recognized)
Use generators like Hyde, but it seems quite overkill for my needs and internationalization seems a bit difficult
Does someone have other propositions that I can look into ?
Thanks !
Use django-cms, it has a Page model that can be translated and has a very smart plugin system to add many content-types into every page.
I use it a lot and it's very easy and yet powerful
For completeness and fairness, here's a full list of available CMS packages for Django.
for a much simpler solution, I would create a model called "Page" with lets say title and text fields.
The title and the text fields I would register to django-modeltranslation which will handle the translation issue.
For the text field i would use TinyMCE which let you insert basically any HTML you want so you can do whatever you need.
In Drupal you could choose in which "region" of your site you want your block displayed. You did not have to modify any php/html code in order to achieve this.
Can such a thing be achieved with Django, and if yes, how?
By block I understand a piece of html output that doesn't have it's own URL and gets displayed along side the main data. (for example a search box or a poll)
Hm you probably want to create context processor and just output from it where you want it in template?
If you want reordering of content blocks in html output inside admin then you need something to generate that output like cms. You could try something like django-fluent-contents for this without requiring big cms.
Django and Drupal shouldn't be compared like this: Drupal is a CMS, Django is a web framework.
If you want to get a somewhat similar experience, I would look at using django-cms. With this, you can create numerous templates and set placeholders within these templates (these are regions of the page like 'sidebar', 'footer', 'content area' etc.). When you go to create a new page in django-cms, you select which template you want to use (maybe a two column layout or a three column layout with a header - depending on what you have created) and then you choose what content (or plugins) you want to place within the placeholders you have created in the template. So this is a somewhat similar experience to Drupal's regions.
I'm working on a Django site with a basic three column design. Left column navigation, center column content and right column URL specific content blocks.
My question is about the best method of controlling the URL specific content blocks in the right column.
I am thinking of something along the lines of the Flatpages app that will make the content available to the template context if the URL matches a pre-determined pattern (perhaps regex?).
Does anyone know if such an app already exists?
If not, I am looking for some advice about the best way to implement it. Particularly in relation to the matching of patterns to the current URL. Is there any good way to re-use parts of the Django URL dispatcher for this use?
Django CMS is a good suggestion, it depends on how deep you want to go. If this is just the beginning of different sorts of dynamic content you want then you should go that way for sure.
A simple one-off solution would be something like this:
You would just need to write a view and add some variables on the end of the URL that would define what showed up there. Depending on how fancy you need to get, you could just create a simple models, and just map the view to the model key
www.example.com/content/sidecontent/jokes/
so if "jokes" was your block of variable sidecontent (one of many in your sides model instances) the urls.py entry for that would be
(r'^content/sidecontent/(?P<side>)/$,sides.views.showsides),
and then in your sides app you have a view with a
def showsides(request, side):
Sides.objects.get(pk=side)
etc...
For something like this I personally would use Django CMS. It's like flatpages on steroids.
Django CMS has a concept of Pages, Templates, and Plugins. Each page has an associated template. Templates have placeholders where you can insert different plugins. Plugins are like mini-applications that can have dynamic model-based content.
Although Django-CMS is an interesting suggestion, there are quite a few projects that do specifically what you've requested - render blocks of content based on a URL. The main one that I know about is django-flatblocks.
I'm going to be honest: this is a question I asked on the Django-Users mailinglist last week. Since I didn't get any replies there yet, I'm reposting it on Stack Overflow in the hope that it gets more attention here.
I want to create an app that makes it easy to do user friendly,
multiple / mass file upload in your own apps. With user friendly I
mean upload like Gmail, Flickr, ... where the user can select multiple
files at once in the browse file dialog. The files are then uploaded
sequentially or in parallel and a nice overview of the selected files
is shown on the page with a progress bar next to them. A 'Cancel'
upload button is also a possible option.
All that niceness is usually solved by using a Flash object. Complete
solutions are out there for the client side, like: SWFUpload
http://swfupload.org/ , FancyUpload http://digitarald.de/project/fancyupload/
, YUI 2 Uploader http://developer.yahoo.com/yui/uploader/ and probably
many more.
Ofcourse the trick is getting those solutions integrated in your
project. Especially in a framework like Django, double so if you want
it to be reusable.
So, I have a few ideas, but I'm neither an expert on Django nor on
Flash based upload solutions. I'll share my ideas here in the hope of
getting some feedback from more knowledgeable and experienced people.
(Or even just some 'I want this too!' replies :) )
You will notice that I make a few assumptions: this is to keep the
(initial) scope of the application under control. These assumptions
are of course debatable:
All right, my idea's so far:
If you want to mass upload multiple files, you are going to have a
model to contain each file in. I.e. the model will contain one
FileField or one ImageField.
Models with multiple (but ofcourse finite) amount of FileFields/
ImageFields are not in need of easy mass uploading imho: if you have a
model with 100 FileFields you are doing something wrong :)
Examples where you would want my envisioned kind of mass upload:
An app that has just one model 'Brochure' with a file field, a
title field (dynamically created from the filename) and a date_added
field.
A photo gallery app with models 'Gallery' and 'Photo'. You pick a
Gallery to add pictures to, upload the pictures and new Photo objects
are created and foreign keys set to the chosen Gallery.
It would be nice to be able to configure or extend the app for your
favorite Flash upload solution. We can pick one of the three above as
a default, but implement the app so that people can easily add
additional implementations (kinda like Django can use multiple
databases). Let it be agnostic to any particular client side solution.
If we need to pick one to start with, maybe pick the one with the
smallest footprint? (smallest download of client side stuff)
The Flash based solutions asynchronously (and either sequentially or
in parallel) POST the files to a url. I suggest that url to be local
to our generic app (so it's the same for every app where you use our
app in). That url will go to a view provided by our generic app.
The view will do the following: create a new model instance, add the
file, OPTIONALLY DO EXTRA STUFF and save the instance.
DO EXTRA STUFF is code that the app that uses our app wants to run.
It doesn't have to provide any extra code, if the model has just a
FileField/ImageField the standard view code will do the job.
But most app will want to do extra stuff I think, like filling in
the other fields: title, date_added, foreignkeys, manytomany, ...
I have not yet thought about a mechanism for DO EXTRA STUFF. Just
wrapping the generic app view came to mind, but that is not developer
friendly, since you would have to write your own url pattern and your
own view. Then you have to tell the Flash solutions to use a new url
etc...
I think something like signals could be used here?
Forms/Admin: I'm still very sketchy on how all this could best be
integrated in the Admin or generic Django forms/widgets/...
(and this is were my lack of Django experience shows):
In the case of the Gallery/Photo app:
You could provide a mass Photo upload widget on the Gallery detail
form. But what if the Gallery instance is not saved yet? The file
upload view won't be able to set the foreignkeys on the Photo
instances. I see that the auth app, when you create a user, first asks
for username and password and only then provides you with a bigger
form to fill in emailadres, pick roles etc. We could do something like
that.
In the case of an app with just one model:
How do you provide a form in the Django admin to do your mass
upload? You can't do it with the detail form of your model, that's
just for one model instance.
There's probably dozens more questions that need to be answered before
I can even start on this app. So please tell me what you think! Give
me input! What do you like? What not? What would you do different? Is
this idea solid? Where is it not?
Thank you!
I just released a simple app for this about a month ago: django-uploadify.
It's basically a Django template tag that acts as a wrapper for the very nifty Uploadify (requires jQuery). Using it is as simple as adding this to your template...
{% load uploadify_tags }{% multi_file_upload ‘/upload/complete/url/’ %}
The tag will fire events (1 per file) on both the client-side and server-side (Django signal) to indicate when an incoming file has been received.
For example, assuming you have a model 'Media' that handles all user-uploaded files...
def upload_received_handler(sender, data, **kwargs):
if file:
new_media = Media.objects.create(
file = data,
new_upload = True,
)
new_media.save()
upload_recieved.connect(upload_received_handler, dispatch_uid=‘whatever.upload_received’)
Check out the wiki for info on how to set it up and create the signal handlers (client/server).
About your conceptual implementation from above, here's a few points of consideration:
Having the app automatically create the "File Model" instance probably isn't as robust as people may already have their own models they're working with
If you want to implement any type of security or authentication, you need an open system and less of an 'auto-create' type
I really think signals/events are the way to handle this, and also handle the 'DO OTHER STUFF' part of what you mentioned.
My conclusion was that multi-upload can never really be a form widget in the sense that Django implements form widgets. 1 file will most likely be represented by 1 model instance (with some exceptions), which means that we end up with a situation where 1 widget can represent N model instances. However Django is setup so that a widget represents 1 value for 1 field in 1 instance. It just doesn't fit for the majority of use-cases to have it as a widget (hence why I went the template tag route).