The app I am creating has many static pages, just like the pages of a website which do not change for some time. Im my model I will have a title field and a text field. I am looking go a way to avoid multiple views and multiple urls for each page. I tried using flatpages, but I was not able to get to work the context processors. For example, if a certain page has many grids. So how to write a single view and a url which will deliver all the pages, along with the context processors.
If you are having problems with flatpages, it's not hard to write your own version!
models.py
from markdown import markdown
class CustomFlatPage(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
slug = models.SlugField(unique=True)
urls.py
url(r'^(?P<slug>[-\w]+)/$','myapp.views.customflatpage', name='customflatpage'),
views.py
from django.views.generic.simple import direct_to_template
def customflatpage(request,slug):
page = get_object_or_404(CustomFlatPage, slug=slug)
return direct_to_template('path/flatpage_template.html',
extra_context={
"page":page,
})
template (has access to request context etc.)
{{ page.title}}
{{ load markup }}
{{ page.body|markdown }}
Use TinyMCE on the body field in django-admin (if you are using it) or your own form if you want rich text.
Related
So I'm currently learning to use Django, and I'm wondering how to correctly split up parts of the functionality while still displaying it on the main page.
For example, I want the header + navigation, a calendar and recent blog articles on the main index page.
On the view article page I'd for example have the header + nav, the calendar and a single article with a comment section.
Now reading the tutorials, if I understand them correctly, I'd split the functionality in a header app, a calendar app and the blog app itself while glueing it together with a core app.
But what I don't understand is how to render apps/other views in the main app. All the ways I found only specify templates itself or look very hacky, so apparently that doesn't seem to be the common way to go.
So there are multiple views are work here:
1.The views that you want to show
2.The view that will render the page, displaying all of the views (lets call this the 'main view'.
The first step is to import all of the other views / models into the views.py file that the main view resides in.
from blog.models import Post
from calendar.models import Calendar
Now you can edit your mainview to acces this data. For example:
class Mainview(TemplateView):
template_name = 'app/homepage.html'
def get_context_data(self, **kwargs):
#This will only show the latest post
data['posts'] = Post.objects.all().order_by('-id')[:1]
data['calendar'] = Calendar.objects.all()
return data
Now you can acces the data from the other apps in your template using the {{ }} tags, for example - you could do something like this:
{% for post object in post %}
{{ post.title }}
{{ post.content}}
{% endfor %}
I've made an extra image field as shown by #Timmy O'Mahony on
How to add some extra fields to the page in django-cms? (in django admin panel)
I'd like to call this image field from another page using its reverse_id, much like
{% page_attribute "extended_page_options.image" "my_page_reverse_id" %}
Do I need a custom template tag? How can I do it?
I am using django-cms 2.4.3 and django 1.5.5
EDIT:
models.py
from django.db import models
from django.utils.translation import ugettext_lazy as _
from cms.models.pagemodel import Page
from filer.fields.image import FilerImageField
class ExtendedPage(models.Model):
page = models.ForeignKey(Page, unique=True, verbose_name=_("Page"), editable=False, related_name='extended_fields')
image = FilerImageField(blank=True, null=True)
In a recent project, I think I solved this with a context_processor as follows:
from django.conf import settings
def page_extension(request):
"""Puts settings.DEBUG and the page_extension, if present and puts it into
the context"""
context = {'debug': settings.DEBUG}
if request.current_page:
page = request.current_page
try:
context.update({'page_extension': page.page_extension})
except:
try:
context.update({'page_extension': page.publisher_public.page_extension})
except:
pass
return context
In this case, I've also used the opportunity to also add the value of settings.DEBUG, this is optional of course.
Then, just add this to your settings file as:
TEMPLATE_CONTEXT_PROCESSORS = (
...
'path.to.above.code.page_extension',
)
Then, next step, is just access the value in your templates:
{% if page_extension and page_extension.my_page_property %}{{ page_extension.my_page_property }}{% endif %}
First thing, if you are starting out the new project, go for django cms 3.0, it has lots of new and exciting features than the previous release.
Back to your question, go to the advanced settings of the page which contains the actual image field and add the id. Then on other page do like this:
{% page_attribute "field_name" "my_page_reverse_id" %}
Short:
I'd like to create an app which provides a well formatted form that can be imported into other apps. Doing this using nothing but ModelForm results in partial success as it renders only the form fields without any of the additionally required elements like buttons. This however should also be encapsulated in the app.
Long:
For a better understanding lets assume we have an app called blog and one called comments. They've been separated since comments may also be used in other places and apps. comments should provide a form which is then added to the view or the template of blog
So here's some pseudo code for better a understanding.
comments/models.py:
class Comment(models.Model):
comment = models.TextField()
author = models.CharField(max_length=64)
comments/forms.py:
class CommentForm(forms.ModelForm)
class Meta:
model = Comment
comments/templates/comments/comment_form.html:
<form method="post" action="#">
{{ formfields }}
<button type="submit">Submit</button>
</form>
Clearly there's a step missing since the ModelForm and the template are not brought together. My goal now is to import exacly such a marriage to blog
blog/views.py
def render_article(request):
context = {
...
comment_form: <SOMETHING THAT CREATES A NICE TEMPLATE BASED HTML FORM>
}
return render(request, 'blog/article.html', context)
In essence I'm looking for a single object of function that I can use in any kind of app to provide a complete form. That way it always looks the same in all apps.
How to do this?
You could override django.forms.Form.__unicode__ in your form:
from django.utils.safestring import mark_safe
class MyForm(forms.Form):
...
def __unicode__(self):
html = super(MyForm, self).__unicode__
html = html + '<button type="submit">Submit</button>'
// or whatever — render a wrapper template, anything
return mark_safe(html)
I am an absolute beginner in django-cms, just acquired some pieces of knowledge to create templates. Just wondering, how to create a portal page that has a few acticles in each different categories?
Please simply point out a practical way to do, no real code is needed.
Thank you.
As others have pointed out, the way to do this is by hooking your CMS page to another set of views. Django-CMS provides application hooks:
#cms_app.py
from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
class YourModuleApp(CMSApp):
name = 'My App MOdule'
urls = ['my_app.urls']
apphook_pool.register(YourModuleApp)
So, if you had a module called "my_app" with a urls.py in it, Django-CMS will add those patterns to the page. Look in the "Advanced Settings" section of the page in admin for the application drop-down menu.
Once the app is hooked to the page, Django-CMS will pull any content and the layout template from the information it holds, then hand off processing to the additional URL patterns that are hooked to it. That's how you can pull in another model, add a form, handle a POST, etc.
You could just do it the normal Django way. Create a normal Django app, with a URL pointing to a view that renders a template. The view could look like this:
from django.shortcuts import render
from cms.models import Page
def articles(request):
pages = Page.objects.public()
render(request, 'example.html', {'pages': pages})
And the template could look like this:
{% load cms_tags %}
{% for page in pages %}
<p>{% page_attribute "page_title" page %}</p>
{% endfor %}
You could stop here. Or you could have...
Additional Django CMS integration with AppHooks
Do you want your non-developer content managers to be able to put a list of articles wherever they want? This is where AppHooks come in.
Create a CMSApp class in the file appname/cms_app.py like this:
from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
from django.utils.translation import ugettext_lazy as _
class ArticleListApp(CMSApp):
app_name = 'articlelist'
name = _('Article List')
def get_urls(self, page=None, language=None, **kwargs):
return ['articlelist.urls']
apphook_pool.register(YourModuleApp)
Delete the URL entry in your project-wide urls.py as you no longer need it. Your app's urls.py needs to include a view for the regex ^$.
Now you or any content manager user with necessary permissions can create a page in the admin interface, and modify the advanced settings to select the "Article List" application:
One gotcha is that this will have no effect until the page is published (as well as all of its ancestor pages).
I have a project which has just assimilated several apps from other projects of mine to one main project. The structure is one main app that lies at the root url and other apps with specific urls. I have set up my urls.py:
url(r'^$', include('main_app.urls')),
url(r'^app1/', include('app1.urls')),
url(r'^app2/', include('app2.urls')),
url(r'^app3/', include('app3.urls')),
I have a model in my main_app models.py which describes my other apps along the lines of:
class App(models.Model):
title = models.CharField()
image = models.ImageField("App Image", upload_to="images/apps/", blank=True, null=True)
description = models.TextField()
And in my main_app views:
def index(request):
app_list = App.objects.all()
return render_to_response('index.html',
locals(), context_instance=RequestContext(request))
So, in my root index template (main_app) I want to cycle through all apps and print a link:
{% for app in app_list %}
{{ some_app_variables }}
Link to app
{% endfor %}
My question is how should I define this link. Should I have a get_absolute_url for the app model?
Any help much appreciated.
An app doesn't inherently have some URL associated with it. URLs are tied to views, and those views could reference any model from any app or no models or apps at all for that matter. What's you're doing doesn't make sense.
UPDATE: I'm still unsure about what you're linking to. An "app" is an abstract concept. I understand having a list of "Apps", but what kind of view would you get for an individual app? Still, yes, you should have a get_absolute_url method on your Apps model. Then, your best bet would be to name whatever view in each app is going to be the "index" view something along the lines of "app_(title)". Then you can construct the right reverse with something along the lines of:
#models.permalink
def get_absolute_url(self):
return ('app_%s' % self.title, (), {})
Of course, you should probably modify that with something akin to a slug to accommodate titles that might have multiple words, e.g. "Cool App" would need to be replaced with something like "cool_app".
Like I said, though, what you're trying to accomplish still doesn't make much sense from where I'm sitting.