Search code examples
python-3.xflaskflask-admin

How do I redirect @expose('/') to @expose('/roll') by onclicking the button


View class :

    from sqlalchemy import desc
    from datamodels.relational_tables import initialize_datamodels
    from dataaccess.postgresql.database import (session_scope)
    import datamodels.relational_tables
    from flask.ext.admin import Admin, BaseView, expose
    from akamai_env import get_akamai_config
    from flask import request
    import json
    from sqlalchemy.sql.functions import now
    from flask import Flask, redirect, url_for
    import logging
    _log = logging.getLogger(__name__)



    akamai_config = get_akamai_config()
    base_url = akamai_config['webserver']['base_url']


    class RollBack(BaseView):

        @expose('/')
        def fetch_healthy_dataset_from_db(self):

            initialize_datamodels()
            with session_scope() as session:
                epd_ip_dataset = datamodels.relational_tables.EpdIpDataset
                qry = session.query(epd_ip_dataset).filter_by(dataset_state='healthy').order_by(
                    desc(epd_ip_dataset.dataset_id)).all()

                qry_last = session.query(epd_ip_dataset).filter_by(dataset_state='healthy').order_by(
                    desc(epd_ip_dataset.dataset_id)).first()

                url = url_for('.return_rollback_ui')
                url_for('rollback.return_rollback_ui')
                return self.render('airflow/base.html',
                                   qry=qry,
                                   dataset_id=qry_last.dataset_id,
                                   base_url=base_url,
                                   url=url)

        @expose('/roll', methods=['POST'])
        def return_rollback_ui(self):
            if request.method == 'POST':
                #body_req = request.json
                body_req = request.get_data()
                _log.error("Body of the request is ", body_req)
                #data = json.dumps(body_req)
                #self.initalize_db(body_req)
                return '<html> <h1> Hi I am sending a response</h1></html>'

        def initalize_db(self, body):
            dataset_id = body

            epdumppushrollback = datamodels.relational_tables.EpdUmpPushRollback

            with session_scope() as session:
                epdumppushrollback_obj = epdumppushrollback()
                epdumppushrollback_obj.dataset_id = dataset_id
                epdumppushrollback_obj.record_id = ''
                epdumppushrollback_obj.operator_name = ''
                epdumppushrollback_obj.activation_flag = 'active'
                epdumppushrollback_obj.record_creation_time = now()
                epdumppushrollback_obj.start_time = now()
                epdumppushrollback_obj.end_time = ''
                session.add(epdumppushrollback_obj)
                session.flush()


    class RollBackResume(BaseView):

        # @expose('/')
        # def index(self):
        #     return self.render('airflow/dags.html')

        def fetch_audited_dataset_from_db(self):
            initialize_datamodels()
            with session_scope() as session:
                epd_ip_dataset = datamodels.relational_tables.EpdIpDataset
                qry = session.query(epd_ip_dataset).filter_by(dataset_state='audited'). \
                    order_by(desc(epd_ip_dataset.dataset_id)).all()
                return qry

        @expose('/')
        def return_resume_ui(self):
            qry = self.fetch_audited_dataset_from_db()
            return self.render('airflow/rollback_resume.html',
                               qry=qry,
                               base_url=base_url)

        @expose('/rollbackresume', methods=['POST'])
        def return_rollback_ui(self):
            if request.method == 'POST':
                body_req = request.json
                data = json.dumps(body_req)

        def fetch_from_db(self):

            dataset_id = None
            initialize_datamodels()
            with session_scope() as session:
                epd_ump_push_rollback = datamodels.relational_tables.EpdUmpPushRollback
                qry = session.query(epd_ump_push_rollback).filter_by(activation_flag='active'). \
                    order_by(desc(epd_ump_push_rollback.dataset_id)).first()
                if qry:
                    dataset_id = qry.dataset_id
                return dataset_id

        def write_to_db(self):

            dataset_id = self.fetch_from_db()
            epd_ump_push_rollback = datamodels.relational_tables.EpdUmpPushRollback

            with session_scope() as session:
                qry = session.query(epd_ump_push_rollback)
                for rows in qry:
                    if rows.dataset_id == dataset_id:
                        rows.activation_flag = 'inactive'
                        rows.end_time = now()
                        session.commit()
                        session.flush()
                        break

HTML Page : 
<html>
<style>
p
{
    opacity: 0;
}

</style>
<head>
  <title>Roll back UI</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>

