Question

This is my first time posting to Stack Overflow. I'm trying to build a relatively simple game using Python, Jinja2 and Google App Engine. At the moment, I've just built some simple CRUD functions for creating, editing, listing, and destroying games. And, for the most part, it seems to work. But, it seems that my CSS stylesheet is not being applied whenever I pass a value to retrieve a specific game. It does, however, seem to work just fine whenever I don't pass any values. For example, if I call functions like "create_game" or "all_games", which don't take any parameters, their respective templates are rendered correctly with the relevant CSS styles. But, if I call a function like "edit_game/12345567", the CSS stylesheet is not applied at all, even though the html tags and the python-generated content does appear to work.

I'm not really sure where the problem resides. Could this have something to do with the way templates are rendered? Or is it some sort of routing/mapping issue?

Here is my main.py:

    import webapp2
    from controllers.authController import *
    from controllers.baseController import *
    from controllers.gameController import *

    app = webapp2.WSGIApplication([('/', MainPage),                     
            ('/create_game',CreateGame),
            ('/player_games/([\d]+)',PlayerGames),
            ('/all_games',AllGames),
            ('/edit_game/([\d]+)',EditGame),
            ('/delete_game/([\d]+)',DeleteGame),
                    ],
                    debug=True)

and my baseController.py:

from controllers.authController import LoginSession
import webapp2
import cgi
import datetime
import urllib
import jinja2
import os
import wsgiref.handlers
from google.appengine.api import users

TEMPLATE_DIR = os.path.join(os.path.dirname(__file__), '../views/templates')
jinja_environment = \
        jinja2.Environment(loader=jinja2.FileSystemLoader(TEMPLATE_DIR))

class BaseHandler(LoginSession):
    @webapp2.cached_property
    def jinja2(self):
        return jinja2.get_jinja2(app=self.app)

    def render_template(
            self,
            filename,
            temp_values,
            **template_args):
            template = jinja_environment.get_template(filename)
            self.response.out.write(template.render(temp_values))

    def authvals(self): 
            current_player = LoginSession.current_player(self)
            url = LoginSession.url(self)
            url_linktext = LoginSession.linktext(self)
            auth_vals = {
                    'url': url,
                    'url_linktext': url_linktext,
                    'c_player': current_player,
            }
            return auth_vals

class MainPage(BaseHandler):    

    def get(self):
            gurl = self.request.get('/create_game')
            gurl_linktext = 'Create a New Game!'
            mp_vals = {
                    'game_url': gurl,
                    'game_url_linktext': gurl_linktext,
            }
            authvals = self.authvals()
            vals = dict(mp_vals.items() + authvals.items())
            self.render_template('index.html', vals)

Below are two classes from gameController.py. While "AllGames" seems to render everything correctly, including the correct CSS styling, "PlayerGames" seems to render the correct python-generated content and html, but doesn't seem to make use of any CSS. I would expect the CSS to just be inherited along with "base.html", since that is where the CSS styles are being applied. But, somehow this isn't happening.

from models.gameModel import *
from authController import *
from baseController import * 
import baseController
from google.appengine.ext import db
from google.appengine.ext.db import Key

class AllGames(BaseHandler):

    #this returns all games 
    def get(self):
        games = GameModel.all()
        ag_vals = {
            'games': games
        }
        authvals = self.authvals()
        vals = dict(ag_vals.items() + authvals.items())

        self.render_template('all_games.html',vals)

class PlayerGames(BaseHandler):

    #This returns a given player's games
    def get(self,player_id):
        player = users.User(_user_id = 'player_id')

        g = GameModel.all()
        games = g.filter('game_created_by =', player)         
        pg_vals = {
        'games': games
        }
        authvals = self.authvals()
        vals = dict(pg_vals.items() + authvals.items())

        self.render_template('player_games.html',vals)  

Here is base.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<html xmlns="http://www.w3.org/1999/xhtml">

<html>
<head>
{% block head %}
    <link type="text/css" rel="stylesheet" href="views/static/css/main.css" />
    <link type="text/css" rel="stylesheet" href="views/static/css/reset.css" />
    <title>O2O: {% block title %}{% endblock %}</title>
{% endblock %}
</head>
<body>
<div class="login">
    {% block login %}
        <table>
            <tr>
                {% if c_player %}
                    <td>You are logged in as: {{ c_player }} </td>
                {% else %}
                    <td>You are not logged in.</td>
                {% endif %}

                <td><a href="{{ url }}">{{ url_linktext }}</a></td> 
            </tr>
        </table>
    {% endblock login %}
</div>
<div class="navbar">
    {% block navbar %}
    <table>
        <col class="navbar" />
        <colgroup class="controls"> 
            <col /> <col /> <col /> <col />
        </colgroup> 
        <tr>
            <th>
                <form action="/create_game" method="post"> 
                    <div><input type="submit" value = "Create a new Game!"></div>
                </form>
            </th>
            <th>
                <form action="/player_games/{{ c_player.user_id() }}" method="get">
                    <!--div><input type="hidden" value = {{ c_player.user_id() }} ></div-->
                    <div><input type="submit" value = "My Games" ></div>
                </form>
            </th>
            <!--th>
                <a href ="player_games/{{ c_player.user_id() }}">My Games</a>
            </th-->
            <th>
                <form action="/all_games" method="get">
                    <div><input type="submit" value = "All Games" ></div>
                </form>
            </th>

            <th>
                Stats?
            </th>
            <th>
                Current Games?
            </th>
        </tr>   
    </table>
    {% endblock navbar %}
