The goal is to create a text file editor within the Wagtail admin site.
Specifically for robots.txt file. I want the admin to update the file from the admin.
How can I do that?
There are some considerations to make for the robots.txt file hitting your server and doing a database read each time. You probably will want to consider some kind of caching layer here, however I have answered assuming you will resolve that and just want to get a Wagtail 'editor' solution here.
Wagtail provides a contrib.settings module that allows you to have a settings model per site. This is a very helpful module that allows users, usually admin only users, to modify content that is specific to a site but does not suit the idea of a 'page'.
https://docs.wagtail.org/en/stable/reference/contrib/settings.html
Settings model
In your app's models.py file - set up a new settings model.
from django.db import models
from wagtail.admin.panels import FieldPanel
from wagtail.contrib.settings.models import BaseSetting, register_setting
#register_setting
class MySettings(BaseSetting):
robots = models.TextField(blank=True)
panels = [
FieldPanel('robots'),
]
robots.txt view & template
There are lots of ways to load a View with robots.txt
Accordbox has a good tutorial on how to set up a robots.txt view https://www.accordbox.com/blog/wagtail-seo-guide/#robotstxt
Once you have your view, you can get the settings output via the model class.
# using in your view
def robots_view(request):
robots = MySettings.for_request(request).robots
## return the content in your view
Alternatively you can use in your template context via an injected template context variable
note: 'wagtail.contrib.settings.context_processors.settings' must be added to context_processors
User-agent: *
{{ settings.app_label.MySettings.robots }}
Considerations
If possible, it would always be better to serve a static file here, or strongly cache this value at a minimum.
Validation is a must - make it hard for your editors to break your website, remember that search engines only crawl this semi-regularly and breaking this could mean a few days of de-listing or broken listings if your editors are not careful.
Permissions are a must, maybe even a two step process to push these changes live somehow?
You could possibly put a robots field on your HomePage model and access the data in your robots view. This kind of breaks the concept of this model only reflecting the home page but then extending to the 'root' content.
To reverse a model url for Django Admin, you need to write admin:appname_modelname_change . But what if the model name has underscores?
I have a model called AdNetwork inside an app called pubscout, and I am trying to reverse its url.
admin:pubscout_adnetwork_change doesn't work
admin:pubscout_ad_network_change doesn't work either
How to fix this?
Please can you show us your code.
reverse('admin:%s_%s_change' % (app_label, model_name), args=(object_id,))
Something like this should work:
reverse('admin:pubscout_adnetwork_change', args=(object_id,))
... where object_id is an AdNetwork pk.
Please make you have registered the AdNetwork model and hooked the AdminSite instances into your URLconf.
Docs: https://docs.djangoproject.com/en/1.9/ref/contrib/admin/#reversing-admin-urls
How can we add 'blog.site_name.com' or such types of url in Django instead of 'site_name.com/blog/' to urls.py in Django? I want to make URLs like 'mail.google.com', 'drive.google.com'. How can we make such urls in Django? Is there any easy way to do this?
You can create two urlconf files, one for site_name.com, another for blog.site_name.com.
Then you make a custom middleware that will switch the urlconf based on domain name. See Django docs for details.
I want to change the default url for django admin from /admin to /djadmin so that I can use /admin for my own purposes.
So far all I have done is update the urls.py file, changing the admin url to
url(r'^djadmin/', include(admin.site.urls)),
and then adding my own
(r'^admin/', include('my_app.admin_urls')),
However when I now navigate to /admin I get the following error
Forbidden
You do not have staff privileges.
Which since I don't require this parameter I assume is coming from an internal django check. If I change the user to have the is_staff flag checked then it works fine and redirects to my admin pages.
Is there something else I need to do to stop Django checking for the is_staff flag whenever I navigate to an admin url?
The is_staff flag is wrapped in the code of Django admin site, because is intended to restrict the usage of this interface only to a subgroup of selected users (the ones that administrate the content of the website). The only way to remove it is to subclass the Django's admin site, so a your own custom site.
For admin site customization see the official documentation or other answers like the one I've posted previously. In the AdminSite subclass you have to override the has_permission method with:
def has_permission(self, request):
return request.user.is_active
You also need to use a custom admin form (AdminSite.login_form) and modify the base.html template, removing references about is_staff in a pair of if statements.
I want to have 2 separate admin sites inside a Django project.
By separate I mean - they should have separate users authentication, they should administer different models, and have different looks and URLs.
The reason I want to do it is the customer wants separate section to administer the CMS part of the page, and separate to use as a 'back-office' solution.
I thought about just making a copy od django.contrib.auth appliaction in my project tree, naming it differently and using separate admin.site.register() calls for both of them. This way I can have other models available in each one of them, diffrent looks, etc. I don't know how to solve the user-authentication problem (I should have different user to be able to log into CMS then into the BackOffice).
Anyone happened to do this before and could give me some hint? Or what I plan to do is just wrong by design?
You can subclass Django's AdminSite (put it eg. in admin.py in your project root):
from django.contrib.admin.sites import AdminSite
class MyAdminSite(AdminSite):
pass
#or overwrite some methods for different functionality
myadmin = MyAdminSite(name="myadmin")
At least from 1.9 on you need to add the name parameter to make it work properly. This is used to create the revers urls so the name has to be the one from the urls.py.
Then you can use it in your app's admin.py the same way as you do with the normal AdminSite instance:
from myproject.admin import myadmin
myadmin.register(MyModel_A)
You also need to define some urls for it (in your project's urls.py):
from myproject.admin import admin, user_site
from myproject.admin import myadmin
urlpatterns = patterns('',
...
(r'^admin/', include(admin.site.urls)),
(r'^myadmin/', include(myadmin.urls)),
Also see this: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#adminsite-objects
To register models in different AdminSites you just need to create different instances of django.contrib.admin.sites.AdminSite, see this.
You will be good to go with two different admin sites managing different models and having different templates.
For authentication and permissions you should be able to use the build-in django.contrib.auth as is with custom permissions (hope someone else will be able to help more here)
I'm not sure that my finding, reported here, would have been entirely helpful to kender because, among other things, I don't know if he was talking not only about two admin sites but also two databases, one for each. That's my situation. I got the bright idea that I wanted one of my apps, a new app, to have its own database and own admin pages.
But I ran into a problem with the AdminSite subclassing approach of Bernhard Vallant, though it seems to be the orthodox and essentially correct thing to do. I resolved the problem.
Here's the mod to Bernhard Vallant's code that I found to be utterly necessary:
from django.contrib.admin.sites import AdminSite
class MyAdminSite(AdminSite):
pass
#or overwrite some methods for different functionality
myadmin = MyAdminSite(name='anything')
Yes, I do really mean name='anything' that you choose (as long as it isn't 'admin'). And I've toggled in and out with it and it fails every time without the anything-but-admin name assignment.
The symptoms that I acquired were that when I added the second database and created a myadmin for it and then registered the model with myadmin.register(My_ModelA), and went to look at the two admin app pages, the one for my new app that used the second database and myadmin and the model My_ModelA looked fine, but my old admin page showed dead links for its models and when I clicked there on a non-dead link for an app (an old app that uses the old database) I got a 404 code to the effect that the page didn't exist.
Also, I don't know that it matters, but I did something different from what
Bernhard Vallant did in the project urlconf:
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/', include('mynewapp.urls')),
url(r'^someword/admin/', include(admin.site.urls)),
)
OK, "someword" is irrelevant--- there for appearances with regard to the end user and not the name of an app or the project. But the associated admin is the one for my old app and old database. Note the autodiscover() inclusion. There's some murky language in the docs to which Bernhard Vallant linked regarding its use when the project urlconf is configured as Bernhard Vallant has it with the myadmin import but also with a reference to the default admin.
And for the urlconf for mynewapp I have:
from django.conf.urls import patterns, url, include
from myproject.admin import myadmin
urlpatterns = patterns('',
url(r'/', include(myadmin.urls) )
)
urlpatterns += patterns('mynewapp.views',"... url() stuff for mynewapp's views"),
)
Notwithstanding the utter necessity of naming your AdminSite instance internally to something other than 'admin', I must add that when it came time to jazz up the mynewapp's admin.py file with some admin.ModelAdmin subclassing, it was necessary to indeed use admin.ModelAdmin as the parent class. myadmin is after all an instance of a subclass of AdminSite. As such I gather that it's on a par with admin.site, not with admin.
This is all very confusing to a NOOB like me because admin, with the lower case, looks like an instance, and I am unfamiliar with subclassing instances. So I assume that it isn't.