Django: Register models to admin site dynamically on request - python-3.x

I have some django models registered to my admin site by declaring them in my admin.py file. I however do not want specific internal users to be able to see certain tables. Is there a way to dynamically registered models to the admin site when a request is is received?
e.g something like if request.user.email has a .gmail domain don't register the user's table.
admin.py
from django.contrib.admin import AdminSite
admin_site = MyAdminSite()
for model_name, model in app.models.items():
model_admin = type(model_name + "Admin", (admin.ModelAdmin, ), {'list_display': tuple([field.name for field in model._meta.fields])})
admin.site.register(model, model_admin)

Related

Django admin - User and group extend

Iam trying to update my user model in Django's admin Panel.
I want to add a field/column in Admin panel named "Group" for Users. This field will have the option to select any value from the existing Groups (single option only/Dropdown).
I tried to search for the document but I couldnt found out the relevant information to manipulate the User Admin panel. Although I do found a few blogs and video where they have created a new app and extend the User model.
Is it possible to update Admin panel for User? Please suggest any document or blog or any approach to achieve the goal.
You will probably have to extend the user model in models.py, and also to use Inlines to reflect the changes to the admin site. Both of these steps are performed by Julia in this video: https://www.youtube.com/watch?v=sXZ3ntGp_Xc
The documentation for Inlines can be found here.
So in your admin.py you can extend UserAdmin and in Permissions if you add groups it will create a group assignment to your user create form in admin.
class CustomUserAdmin(UserAdmin):
add_form = UserCreateForm
fieldsets = (
(None, {'fields': ('email')}),
('Permissions', {'fields': (('is_active', 'groups'), )}),
)

Unble to use the working Django modles for index.html page ( Modles data entried in admin page but not visible in index.html page)

I have created modles in modles.py as below:
class Title(models.Model):
title = models.CharField(max_length=100)
def __str__(self):
return self.title
, migrate successfully, later on, registered the moodle in admin.py as
admin.site.register(Title),
But the issue is I can see in admin pannel that modles created and upadted the data but in index.html page, I used as {{Title.title}} which seems not working. Need help ????? Do i need to create views and what I should types in views.py
I have gotten my answer as I have to use for loop in order to work my models.

How can I protect the loopback explorer by username and password?

I've just started using loopback4 and I would like to protect the /explorer from being public. The user would initially see a page where username and password must be entered. If successful, the user is redirected to /explorer where he can see all API methods (and execute them). If user is not authenticated, accessing the path /explorer would give a response of "Unauthorized". Is there a way to easily implement this?
There is issue talking about a GLOBAL default strategy is enabled for all routes including explorer in https://github.com/strongloop/loopback-next/issues/5758
The way is to specify a global metadata through the options:
this.configure(AuthenticationBindings.COMPONENT).to({
defaultMetadata: {
strategy: 'JWTStrategy'
}
})
this.component(AuthenticationComponent);
registerAuthenticationStrategy(this, JWTAuthenticationStrategy)
But in terms of enabling a single endpoint added by route.get(), it's not supported yet, see code of how explorer is registered. #loopback/authentication retrieves auth strategy name from a controller class or its members, but if the route is not defined in the controller, it can only fall back to the default options, see implementation

django registration module with multiple registration forms

I want to use 2 different forms for registering Seller and buyer using dhango registration module. Both forms will be different. I have created accounts/forms for both forms, but not sure how to invoke the different template for different user categories. In both the cases, it is invoking default registration_form.html.
here is my accounts/forms.py
class UserRegForm(RegistrationForm):
news_letter=forms.BooleanField(required=False, initial=True)
first_name=forms.CharField(max_length=30)
last_name=forms.CharField(max_length=30)
class SellerRegForm(RegistrationFormTermsOfService):
captcha = ReCaptchaField()
shop_name=forms.CharField(max_length=30)
mobile_number=forms.CharField(max_length=30)
email=forms.CharField(max_length=30)
address=forms.CharField(max_length=100)
city=forms.CharField(max_length=30)
state=forms.CharField(max_length=30)
pin_code=forms.CharField(max_length=10)

How to secure the flask-admin panel with flask-security

