Showing link in menu conditional on logged in status - django

Using Mezzanine it's easy to toggle showing or not showing of regular pages using the 'Login necessary' toggle.
I want use this toggle for a Link-type page, unfortunately it's not there. What's the best way to achieve the toggling effect in Mezzanine?
I probably can inherit from the Link class and do something like this
class LoginLink(Link):
login_required = models.BooleanField(_("Login required"), default=False,
help_text=_("If checked, only logged in users can view this page"))
and use LoginLink as the page type instead but I hope there is a better solution. A better solution would have the following:
No new page type
No messing with core Mezzanine
I'm pretty sure my proposed solution works (but I really don't like it). Is it possible to extend the Mezzanine Link type in such a way only my own Link type is visible in the admin?

I've found a solution that's pretty short and sweet. The nice thing is that the login_required is already available for all pages through pages_page so we don't have to do any database modifications. With this solution you lose the option to create the default link type but in my case that's a plus from a usability perspective. One Link type is sufficient. The code for my solutions is as follows and goes into admin.py
# Get the Mezzannine admin logic and the Link model
from mezzanine.pages.admin import LinkAdmin
from mezzanine.pages.models import Link
# Create a custom LoginLink, with the login_required code from the page.
from copy import deepcopy
class LoginLinkAdmin(LinkAdmin):
fieldsets = deepcopy(LinkAdmin.fieldsets) + \
((None, {"fields": ("login_required",)}),)
# Unregister and register the LinkAdmin
admin.site.unregister(Link)
admin.site.register(Link, LoginLinkAdmin)
Adding this should be copy and paste.
Edit
I later found that this is the preferred way in the documentation. However, this only seems to work in my dev environment and not in our production-like environment. Further searching led me to the Model Customization docs. I didn't get this to work but it gave me a new idea. Mezzanine overrides the standard admin.site functionality, as described in this comment in /mezzanine/boot/lazy_admin.py:
"""
Defers calls to register/unregister until autodiscover is called
to avoid load issues with injectable model fields defined by
``settings.EXTRA_MODEL_FIELDS``.
"""
So I've come up with yet another solution. I've put the code above in my urls.py after admin.autodiscover() and deleted it from admin.py. This is ugly but it seems to work.

Related

Why are my models not showing up in django admin site?

I have made alot of models and forgot to register them when I made them, after I realized I didn't register them I went and registered them the usual way (shown below). I've deleted the database and all migrations (including __pycache__) but haven't deleted the __pycache__ in the inner project folder (that holds settings.py) because I don't know if that would cause problems or not. I've tried using admin.register(Comment,admin) but that didn't work and, as you know, isn't necessary. I'm not sure what other information I would need to give so please let me know what else you need to know. Just so you know, I have 'django.contrib.admin' and 'django.contrib.sites' in the INSTALLED_APPS and also have path('admin/', admin.site.urls) in the project level urls.py
admin.register(PicturePost)
admin.register(VideoPost)
admin.register(TextPost)
admin.register(Comment)
admin.register(Report)
Please use below code because you are not using correct method to register the model. admin.register is method decorator for ModelAdmin class.
admin.site.register(PicturePost)
admin.site.register(VideoPost)
admin.site.register(TextPost)
admin.site.register(Comment)
admin.site.register(Report)
admin.register is a decorator that you should apply to custom ModelAdmin classes - not a function that you can use to register models.
You need to use admin.site.register instead:
admin.site.register(PicturePost)
etc.

How do you override Django's admin app_index?

I'm very familiar with how to override Django's admin templates, but I haven't been able to find any instructions on how to properly override the context available to said templates. For example this page:
/admin/users/
The style for this page can be overridden by creating a file at:
root/users/templates/admin/users/app_index.html
But what if I want to do some more Python-level stuff before the template is loaded? Specifically in my case I want to generate a sort of dashboard for /admin/users/ and for that I'll need to run a rather elaborate query.
Now I know I could hack this by creating a template tag that does the query for me, but frankly that's pretty dirty as you're hitting the database from a template, so I'd like to do this better if such a way exists.
If however you can state with confidence (and convincingly) that this simply can't be done without rewriting django.contrib.admin.sites.AdminSite.app_index, then I'll flag your answer as correct and go with my ugly hack.
It can be done, and without rewriting app_index. Since AdminSite is intended to be customized through subclassing.
Looking at the AdminSite implementation, you can see app_index has a keyword argument extra_context. You can utilize this for your purposes to avoid rewriting as follows
from django.contrib.admin import AdminSite
class MyAdmin(AdminSite):
def app_index(self, request, app_label, extra_context=None):
if not extra_context:
extra_context = {}
extra_context['my_new_key'] = 'val'
super().app_index(request, app_label, extra_context=extra_context)
The problem then arises that you would need to instantiate your custom site and use it to set your urls and register model admins. If this is inconvenient as suggested by Alasdair, you might consider this.
All that being said, you will still hit the database on the request anyway, similar to your concern with the tag. Only caching would solve that.

Use custom Comment app and the default Comment from Django

I have a custom comment app but also want to use the original Comment app, without the added fields of my custom app. Is there a way to do this?
Thanks!
Sure, but if you named your custom app "comments" as well, you'll have to be extra careful to keep things straight. It would probably be best to import Django's comment system like so:
from django.contrib import comments as django_comments
You can then access the comment model like:
django_comments.Comment
Which will signal where it's actually coming from at a glance.

Use Django admin modules inside own forms

In the Django admin i have a customized changelist with added search and filters. I have been looking alot but cannot seem to find a way to use the whole "changelist module" outside of admin. So i can embed it in one of my own pages.
I do not need any of the authentication or anything like that. I just want to show a table (for a content management backend) that has the nice search, sort and filter capabilities.
Is there perhaps any documentation about doing this?
Of course you can use the ChangeList class for your own projects. I cannot give you a full documentation on doing so here, but some points to start with.
Have a look here to see how the
ChangeList has to be initialized in
your view. (The ChangeList class
lives at
django.contrib.admin.views.main, so
import it from there!)
Look at the admin templates to see how the
corresponding template tags are used.
(also this template)
Maybe you will also find the django.contrib.databrowse-application helpful!

Best way to fix django admin preview of flatpage attached to multiple sites

I have flatpage attached to multiple sites. Its admin preview chooses
arbitrary site, which is quite obvious after debugging up to lines 35-36 of
django.contrib.contenttypes.views.shortcut().
What would be the best way of fixing this problem?
I see that the shortcut() function takes a request object, so I could just extract host from there, but I prefer to not patch the live server.
I haven't looked at catching admin url yet, so maybe someone can suggest some nice solution?
In my opinion, this could be considered a bug in Django, and at least a partial fix would be to check if the current SITE_ID is one of the sites related to the object, and if so use that one instead of an arbitrary one. You could file a ticket with a patch.
To fix it without patching Django, you might look into overriding the admin edit-form template for the flatpages model so that you can put the URL you want into that link instead of the default one that goes to the shortcut view. I haven't looked into it enough to know how clean that would be.
Another option might be to monkeypatch the Flatpage model with a get_absolute_url method that actually returns a complete absolute url, including the domain, based on Site.objects.get_current().domain.