<nav class="navbar navbar-inverse">
  <div class="container-fluid">
    <div class="navbar-header">
      <a class="navbar-brand" href="{{base_url}}/admin/">Airflow</a>
    </div>
    <ul class="nav navbar-nav">
      <li class="active"><a href="{{base_url}}/admin/">DAGs</a></li>
      <li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#">Data Profiling <span class="caret"></span></a>
        <ul class="dropdown-menu">
          <li><a href="{{base_url}}/admin/queryview/">Ad Hoc query</a></li>
          <li><a href="{{base_url}}/admin/chart/">Charts</a></li>
          <li><a href="{{base_url}}/admin/knownevent/">Known Events</a></li>
        </ul>
      </li>
        <li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#">Browse <span class="caret"></span></a>
        <ul class="dropdown-menu">
          <li><a href="{{base_url}}/admin/slamiss/">SLA Instances</a></li>
          <li><a href="{{base_url}}/admin/taskinstance/">Task Instances</a></li>
          <li><a href="{{base_url}}/admin/log/">Logs</a></li>
            <li><a href="{{base_url}}/admin/basejob/">Jobs</a></li>
            <li><a href="{{base_url}}/admin/dagrun/">DAG Runs</a></li>

        </ul>
      </li>

        <li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#">Admin <span class="caret"></span></a>
        <ul class="dropdown-menu">
          <li><a href="{{base_url}}/admin/pool/">Pools</a></li>
          <li><a href="{{base_url}}/admin/configurationview/">Configuration</a></li>
          <li><a href="{{base_url}}/admin/user/">Users</a></li>
            <li><a href="{{base_url}}/admin/connection/">Connections</a></li>
          <li><a href="{{base_url}}/admin/variable/">Variables</a></li>
            <li><a href="{{base_url}}/admin/xcom/">XComs</a></li>
        </ul>
      </li>

        <li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#">Rollback <span class="caret"></span></a>
        <ul class="dropdown-menu">
          <li><a href="{{base_url}}/admin/rollback/">Rollback </a></li>
          <li><a href="{{base_url}}/admin/rollbackresume/">Resume</a></li>
        </ul>
      </li>

        <li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#">Docs <span class="caret"></span></a>
        <ul class="dropdown-menu">
          <li><a href="#">Documentation</a></li>
          <li><a href="#">Github</a></li>
        </ul>
      </li>

        <li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#">About <span class="caret"></span></a>
        <ul class="dropdown-menu">
          <li><a href="{{base_url}}/admin/versionview/">Version</a></li>
        </ul>
      </li>
    </ul>
  </div>
</nav>

<div class="container">
    <h3>RollBack UI</h3>
  <table class="table table-bordered">
    <thead class="thead-dark">
      <tr>
        <th scope="col">#</th>
        <th scope="col" >Dataset Id</th>
        <th scope="col">Dataset State</th>
      </tr>
    </thead>
    <tbody>
     {% for i in qry%}
            <tr>
                <th scope="row"> </th>
               <td> {{ i.dataset_id }} </td>
               <td> {{ i.dataset_state }} </td>
            </tr>
     {% endfor %}

    </tbody>
  </table>
  </div>
   <head>
<div class="container">
  <button type="button" class="btn btn-primary" onclick="loadDoc()" id="myBtn"> Rollback to {{dataset_id}} </button>
</div>
  <p id="dataset_id"> {{ dataset_id }}</p>

<script>
function loadDoc()
{
  document.getElementById("myBtn").disabled = true;
  var xhttp = new XMLHttpRequest();
  var dataset_id = document.getElementById("dataset_id");

  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("demo").innerHTML = this.responseText;
    }
  };
  xhttp.open("POST", "http://localhost:8085/admin/rollback/roll/", true);
  xhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  xhttp.send("foo=bar&lorem=ipsum");
}
</script>
   </head>
<body>

<h2> Url of the index is {{ url }} </h2>

</body>>
</html>

Explanation of code :

I have class RollBack which returns a table after querying the database, there is a button present on that page; when I click on that button, I want to post some data to an endpoint which I am doing using XMLHttpRequest in the html page.

When I click on that button, the post data is directing me to @expose('/') method instead of @expose('/roll'), since @expose('/') method doesn't support post method it is throwing 405 error. I want my onclick action of button to redirect to @expose('/roll') method.


Solution

  • The reason that your code is throwing a 405 is because you haven't configured your expose function to handle POST methods. The default is to handle only GET as explained in the docs.

    Your code logic should look something like the following:

    from flask import request

    class RollBack(BaseView):
    
        @expose('/',  methods=('GET', 'POST'))
        def fetch_healthy_dataset_from_db(self):
    
            if request.method == 'POST':
                #  Anything within this block is processing a POST method
    
                 # make sure you eventually return a view
                return "Success"
    
            #  Anything after this point is processing a GET method