Django - Pre render signal? - django

I have a 'live settings' app which I use to store certain global site settings. Certain pages of my site reference these settings, although generally they only use 2-3 at a time. I access these settings using a custom template tag like so:
{% settings site_name %}
Each time I use this tag, the model will retrieve the setting from the database, so if I had something like:
{% settings site_name %} {% settings num_articles %}
the database would get queried twice.
What I'd like to do is not hit the database more than once per page for the settings values, if I could get all the settings used on a page and then hit the database to retrieve them all, that would be much better.
I had a look through the documentation and it seems Django has no pre render signal which I could use to update any references to the settings, so does anyone have any suggestions how I could optimise this system? And yes obviously caching is the obvious answer but I'd still like to improve on this for when the page isn't cached.

Agreeing with Daniel that process_template_response is the hook you're looking for. I don't know how many settings you have, but it could also make sense to retrieve all settings once, and store them in some dictionary like structure, so you can access them anytime without hitting the database. You could retrieve them once either per request, or - even if your settings do barely change - when django initializes. You could additionally use django's signals to update your cached settings on delete or update.
If you have a look at django-dbsettings you will see it does a similar thing!

Django 1.3 includes the new TemplateResponse class, which allows you to modify the response later in the rendering process - eg in middleware. This looks like it might do what you want.

