Search code examples
pythonurl-rewritingpyramid

How to mimic the url aliasing functionality of mod_rewrite with Pyramid (Python Framework)?


I'm working on converting an existing Drupal site to Pyramid. The Drupal site has urls that are SEO friendly example: "testsite.com/this-is-a-page-about-programming". In Drupal they have a system which maps that alias to a path like "testsite.com/node/33" without redirecting the user to that path. So the user sees "testsite.com/this-is-a-page-about-programming" but Drupal loads node/33 internally. Also if the user lands on "testsite.com/node/33" they would be redirected to "testsite.com/this-is-a-page-about-programming".

How can this be achieved in Pyramid without a major performance hit?


Solution

  • You don't really need all this stuff with Pyramid - it can handle nice urls natively.

    Basically, your "page" model would have a slug field which would store the SEO-friendly URL fragment:

    class Page(Base):
        id = sa.Column(sa.Integer, primary_key=True)
        slug = sa.Column(sa.String, index=True, unique=True)
        title = sa.Column(sa.String)
        body = sa.Column(sa.String)
    

    Then you would have a route which directly maps /:slug url's to a view which would find a page by its slug and render it.

    For backward compatibility purposes you may also have a view mapped to /node/:id, which would simply redirect to the /:slug view, but that's only needed if you want to preserve the old redirects.

    Here's another variation of your Page model:

    class Page(Base):
        slug = sa.Column(sa.String, primary_key=True)
        title = sa.Column(sa.String)
        body = sa.Column(sa.String)
        historical_node_id = sa.Column(sa.Integer, index=True, unique=True)
    

    UPDATE: Regarding "Is there something like a server level redirect for wsgi servers that could be coded into a file rather than having to make a database query and then redirecting?" - this is the very definition of premature optimization :)

    The cost of a browser making a request, receiving a redirect and making another request is often in the order of hundreds of milliseconds, especially if the server is on another continent - purely because of speed of light. Full page loading usually in the order of seconds. The cost of fetching a single row from a database running on the same machine is usually less than a millisecond - hundreds of times faster than the redirect itself.

    But, if you insist, there definitely are ways to do that:

    1. Hard-code the values in some dict:

      HISTORICAL_URLS_MAPPING = {
          '33': '/this-is-a-page-about-programming',
          '34': '/this-is-a-page-about-premature-optimization'
      }
      
      def historical_node_id_view(node_id):
          return HTTPFound(HISTORICAL_URLS_MAPPING[node_id])
      
    2. Normally a Pyramid app is served behind an "industrial" web server, such as Nginx or Apache. You can drop a bunch of configuration lines into the webserver config.