</div>
<div class="content">{% block content %}{% endblock %}</div>
<div class="footer">
    {% block footer %}
    &copy; Copyright 2012</a>.
    {% endblock %}
</div>
</body>
</html>

Here is all_games.html, which does appear to be rendered correctly:

{% extends "base.html" %}
{% block title %} All Games {% endblock %}
{% block content %}     
    <h2>All Games</h2>

    <h4>These are all of the games:</h4>
        <table>
            <tr>
                <th>Time Created:                   </th>
                <th> ----------                     </th>
                <th>Game ID:                        </th>
                <th>Creator:                        </th>
                <th>Edit?                           </th>
                <th>Edit via button?                </th>
                <th>Delete?                         </th>
            </tr>       
            {% for game in games %}
            <tr>                
                <td> {{ game.game_created_at }}     </td>
                <td> ----------                     </td>   
                <td> {{ game.key().id() }}          </td>
                <td> {{ game.game_created_by }}     </td>
                <td>
                    <a href ="edit_game/{{ game.key().id() }}"> edit </a>
                </td>
                <td>    
                <!--button to view the game --> 
                    <form action="/edit_game/{{ game.key().id() }}" method="get">
                        <!--div><input type="hidden" name ="game_id" value={{ game.key().id() }}></div-->
                        <div><input type="submit" value = "Edit Game!" ></div>
                    </form> 
                </td>
                <td>        
                <!-- button to destroy the game -->
                    <form action="/delete_game/{{ game.key().id() }}" method="get">
                        <!--div><input type="hidden" name ="this_game" value={{ game.key().id() }}></div-->
                        <div><input type="submit" value = "Delete This Game?" ></div>
                    </form>
                </td>                           
            </p>
            </tr>                               
        {% endfor %}
        </table>        
{% endblock %}

and here is player_games.html, which is almost identical to all_games.html. However, this appears to be rendered without CSS, although the html and contents are apparently being displayed properly:

{% extends "base.html" %}
{% block title %} PLayer's Games {% endblock %}
{% block content %}
    <h2>{{ c_player }}'s Games</h2>

    <h4>These are all of the games:</h4>
    <div id="gamelist">
        <table>
            <tr>
                <th>Time Created:                   </th>
                <th> ----------                     </th>
                <th>Game ID:                        </th>
                <th>Creator:                        </th>
                <th>Edit?</th>
                <th>Delete?</th>
            </tr>       
            {% for game in games %}
            <tr>                
                <td> {{ game.game_created_at }}     </td>
                <td> ----------                     </td>   
                <td> {{ game.key().id() }}  </td>
                <td> {{ game.game_created_by }}     </td>
                <td>    
                <!--button to edit the game --> 
                    <form action="/edit_game/{{ game.key().id() }}" method="get">
                        <!--div><input type="hidden" name ="game_id" value={{ game.key().id() }}></div-->
                        <div><input type="submit" value = "Edit Game!" ></div>
                    </form> 
                </td>
                <td>        
                <!-- button to destroy the game -->
                    <form action="/delete_game/{{ game.key().id() }}" method="get">

                        <div><input type="submit" value = "Delete This Game?" ></div>
                    </form>
                </td>                           
            </p>
            </tr>                               
        {% endfor %}
        </table>
    </div>
{% endblock %}

Here is the main.css, which probably is not the issue, since it is being correctly rendered on some of the pages:

.login {
    background-color: black;
    color: #DDDDDD;
}

.navbar {
    background-color: black;
    color: #DDDDDD;
}

.content {
    background-color: white;
}

.footer {
    background-color: #DDDDDD;
}

Although I doubt this is really relevant to the problem, here is also authController.py:

import webapp2
import main
from google.appengine.api import users

class LoginSession(webapp2.RequestHandler):
    def current_player(arg):
        return users.get_current_user() 

    def linktext(arg):
        if users.get_current_user():
            return 'logout'
        else:
            return 'Login'

    def url(arg):
        if users.get_current_user():
            return users.create_logout_url(arg.request.uri)
        else:
            return users.create_login_url(arg.request.url)

I've based some of my code on this simple note-taking app example: https://github.com/fRuiApps/cpfthw/tree/master/webapp2 because I found it to be have a nice, clear MVC structure. Obviously my code is quite a bit more extensive, but some of the code for how the templates should be rendered is more or less based on the example. However, the example does not suffer from the disappearing CSS style problem that I seem to be having. I.e. when I pass requests to edit a specific note, the example appears to render the CSS correctly.

I've been trying to solve this problem for a couple of hours now and despite all of my efforts I seem to be getting nowhere. Since I'm usually able to find really helpful information on StackOverflow, I figured this would probably be the best place to post the issue. Any help would be greatly appreciated! Thanks!

Was it helpful?

Solution

You're loading the CSS with a relative path. When the HTML is a 'top level' page (/create_game), then the CSS-path is relative to the root and all is good. When you're down one level (/edit_game/1234), the CSS is trying to load from /edit_game/views. Change the link hrefs in your HTML to begin /views and it might work. (If you check the dev tools in your browser of choice, you should see 404s for the CSS, and you'll be able to see where the browser is trying to load them from.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top