If you wish to stick to a scheme similar to what you already have, I'd implement a filter that takes in a list of keys and returns a dict with all the relevant values.
Example filter:
def get_settings(key_list):
# take values from conf.settings. In practice, can be from any source
return dict((k, getattr(settings, k, None)) for k in key_list.split(","))
register.filter("get_settings", get_settings)
Usage:
{# load multiple values with a single call #}
{% with "KEY1,KEY2"|get_settings as settings %}
setting values {{ settings.KEY1 }} and {{ settings.KEY2 }}
{% endwith %}
Note that I used a filter instead of a tag because the with builtin expects a single value before as.

Related

Removing built-in fields from wagtailstreamforms

I'm trying to remove the date, time, and multiselect fields from the wagtailstreamforms Admin page, such that they can't be used in any form site-wide.
I've tried calling register('<field_name>', None) to get rid of it, but this doesn't work:
# wagtailstreamforms_fields.py
from wagtailstreamforms.fields import register
#register('date', None)
#register('time', None)
#register('multiselect', None)
And creating an AppConfig to manually purge the wagtailstreamforms.fields._fields dict of the entries, but that doesn't seem to work either. I've made sure that this AppConfig is part of an app that loads after wagtailstreamforms.
class UpdatedConfig(AppConfig):
name = 'my_new_app'
def ready(self):
from wagtailstreamforms.fields import _fields
_fields.pop('date')
_fields.pop('datetime')
_fields.pop('multiselect')
for x in _fields.keys():
print('{}: {}'.format(x, _fields[x]))
Is there any way to do this, hacky or otherwise? I'm using Wagtailstreamforms 3.1 and Wagtail version 2.2.2.
Im the author of wagtailstreamforms and came across this. The ability to restrict what default form fields are loaded from the package is a great idea.
What I propose is to not load them from the the register method but to load them from a settings dict ie:
WAGTAILSTREAMFORMS_DEFAULT_FIELDS = {
'singleline': 'wagtailstreamforms.fields.SingleLineTextField',
'multiline': 'wagtailstreamforms.fields.MultiLineTextField',
'dropdown': 'wagtailstreamforms.fields.DropdownField'
}
the defaults being all the internal fields. This way it can easily be overridden. We will leave the register decorator in place as to not break anything.
https://github.com/AccentDesign/wagtailstreamforms/pull/110
Please leave any comments / suggestions on the pr or the open issue. If you are happy with this will update docs, merge, release then can amend this as an answer.
Cheers, Stu.
One way would be to override this template: https://github.com/wagtail/wagtail/blob/master/wagtail/admin/templates/wagtailadmin/block_forms/stream_menu.html
{% for child_block in child_blocks.list %}
{% if child_block.name != "date" and child_block.name != "datetime" and child_block.name != "multiselect" %}
<li><button type="button" class="button action-add-block-{{ child_block.name }} icon icon-{{ child_block.meta.icon }}"><span>{{ child_block.label }}</span></button></li>
{% endif %}
{% endfor %}
We were able to get what we needed by putting following code in the app's wagtailstreamforms_fields.py
# wagtailstreamforms_fields.py
from wagtailstreamforms.fields import _fields
if _fields.get('date'):
del(_fields['date'])
if _fields.get('datetime'):
del(_fields['datetime'])
if _fields.get('multiselect'):
del(_fields['multiselect'])
So I guess you can say its a mix of the above 2 methods. It might be obsolete in the near future, see Stuart George's answer and its linked PR.

I need to cache a TemplateView with a querystring - how?

Basically, I'm trying to cache a simple search results page (generated with a TemplateView view) with a URL pattern of:
/search/?q=foo
I've tried:
#cache_page - doesn't work with querystrings (why? the stated reason "querystrings usually do not affect the results" completely depends on 'usually' meaning 'always' which is demonstrably false);
django-fancy-cache - doesn't work with CBVs (but in principle appears to do exactly what I want);
Adjusting the action on my form with an onSubmit() to change the url pattern (so that there's no querystring) - for SOME reason this messes up every other page on the site even though the test form doesn't exist on any of those pages.
I can't be the first person in the universe who needs this :-) ... Pointers to something I've missed in the Django docs or to a package that has eluded my search for it GREATLY appreciated.
You could use template fragment caching for that purpose, using the query string to uniquely identify the cache fragment. In your template:
{% load cache %}
{% cache 3600 search_results request.META.QUERY_STRING %}
<!-- search results here -->
{% endcache %}

Django app to "switch on" other apps for specyfic user

I am new to django and I really like its modular construction so I decided to take advantage of it and put all the separated functionalities each in different app.
Now I need a way to switch on and off this apps by both user and admin.
The user options panel would look like this:
[ ] blog
---------------------
[ ] tagging [BUY]
After checking "blog" option user would get the blog in his profile and after buying and checking "tagging" he would get tagging for the blog.
The admin panel would have an ability to show or hide an app from user panel.
I wonder if:
there is an app which would help me switch on and off an app for specyfic user
and if not -
what would be a proper "architecture" for such django app?
Can it be done dynamically in middleware or should it be done during login (check available apps from database, switch them on, redirect to user home page)?
Any advices for such a task?
Thanks,
Robert
I haven't heard of any such app… But I don't expect it would be too hard to build.
If I were doing it, I would put a permissions check in the entry points to each app. For example:
check_app_permission = lambda request: permissions.check_app_permission("blog", request)
def view_blog(request, …):
check_app_permission(request)
…
(it might even be possible to do some magic and inject this check at the urls.py level…)
Additionally, I would create a has_app_permission template tag:
<div id="sidebar">
{% if has_app_permission "blog" %}
{% include "blog/sidebar_recent_posts.html" %}
{% endif %}
</div>
Or similar.
Finally, there are approximately a million ways you could implement the permission system… And without more information I wouldn't be able to comment. The simplest, though, would be something like this:
class App(Model):
name = CharField(…)
class AppPermission(object):
app = ForeignKey(App)
user = ForiegnKey(User)
def user_has_permission(user, app_name):
return AppPermission.objects.filter(app__name=app_name, user=user).exists()
I would avoid trying to do this with middleware, because if I understand the problem correctly, I expect you will (or, at least, I expect I would) end up spending a bunch of time building a generic framework which, in the end, would just have checks similar to those above.
Does that help? Is there something I can clarify?

Putting links in list_detail.object_list to list_detail.object_detail

I've started using Django and am going right to generic views. Great architecture! Well, the documents are great, but for the absolute beginner it is a bit like unix docs, where they make the most sense when you already know what you're doing. I've looked about and cannot find this specifically, which is, how do you set up an object_list template so that you can click on an entry in the rendered screen and get the object_detail?
The following is working. The reason I'm asking is to see if I am taking a reasonable route or is there some better, more Djangoish way to do this?
I've got a model which has a unicode defined so that I can identify my database entries in a human readable form. I want to click on a link in the object_list generated page to get to the object_detail page. I understand that a good way to do this is to create a system where the url for the detail looks like http://www.example.com/xxx/5/ which would call up the detail page for row 5 in the database. So, I just came up with the following, and my question is am I on the right track?
I made a template page for the list view that contains the following:
<ul>
{% for aninpatient in object_list %}
<li><a href='/inpatient-detail/{{ aninpatient.id }}/'>{{ aninpatient }}</a></li>
{% endfor %}
</ul>
Here, object_list comes from the list_detail.object_list generic view. The for loop steps through the object list object_list. In each line I create an anchor in html that references the desired href, "/inpatient-detail/nn/", where nn is the id field of each of the rows in the database table. The displayed link is the unicode string which is therefore a clickable link. I've set up templates and this works just fine.
So, am I going in the right direction? It looks like it will be straightforward to extend this to be able to put edit and delete links in the template as well.
Is there a generic view that takes advantage of the model to create the detail page? I used ModelForm helper from django.forms to make the form object, which was great for creating the input form (with automatic validation! wow that was cool!), so is there something like that for creating the detail view page?
Steve
If you're on django < 1.3 then what you are doing is basically perfect. Those generic views are quite good for quickly creating pages. If you're on django 1.3 you'll want to use the class based generic views. Once you get a handle on those they are are crazy good.
Only note I have is that you should use {% url %} tags in your templates instead of hardcoding urls. In your urls.conf file(s) define named urls like:
url('inpatient-detail/(?P<inpatient_id>\d+)/$', 'your_view', name='inpatient_detail')
and in your template (for django < 1.3):
...
In 1.3 a new url tag is available that improves life even more.

Flickr albums in django admin

I want to do the following:
Having a model (p.e. a model which handles data about photographic reports) create a section which has a preview of an specific flickr album. The URL will be provided by an URLField (until the first save the preview will not be available).
After the first save, it'll show previews of all the images inside that album, and make them selectable (through jQuery for example). Then again, when the images are selected and the object is saved (I think I can use django signals for this) it will notify a specific user telling him a selection has been made.
Is there any plugins available, or any easy way to implement this in django-admin?
Update: 22 days and no anwers... does that mean it can't be done in django-admin?
I personally can't think of any easy way to implement this in the Django admin, simply because I doubt many people who've done it have thought to open source it. I can imagine that it would be very specific to a certain user's / programmer's needs.
In any case, if you wanted to solve this issue, I'd say that your best bet would be overriding the Django admin templates in your django/contrib/admin/templates/admin folder. I believe you'd be best off by editing change_form.html.
My basic approach would be this:
Check the name of the model using opts.verbose_name. For example, if you wanted to do this processing for a model whose verbose name is "Gallery", you would do
{% ifequal opts.verbose_name "Gallery" %}
<!-- neat gallery view -->
{% else %}
<!-- regular form -->
{% endifequal %}
Make a custom template tag that will display the gallery view / form given the object_id and the type of object. This way you can replace the <!-- neat gallery view --> with a {% show_gallery object_id %}. See the Django Docs for more info on creating custom template tags. It's pretty straightforward.
Add whatever Javascript or custom stuff in your template tag template. What you choose to do is up to you.
Sorry you haven't gotten many more answers to your question. Hope this helps!