I'm looking to secure Web API made using Flask and integrated with flask-admin to provide an admin interface. I searched and found that flask-admin has an admin panel at /admin and by default anyone can have access to it. It provides no authentication system and completely open (without any security) since they didn't assume what would be used to provide security. This API has to be used in production, so we can't have an open /admin route for everyone hitting the url. Proper authentication is needed.
In views.py I can't simply put the /admin route and provide authentication through decorator as that would be over-writing the existing route already created by flask-admin so that would cause an error.
Further research shows that there are two modules flask-admin and flask-security. I know that flask-admin has is_accessible method to secure it, but it doesn't provide much functionality which is provided by flask-security.
I've not found any method there to secure the end-point /admin plus all other end-points beginning with /admin such as /admin/<something>.
I'm looking specifically to do this task with flask-security. If it's not possible, please suggest alternatives.
PS: I know I can lock ngnix itself, but that would be the last option. If I can have an authentication system through flask-security that would be good.
Since this is the first result for the "flask-security secure admin" google search, and there is no out-of-the-box solution yet, I think I can contribute.
A similiar question was asked on the flask-admin project Issue List and a simple example using flask-login and mogodb is provided here.
I made an example using SQLAchemy for a sqlite database and flask-security. See the sample flask app below:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import os.path as op
from flask import Flask, render_template, url_for, request
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.event import listens_for
from flask.ext.security import current_user, login_required, RoleMixin, Security, SQLAlchemyUserDatastore, UserMixin
from flask_admin import Admin, AdminIndexView
from flask_admin.contrib import sqla
# Create application
app = Flask(__name__)
# Create dummy secrety key so we can use sessions
app.config['SECRET_KEY'] = '123456790'
# Create in-memory database
app.config['DATABASE_FILE'] = 'sample_db.sqlite'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE']
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
# Create directory for file fields to use
file_path = op.join(op.dirname(__file__), 'static/files')
# flask-security models
roles_users = db.Table('roles_users',
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))
class Role(db.Model, RoleMixin):
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(255))
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
active = db.Column(db.Boolean())
confirmed_at = db.Column(db.DateTime())
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='dynamic'))
# Create Security
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore)
# Only needed on first execution to create first user
##app.before_first_request
#def create_user():
# db.create_all()
# user_datastore.create_user(email='yourmail#mail.com', password='pass')
# db.session.commit()
class AnyModel(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Unicode(64))
def __unicode__(self):
return self.name
class MyAdminIndexView(AdminIndexView):
def is_accessible(self):
return current_user.is_authenticated() # This does the trick rendering the view only if the user is authenticated
# Create admin. In this block you pass your custom admin index view to your admin area
admin = Admin(app, 'Admin Area', template_mode='bootstrap3', index_view=MyAdminIndexView())
# Add views
admin.add_view(sqla.ModelView(AnyModel, db.session))
# To acess the logout just type the route /logout on browser. That redirects you to the index
#login_required
#app.route('/login')
def login():
return redirect('/admin')
#app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
# Build sample db on the fly, if one does not exist yet.
db.create_all()
app.run(debug=True)
Please refer to the flask-security docs to learn how to customize the login page.
Hope this helps.
You should check out the Flask-Security-Admin project, I think it covers pretty clearly what you are looking for.
Taken directly from the link above:
When you first visit the app's home page, you'll be prompted to log in, thanks to Flask-Security.
If you log in with username=someone#example.com and password=password, you'll have the "end-user" role.
If you log in with username=admin#example.com and password=password, you'll have the "admin" role.
Either role is permitted to access the home page.
Either role is permitted to access the /admin page. However, unless you have the "admin" role, you won't see the tabs for administration of users and roles on this page.
Only the admin role is permitted to access sub-pages of /admin page such as /admin/userview. Otherwise, you'll get a "forbidden" response.
Note that, when editing a user, the names of roles are automatically populated thanks to Flask-Admin.
You can add and edit users and roles. The resulting users will be able to log in (unless you set active=false) and, if they have the "admin" role, will be able to perform administration.
The relevant code is located in main.py, and is clearly commented to explain how to replicate the process of securing the flask-admin panel using flask-security.
The most basic, relevant piece to you is the following (line 152-):
# Prevent administration of Users unless the currently logged-in user has the "admin" role
def is_accessible(self):
return current_user.has_role('admin')
I hope this is helpful.
I use #RamiMac's answer for all sub-views, but for the index one (by default /admin), I use this method, re-wrap the method with an admin role required to view.
#app.before_first_request
def restrict_admin_url():
endpoint = 'admin.index'
url = url_for(endpoint)
admin_index = app.view_functions.pop(endpoint)
#app.route(url, endpoint=endpoint)
#roles_required('admin')
def secure_admin_index():
return admin_index()
In my project, this goes directly after all my Flask-Admin code, which is itself in its own startup script, custom_flaskadmin.py.
There's section about security in Flask-Admin documentation: http://flask-admin.readthedocs.io/en/latest/introduction/#authorization-permissions

Resources