Control apps from the admin

Hi

I want to know how I can control the apps I have for my project from within the django admin area. In other words I want to be able to install and enable or disable and even remove apps that are created from my project. So for example if I have a shopping project and I have an app Products I want to see the project in the admin section and then enable or disable or remove the app from the project. I want to also be able to add new apps by uploading a zip file with all the files. I’m sure it’s possible but how would one go about doing this?

Interesting idea, but not exactly practical. Installing, configuring, enabling, or disabling apps requires a restart of the Python process running Django. So you’d have to set something up outside the context of your Django environment that is capable of stopping and restarting your server based upon actions taken within your admin app. (Which, of course, is going to interfere with anyone else using the system at the same time.)

You’ll also need to be able to edit your settings as part of this process as well. Some apps (e.g. Django Debug Toolbar, Treebeard) have settings outside of just being listed in the included apps list as part of the installation process. These could also include changes to url settings.

You don’t need to upload zips - most third-party apps are installed from PyPI using pip. You could do the same thing. You could build a .whl (wheel) file, upload it, then do a pip install from the wheel. (Or, you could set up your own PyPI-like repository to do the pip install from there.)

In addition to any settings file changes, it’s also going to need to handle any database changes as well. Those also need to be done outside the context of the running Django environment.

So yea, it can be done. (Clearly, anything you can do manually can to some degree be automated.) But given what needs to be done to enable / disable those apps, I have my doubts that it’s going to be practical in more than a small handful of special cases, and probably only with apps that you’ve written.

(I’m going to guess that you have some experience with frameworks such as Wordpress or Drupal where it’s common to do those sorts of things. There are some fundamental differences between the architectures of those frameworks and the PHP runtime and Django that make it more practical there than here.)

To answer your last question: “how would one go about doing this?” My answer is, I wouldn’t. I don’t see the potential benefit outweighing all the pitfalls with trying to set up something like it.

Yes I know Drupal and Wordpress work like that and I want it to work exactly the same and yes thanks for the own repository idea I won’t be using zips then but will create my own repository but I must be in some way in control of enabling or disabling the apps dynamically without having to restart the server. It’s kind of like the whole object of the project. It’s like this: The project is for say games and so if someone (a public user) wants to play a new game he/she can buy it and then the system will enable it and then the user can play the game, inside the main django app. We will write all the games but we must be able to dynamically enable or disable them? Any idea how I can do that?

and thanks for the advice

Ok, it sounds like you’re talking about something different here.

Apps aren’t enabled / disabled on a per-user basis. Apps are applied system-wide.

In the type of system you describe, all apps would be installed and active in the system, you just need to manage access on a per-user basis - which is a completely separate concept. You can manage access to a view by user, which either allows them to access that application or not.

Yes I understand they are enabled system-wide but I don’t have all the apps from the start. They are added dynamically. So I might get a new app tomorrow then I want to add it to the system without having to restart the whole system again

I guess it’s theoretically possible that you might be able to kludge something together that kinda-sorta works, but my guess is you’d be diving deep into Django’s internal structures to try and make it all work without it crashing down around your ears - especially since in a common runtime environment such as uwsgi, you’ve actually got multiple instances all running concurrently which would need to be updated at the same time.

Maybe someone else with more in-depth knowledge of the Django “startup” sequence might jump in with some more useful ideas, but all I can say at this point is “Good Luck!”

Thank you for your time and advice it is greatly appreciated. Will have to do more research and ask more questions.

This looks like it could be a solution to this problem:

If you read through the answers, you’ll see that -

  • They’re talking about app-specific settings, not system settings.

  • They reference the doc page: Altering settings at runtime which states as the very first sentence (emphasis mine):
    You shouldn’t alter settings in your applications at runtime.

  • The highest up-voted answer starts:

    AFAIK, the Django settings are supposed to be immutable. There are multiple reasons for this, the most obvious being that Django is not aware of the server’s execution model (prefork / multi-threaded).

  • Changing settings is not the only thing that occurs internally when you activate or deactivate apps.

So yes, what they’re talking about here might be useful as settings within an application, but doesn’t address the issues involved in trying to load a new app while the system remains up. What happens internally at startup is a lot more than just seeing that an app is in the list.

Ok thank you Ken I get it. More work lies ahead :slightly_smiling_face:

If you want to limit access on a per-user basic you need to use permissions and mixins. If you’re taking a functional-based view approach, you can create decorators that mandate specific permissions active on the user accessing the view. For example, if an admin has a special page for updating protected information, the decorator should only allow users with the ‘is_superuser’ flag to be True. Otherwise, the user attempting access gets a 404 or permission denied page. If you’re using a class-based view approach (my personal preference), you can use the pre-built mixin classes Django offers to add logic to your class-based views. I recommend looking into the UserPassesTestMixin (probably what you’ll want for your scenario) and the other mixins Django offers. They keep SLOC to a minimum and are extremely easy to implement.

Hi @calvincani

I am looking for similar things for my application.

Let me know if you identify some way to achieve this?

Awaiting your reply.

As was mentioned in an earlier reply, this really isn’t a good idea. If this is something fundamentally required for your project, you should be looking at a different way to architect it. You could either work to decouple these “dynamic applications” from the core application, or possibly even move to a different framework. But a “production-quality” deployment of Django is not going to support dynamic application additions and removals without an application restart.

Thanks @KenWhitesell

I am not exactly looking the same where Django admin installs/Uninstalls the app from the backend.

Looking for a solution where the Django admin can enable and disable from the admin panel. The application will be there in “Installable_apps” and active. But working if it’s enabled.

I need a solution app-wide not user-wide. Admin has to work more if it’s user-wide. In User-wide mode need to modify access for each and every user if need to enable or disable it.

So let me if this kind of alternative solution is available or if any approach you can suggest.

Awaiting your response.

I’m not aware of any facility available (or even possible as a generic solution) to limit access at the “app” level. I’m guessing you’d still have to implement this on a per-view basis.

The user_passes_test function does not need to use the User object being passed to it. It could just check the status of the application attempting to be accessed and approve/reject based upon some status for that application.

Or, you could get some ideas from the source of the user_passes_test decorator and implement your own that is more customized for your requirements.

Or, if you’re using CBVs consistently, you could create custom CBV classes (or a mixin) that performs a custom check similar to what the LoginRequiredMixin does - only for the app rather than the user.

This is a much different issue than the original question. If you wish to continue to examine this topic in more detail, I’d perhaps suggest opening up a new topic for this.