Hello, today I would like to tell you about how to make a model that stores the usual pages, and not individual records in the database (for ListView, TemplateView, etc.). It will talk about how to expand and complement the existing in Django flatpages. But I would like to talk about the problem that I faced and why I decided to share this functionality. Often there is a situation when the admin for the site administrator needs to implement the functionality of the most ordinary page (one entry in the database is one page where the url, content and additional info for a specific page are written). Thus, you can create new pages directly from the admin page with any url and content.
I will give an example: the task was set to implement such a page, where there would be a plain text field, to which ckeditor is bolted and the administrator could change and write the necessary text about the company, as well as rewrite it. The first thought that visits you is the usual entry in the model and in the controller (view) to make a class based on a TemplateView, and the page was created without any problems. But then you begin to understand that this is a very bad style and if this administrator starts adding new records to the database, the layout will go. Immediately comes to mind a way to override, for example, the method get_context_data or get_queryset (in a ListView). And there to make the necessary selection (for example, to take only the very first record from the database) where the administrator will edit the necessary page, but still it is possible to add new records to the database, which will simply be ignored. Having come up with a couple of ways, I dropped this venture. Considering this to be a bad tone, I remembered the existence of flatpages in Django, but, having refreshed their functionality, it became clear that adding something to their data context is impossible, but you can, for example, specify the desired template that is processed by the 'template', but here the text that you specify in the text field is not processed by the 'template engine'. It is worth considering, but for me it was not a big problem. But what was, is the fact that initially flatpages are not an extensible module and it is impossible to fasten such an important ckeditor. I had to think how this could be done. But it was this functionality that I needed. After the introductory part, now let's move on to a more detailed study of such a good flatpages module, but unfortunately inferior, let's fix it.
What is static pages in janga are pages whose contents are not generated on the basis of the data stored in the model, but are given as ordinary html code in the corresponding predefined fields.
The main disadvantages are:')
- The data is not generated based on the data from the model, and therefore in views.py (hereinafter I will call it the MVC controller, and not the MVT view), we cannot somehow process them, supplement them, and put something else in the data context. Nor can we initially expand or change the model (models.py).
- The content of such pages should be pure html code - this is the main reason why out of the box flatpages are inferior. It is also worth understanding that this code is not processed by the template engine.
Main advantages:- The content of flatpages includes the web address of the page, its title, content and most importantly the path to the template file. The last item is the key, despite the fact that we can not transfer data, but we can make the desired page using: a basic template in which we have a menu configured with tags and janga variables, specify the places where you need to display data from flatpages , connect the 'included templates' and so on.
- One entry in the model corresponds to one page on the site, which is a big plus, the system is fully configured as necessary, which allows us not to write our own bicycle.
Project Setup:
- In settings.py add.
INSTALLED_APPS = [ … 'django.contrib.sites', ''' web- Django. , flatpages.''' 'django.contrib.flatpages', 'flatpage_main' # , . … ]
- Add to the project (settings.py) SITE_ID = 1 and in MIDDLEWARE 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
- We synchronize with the database to add the necessary tables to the database (up to 5 steps of 'flatpage_main' do not write to INSTALLED_APPS).
- We go to the administrative site to check that everything works. You should have a "simple page" graph.
- Create a new application - python manage.py startapp 'flatpage_main'.
- We are setting up ckeditor, this material is already available on the Internet, I think you will be able to install and configure it, and learn how to use this example. If necessary, I will try to write an article on Habr, but the material on this issue is on the Internet.
The implementation of the task:
- Go to the model and add the following code -
from django.db import models from django.contrib.flatpages.models import FlatPage from ckeditor_uploader.fields import RichTextUploadingField class NewFlatpage(models.Model): flatpage = models.OneToOneField(FlatPage) description = RichTextUploadingField(verbose_name = ' ',default='') text_block = RichTextUploadingField(verbose_name=' ',default='') def __str__(self): return self.flatpage.title class Meta: verbose_name = " " verbose_name_plural = " "
We will understand what is written here:
... import FlatPage Add a model to which we will refer.
... import RichTextUploadingField special field that is needed for ckeditor to work
In our new class, we link through OneToOneField to the FlatPage model, thereby creating the necessary connection, which allows us to increase the basic flatpages functionality by expanding it.
And then we add any fields we need that we want to be in the admin and in the future on the page itself, thereby we can add a field for any content we need.
- The next step is admin.py.
from django.contrib import admin from django.contrib.flatpages.admin import FlatPageAdmin from .models import * class NewFlatpageInline(admin.StackedInline): model = NewFlatpage verbose_name = "" class FlatPageNewAdmin(FlatPageAdmin): inlines = [NewFlatpageInline] fieldsets = ( (None, {'fields': ('url', 'title', 'sites')}), (('Advanced options'), { 'fields': ('template_name',), }), ) list_display = ('url', 'title') list_filter = ('sites', 'registration_required') search_fields = ('url', 'title') admin.site.unregister(FlatPage) admin.site.register(FlatPage, FlatPageNewAdmin)
Let's start parsing:
The first class NewFlatpageInline and the attribute in the second class inlines = [NewFlatpageInline] creates a link between these classes, making it possible to display fields from two interrelated tables on one page ('allows editing related objects on the same page with the parent object').
fieldsets allows you to specify the fields and settings that will be displayed in the admin interface of the parent object (flatpage), the extra settings have been removed.
The last two lines are the removal and registration of models in the admin panel.
- The third step is urls.py.
url(r'^main/$', views.flatpage, {'url': '/main/'}, name = 'main'),
We add this line if we clearly know that this page will be exactly, and we want to process it in the base template, for example, in the menu, and refer to it by the name in the template variable, because the template itself is rendered as a “template engine”.
For other pages you can specify - url(r'^/', include('django.contrib.flatpages.urls')),
Thus, any other url address will be associated with the url address that you specify when creating a new page.
- The fourth step is the template:
{% url 'main' as main %} {% if request.path == main %} <li class="navigation__elem navigation__elem--main navigation__elem--current"> <a href="{% url 'main'%}" class="navigation__href navigation__href--current"><i class="demo-icon icon-main__icon"></i></a></li> {% else %} <li class="navigation__elem nav-active"><a href="{% url 'main'%}" class="navigation__href"><i class="demo-icon icon-main__icon"></i></a></li> {% endif %}
Above, I wrote an example of how the menu works with flatpages and the rest of the pages based on controllers and templates, I think the code here is extremely clear and understandable, comments are unnecessary. As you can see, getting the name of the url of the address from urls.py, and then processing it is not difficult, thereby closing the last difficulty in implementation.
The final touch, in the template that we specified when creating the page, when creating the page in the admin panel there will be a field that indicates the template for this page (for example: main.html). In this template, we add the fields we need, using variables.
{{flatpage.newflatpage.description|safe}}
and
{{flatpage.newflatpage.text_block|safe}}
, thereby allowing us to display the necessary data on the summary page. In this template, everything works the same as in others, for example, inheritance from base.html.
- Deploy - when deploying you will encounter a couple of errors related to the operation of 'django.contrib.sites', you must enter the shell (python manage.py shell) and write the following commands:
>>> from django.contrib.sites.models import Site >>> site = Site.objects.create(domain='http://_.ru/', name=''http://_.ru/) >>> site.save()
This should help solve the problem with the exception.
That's all! We got a cool and convenient way to add, edit and delete pages on your site. We learned how to implement a menu that allows you to switch between active and non-active items and it doesn’t matter whether it flatpages or pages with controllers. We also worked with ckeditor and figured out how to configure it. Dismantled all the passing moments and difficulties. And the most important thing is that they connected everything into a convenient and useful tool that will allow you to competently administer the site in the future, as well as develop it, which of course is convenient for the end user. I hope this article was helpful and will help many people in their work! Someone will save time. And someone will write in the comments below additional tips and complement it!