Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Senso
Nov 4, 2005

Always working
Django 1.0 just came out, should it really be upgraded on a "production" website?

Adbot
ADBOT LOVES YOU

No Safe Word
Feb 26, 2005

Not immediately but you should begin to migrate at some point.

And here's the link to the porting guide: http://docs.djangoproject.com/en/dev/releases/1.0-porting-guide

MononcQc
May 29, 2007

In Django 1.0 here.

What would be the best way to manage this view:

I have this model for a blog entry (I'm only leaving the relevant fields in):
code:
class Entry(models.Model):
    #whatever stuff, this is the content I want
    pub_date = models.DateTimeField()
    published = models.BooleanField()

class Category(models.Model):
    slug = models.SlugField()

class EntryCategory(models.Model):
    entry    = models.ForeignKey(Entry)
    category = models.ForeignKey(Category)
I want to find all entries having the category related to the Category.slug field.
So I would like to be able to do the equivalent of this SQL query (not tested, but should cover it all):
code:
SELECT `entry`.* 
FROM `entry` 
LEFT JOIN `EntryCategory` ON(`entry`.`id` = `EntryCategory`.`entry`)
LEFT JOIN `Category` ON (`EntryCategory`.`category` = `Category.`id`)
WHERE `category`.`slug` = 'variable_here'
AND `entry`.`published` = True
AND `entry`.`pub_date` <= now
ORDER BY `entry`.`pub_date` DESC
The direction of the join has no importance, and the filtering, I could do myself I guess. What I have the most trouble with is getting to emulate the join (or just comparing primary and foreign keys).

It seems there is not really possible way and I should use models.ManyToManyField(), but I'm not quite sure about it.

king_kilr
May 25, 2007
Why are you creating the join table yourself instead of just using a ManyToManyField?

EDIT: If the reason you are doing it is to add extra fields to the join table look at the through kwarg on M2M Fields.

bitprophet
Jul 22, 2004
Taco Defender
What king_kilr said: if you have other fields you're not showing us on EntryCategory, then you want to have a ManyToManyField on Entry or Category, pointing at the other one, and with through=EntryCategory or similar.

If all you have with EntryCategory is just those two foreign keys, then ditch that and just use a normal ManyToManyField (without the through argument).

Then, if you had the M2M on Entry, like categories=ManyToManyField(Category), you'd do something like this:
code:
entries = Entry.objects.filter(categories__slug="foo")
Might be slightly off base (it might be category__slug) but that's the general idea.

MononcQc
May 29, 2007

Thanks, will look into the many to many field then.

I don't know why I didn't use it, probably lack of research on my part. So used to making all the queries and tables myself and whatnot.

Idimmu
Feb 22, 2003

not sure if this is the right place to ask, ive got this model but ..

code:
from django.db import models

class Tag(models.Model):
        slug = models.SlugField(
                'Slug',
                prepopulate_from("title",),
                help_text='Automatically built from the title.',
                primary_key='True'
        )
        title = models.CharField('Title', maxlength=30)
I get this error

code:
idimmu@server:~/www/blog$ python manage.py sql b
blog.b: name 'prepopulate_from' is not defined
1 error found.
Traceback (most recent call last):
  File "manage.py", line 11, in <module>
    execute_manager(settings)
  File "/var/lib/python-support/python2.5/django/core/management.py", line 1672, in execute_manager
    execute_from_command_line(action_mapping, argv)
  File "/var/lib/python-support/python2.5/django/core/management.py", line 1620, in execute_from_command_line
    mod_list = [models.get_app(app_label) for app_label in args[1:]]
  File "/var/lib/python-support/python2.5/django/db/models/loading.py", line 40, in get_app
    mod = load_app(app_name)
  File "/var/lib/python-support/python2.5/django/db/models/loading.py", line 51, in load_app
    mod = __import__(app_name, {}, {}, ['models'])
  File "/home/idimmu/www/blog/../blog/b/models.py", line 3, in <module>
    class Tag(models.Model):
  File "/home/idimmu/www/blog/../blog/b/models.py", line 6, in Tag
    prepopulate_from("title",),
NameError: name 'prepopulate_from' is not defined
On Ubuntu Hardy with Django 0.96.1-2 (yes i know i should upgrade to 1.0, its going to hit backports within the week as its in intrepid!)

bitprophet
Jul 22, 2004
Taco Defender
code:
                prepopulate_from("title",),
Please explain what this line is doing, and why it differs from the others around it, and hopefully that will clue you in on what's wrong :)

bitprophet fucked around with this message at 23:53 on Sep 5, 2008

The Real Ambassador
Apr 9, 2005

I'll explain and make it plain, I represent the human race.

bitprophet posted:

code:
                prepopulate_from("title",),
Please explain what this line is doing, and why it differs from the others around it, and hopefully that will clue you in on what's wrong :)

That's a magical feature from 0.96 that will automatically fill in your field based on what is entered into the title field. I believe they took that out of 1.0 so please steer away from it.

bitprophet
Jul 22, 2004
Taco Defender

The Real Ambassador posted:

That's a magical feature from 0.96 that will automatically fill in your field based on what is entered into the title field. I believe they took that out of 1.0 so please steer away from it.

This is true, but not what I was getting at, he has a pretty silly syntax error :)

The Real Ambassador
Apr 9, 2005

I'll explain and make it plain, I represent the human race.

bitprophet posted:

This is true, but not what I was getting at, he has a pretty silly syntax error :)

Forgive me, I didn't know your code had a gender.

Sivart13
May 18, 2003
I have neglected to come up with a clever title

The Real Ambassador posted:

That's a magical feature from 0.96 that will automatically fill in your field based on what is entered into the title field. I believe they took that out of 1.0 so please steer away from it.
It's still around in the admin as
code:
class SomethingAdmin(admin.ModelAdmin):
    prepopulated_fields = {'slug':[b][/b]('title',)}

Idimmu
Feb 22, 2003

bitprophet posted:

code:
                prepopulate_from("title",),
Please explain what this line is doing, and why it differs from the others around it, and hopefully that will clue you in on what's wrong :)

as new as i am to python the error suggests that the prepopulate_from function is undefined, the only 'interesting' thing I can see is the , after title because prepopulate_from takes a tuple/list?

should i be doing something more like:

something = prepopulate_from ..?

im happy to lose it anyway now seeing as its deprecated!

bitprophet
Jul 22, 2004
Taco Defender

Idimmu posted:

as new as i am to python the error suggests that the prepopulate_from function is undefined, the only 'interesting' thing I can see is the , after title because prepopulate_from takes a tuple/list?

should i be doing something more like:

something = prepopulate_from ..?

im happy to lose it anyway now seeing as its deprecated!

Close, but not quite! Let's look at the code again:
code:
class Tag(models.Model):
    slug = models.SlugField(
        'Slug',
        prepopulate_from("title",),
        help_text='Automatically built from the title.',
        primary_key='True'
    )
    title = models.CharField('Title', maxlength=30)
Notice that most of the other arguments to your Field subclasses (SlugField and CharField) are of the form x=y (i.e. primary_key='True', maxlength=30, etc)? You're missing that for prepopulate_from. It should read prepopulate_from=("title",).

In other words, because you're lacking the equals sign before the tuple, and because tuples happen to be defined with parentheses, you've inadvertently created a function call, hence the error. You want to be saying "the prepopulate_from argument should be given this tuple as its value", which is why you need an equals sign.

vvv Good catch, that one went right over me :downs:

bitprophet fucked around with this message at 21:12 on Sep 6, 2008

king_kilr
May 25, 2007
Also, it should br primary_key = True; not 'True', one is a string, the other is a bool.

Janitor Prime
Jan 22, 2004

PC LOAD LETTER

What da fuck does that mean

Fun Shoe
Hey guys I'm about to start a new project for Facebook and I want to use Django. I'm new to Python as well so that's not a big help, but I've gotten past the first 6 chapters of Learning Python and will be moving to the Django book once I'm done with that.

My question has more to do with the hosting of this project. I'm expecting it to generate a lot of traffic and wanted to know if those shared hosting plans would be enough. At what point will 64 MB not be enough to serve all my users? I don't have a lot of money right now, so I wanted to see how long that shared hosting would last me.

Thanks!

Janitor Prime fucked around with this message at 18:21 on Sep 7, 2008

FrontLine
Sep 17, 2003
I gave Mr. Adequate hot, steamy man love and all he bought me was a custom title!
Can anybody help me out with creating an Object outside of the Django Admin console and the Python shell. I'd like to be able to run a script like this:

'createobject.py'
code:
from News.models import ChoiceArticle as CA
NewCA = CA()
NewCA.Title = "News Story title"
NewCA.URL = "http://www.genericnewssite.com"
NCA.Summary = "A summary of what the story is about"
NCA.save()
But, as possibly expected, I keep getting an ImportError:

code:
ImportError: Settings cannot be imported, because environment variable DJANGO_SETTINGS_MODULE is undefined.
Any idea how to get around this?

The Real Ambassador
Apr 9, 2005

I'll explain and make it plain, I represent the human race.

FrontLine posted:

Can anybody help me out with creating an Object outside of the Django Admin console and the Python shell. I'd like to be able to run a script like this:

'createobject.py'
code:
from News.models import ChoiceArticle as CA
NewCA = CA()
NewCA.Title = "News Story title"
NewCA.URL = "http://www.genericnewssite.com"
NCA.Summary = "A summary of what the story is about"
NCA.save()
But, as possibly expected, I keep getting an ImportError:

code:
ImportError: Settings cannot be imported, because environment variable DJANGO_SETTINGS_MODULE is undefined.
Any idea how to get around this?

Put this in your codes at the top:

import sys
import os
sys.path.append('..')
os.environ['DJANGO_SETTINGS_MODULE'] = 'myproject.settings'

MEAT TREAT posted:

My question has more to do with the hosting of this project. I'm expecting it to generate a lot of traffic and wanted to know if those shared hosting plans would be enough. At what point will 64 MB not be enough to serve all my users? I don't have a lot of money right now, so I wanted to see how long that shared hosting would last me.

Why not just use shared hosting until it becomes apparent that it is no longer enough? Shared hosting can host more than you'd think. By the time your website becomes so popular that you need a dedicated server, chances are you'll be making enough off ads to cover a good portion of the cost.

To put off the need for a dedicated server, you can even be clever and get several shared hosting accounts with different companies. For example, one could host your static content, the other could be for your Django code. That might help reduce the possibility of your hosting company murdering you for using too much of their "unlimited" resources. It happens, but not as much as it used to. Back in 2000, I had a popular little webpage that got a bunch of visitors. The next thing I knew my credit card was getting hit with $300 charges for excessive bandwidth usage on my Unlimited* account. I guess the moral of the story is to be wary of any host that offers "unlimited*" resources.

The Real Ambassador fucked around with this message at 09:07 on Sep 8, 2008

FrontLine
Sep 17, 2003
I gave Mr. Adequate hot, steamy man love and all he bought me was a custom title!

The Real Ambassador posted:

Put this in your codes at the top:

import sys
import os
sys.path.append('..')
os.environ['DJANGO_SETTINGS_MODULE'] = 'myproject.settings'

I haven't tested this yet but I'll trust that it works... although to be honest it looks weird. In any case if no one posts a better solution I'll run with it.

Git
Aug 21, 2004

FrontLine posted:

I haven't tested this yet but I'll trust that it works... although to be honest it looks weird. In any case if no one posts a better solution I'll run with it.

Another solution is to just set the DJANGO_SETTINGS_MODULE environment variable outside of your script before running it.

Alternatively, you can set it temporarily just for your script by executing your program from the command line with the command
code:
DJANGO_SETTINGS_MODULE=myproject.settings python createobject.py

Senso
Nov 4, 2005

Always working

MEAT TREAT posted:

My question has more to do with the hosting of this project. I'm expecting it to generate a lot of traffic and wanted to know if those shared hosting plans would be enough. At what point will 64 MB not be enough to serve all my users? I don't have a lot of money right now, so I wanted to see how long that shared hosting would last me.

I can't provide hard data but I host a wiki for a popular game and I get about ~50,000 pageviews per day. I go through about 80GB/month. The whole deal (the hosting is a goon company so I think I had a small deal) costs me nearly $20/month.

bitprophet
Jul 22, 2004
Taco Defender

FrontLine posted:

I haven't tested this yet but I'll trust that it works... although to be honest it looks weird. In any case if no one posts a better solution I'll run with it.

Git posted the other, slightly shorter method -- the overall point is that the shell environment your Python code executes in, must have DJANGO_SETTINGS_MODULE='myproject.settings' (with appropriate value for myproject of course) defined somewhere, somehow. There's no other way for Django to know which settings file to use.

Additionally, myproject needs to be in your Python path in order for it to resolve when imported by Django. Some people symlink their project into Python's existing site-packages directory; others, like The Real Ambassador, tweak the path at runtime.

TRA's example does the sys.path.append('..') which will work if your script is at the same level as your Django project folder; if that is not the case, you'll need to use an absolute path, i.e. sys.path.append('/home/username/django/') if your project folder is /home/username/django/myproject.


Finally, a silly nitpick, you should never name Python modules (folders) with capital letters, as you seem to have done with your 'News' app, it's bad form. The convention is to use lowercase for just about everything except class names, which get CamelCased.

NadaTooma
Aug 24, 2004

The good thing is that everyone around you has more critical failures in combat, the bad thing is - so do you!
I'm about to start a new project, and trying to decide if I should use the built-in authentication system vs. rolling my own. I want two different account types: One for adults (requiring e-mail validation), and one for kids (no e-mail required), where each child's account is tied to one or more parent accounts, so that a parent can change manage their son or daughter's setup. This would imply a many-to-many relationship in the original Django "User" table, and I'm not sure it's designed for that. If I roll my own, I'm actually considering making it two tables (one for each account type), just to keep the DB design simpler. The built-in administrative pages, while awesome, aren't an issue here, because I'll be the only person using them in this case.

Any thoughts? Roll my own, or start hacking the hell out of the built-in authentication system?

VVVVV Great idea! Thanks. :)

NadaTooma fucked around with this message at 18:31 on Sep 8, 2008

deimos
Nov 30, 2006

Forget it man this bat is whack, it's got poobrain!

NadaTooma posted:

I'm about to start a new project, and trying to decide if I should use the built-in authentication system vs. rolling my own. I want two different account types: One for adults (requiring e-mail validation), and one for kids (no e-mail required), where each child's account is tied to one or more parent accounts, so that a parent can change manage their son or daughter's setup. This would imply a many-to-many relationship in the original Django "User" table, and I'm not sure it's designed for that. If I roll my own, I'm actually considering making it two tables (one for each account type), just to keep the DB design simpler. The built-in administrative pages, while awesome, aren't an issue here, because I'll be the only person using them in this case.

Any thoughts? Roll my own, or start hacking the hell out of the built-in authentication system?

You could inherit User into an AdultUser and ChildUser model and use them that way.

Idimmu
Feb 22, 2003

bitprophet posted:

Close, but not quite! Let's look at the code again:
code:
class Tag(models.Model):
    slug = models.SlugField(
        'Slug',
        prepopulate_from("title",),
        help_text='Automatically built from the title.',
        primary_key='True'
    )
    title = models.CharField('Title', maxlength=30)
Notice that most of the other arguments to your Field subclasses (SlugField and CharField) are of the form x=y (i.e. primary_key='True', maxlength=30, etc)? You're missing that for prepopulate_from. It should read prepopulate_from=("title",).

In other words, because you're lacking the equals sign before the tuple, and because tuples happen to be defined with parentheses, you've inadvertently created a function call, hence the error. You want to be saying "the prepopulate_from argument should be given this tuple as its value", which is why you need an equals sign.

vvv Good catch, that one went right over me :downs:

ah awesome cheers, that makes a lot more sense now!

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Can anyone spot what I'm doing wrong here?

I'm trying to get my local debugging server to load the static content.
code:
from django.views.static import serve
from django.conf import settings

urlpatterns = patterns('',
	# Media:
	(r'^media/', mediaIndex),

	#crap snipped out
)

if settings.DEBUG == True:
	urlpatterns += patterns('',(r'^static/(?P<path>.*)$', serve, {'document_root': settings.STATIC_ROOT}),)
	
urlpatterns += patterns(
	# Index:
	'',(r'^', mainIndex),
)
Edit 2: I guess whatever gets passed to patterns() first gets silently ignored, so that answers part of my question.

Edit: I went back to my 'working' version of the URLs file and it no longer loads static content. I edited the post to reflect that.

Munkeymon fucked around with this message at 21:13 on Sep 9, 2008

bitprophet
Jul 22, 2004
Taco Defender
I don't see anything functionally wrong (though I've never used staticserve, always just go straight to using Apache) but your code could use a lot of cleanup, allow me to nitpick :)

code:
urlpatterns = patterns('',
	# Media:
	(r'^media/', mediaIndex),

	#crap snipped out
)
You seem to be using 8-space indents -- the Python standard is 4 spaces. Plus that makes it much easier not to have super duper long lines when you're a few indent levels in. I definitely suggest setting your editor to 4-space indents.

code:
if settings.DEBUG == True:
No need to do this: just do if settings.DEBUG: :)

code:
	urlpatterns += patterns('',(r'^static/(?P<path>.*)$', serve, {'document_root': settings.STATIC_ROOT}),)
This is my main complaint, this big ol' one-liner makes it really hard to see what your code is doing (especially if it's in a narrow container like a quote tag). Try formatting it more like the others, like so:

code:
urlpatterns += patterns('',
    (r'^static/(?P<path>.*)$', serve, {
        'document_root': settings.STATIC_ROOT
    }),
)
I just double checked the docs and your URL line's contents still look OK, although I'm curious what settings.STATIC_ROOT is set to. You're not getting any errors in the output of the runserver or anything? Have you double checked permissions (just in case settings.STATIC_ROOT doesn't have correct read/execute permissions for the user running runserver)?

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



bitprophet posted:

You seem to be using 8-space indents -- the Python standard is 4 spaces. Plus that makes it much easier not to have super duper long lines when you're a few indent levels in. I definitely suggest setting your editor to 4-space indents.

My editor uses tabs, which is what those are. I'm not going to use spaces. I don't relly mind if the debugging stuff looks bad since it'll be changed 100 times before the project goes live anyway.

quote:

I just double checked the docs and your URL line's contents still look OK, although I'm curious what settings.STATIC_ROOT is set to. You're not getting any errors in the output of the runserver or anything? Have you double checked permissions (just in case settings.STATIC_ROOT doesn't have correct read/execute permissions for the user running runserver)?

Wouldn't a permissions problem make it throw an error somewhere?

Anyway, I changed the ADMIN_MEDIA_PREFIX to /media/ (in settings) and it works now. Too much magic going on for me to keep track I guess.

MononcQc
May 29, 2007

Working on limiting results in my views.

So I know Something.objects.all()[:5] would give me an SQL limit of 0,5.
However, I'm using get-list_or_404, which I guess will fail:
code:
entries = get_list_or_404(
    Entry.objects.order_by('-pub_date'),
    published=True,
    pub_date__lte=datetime.now(),
)[:10]
It sounds like what I'll be getting is a slice off an unlimited query result, or a terrible resource hog for small results.

The other thing I tried was
code:
entries = get_list_or_404(
    Entry.objects.order_by('-pub_date')[:10],
    published=True,
    pub_date__lte=datetime.now(),
)
which makes the whole thing fail: Cannot filter a query once a slice has been taken.
Logical.

Is there any way I can achieve that or I'll have to do it the long way without shortcuts? Maybe there's something I missed from the doc again.

MononcQc fucked around with this message at 05:31 on Sep 10, 2008

No Safe Word
Feb 26, 2005

MononcQc posted:

Is there any way I can achieve that or I'll have to do it the long way without shortcuts? Maybe there's something I missed from the doc again.
The long way isn't really that long, since get_list_or_404 literally just does this:

code:
queryset = _get_queryset(klass)
obj_list = list(queryset.filter(*args, **kwargs))
if not obj_list:
    raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
return obj_list
And all _get_queryset does is allow the passed in klass arg to be either an actual Queryset or a Manager.

Senso
Nov 4, 2005

Always working
I have a weird problem.
:words:

EDIT: I found my mistake, sorry.

Senso fucked around with this message at 21:38 on Sep 11, 2008

m0nk3yz
Mar 13, 2002

Behold the power of cheese!
I wish you for to help me make better django!

I just released the most rudimentary prototype of the test-engineering application I've been farting around with, and I am looking to get everything from django, to basic layout/design feedback. This web thing is hard.

http://code.google.com/p/testbutler/

I'm currently refactoring the templates to use extends and cleaning up the hanging mess I left in a few areas.

bitprophet
Jul 22, 2004
Taco Defender

m0nk3yz posted:

I wish you for to help me make better django!

I keep forgetting you're Jesse Noller, and so I'll see your blog post in my feed (assuming it's the Django community feed, either that or Planet Python) and then run across a post here a few hours later and do a double-take :)

Looks like a neat app (from reading the main google code page -- it's not really something in the vein of CruiseControl, is it? because it's designed to track manual testing as well as automatic) and it sounds like you're definitely trying to do things The Right Way, which is always great!

I can indirectly recommend James' book, especially after reading his DjangoCon slides, which rocked. Plus I know him from #django and he's a smart cookie.

I'd also recommend my book but it's not quite out yet v:shobon:v and we don't go into the philosophy as heavily as James probably does (ours being more of a well-rounded book instead of focusing solely on app design).

m0nk3yz
Mar 13, 2002

Behold the power of cheese!

bitprophet posted:

I keep forgetting you're Jesse Noller, and so I'll see your blog post in my feed (assuming it's the Django community feed, either that or Planet Python) and then run across a post here a few hours later and do a double-take :)

Looks like a neat app (from reading the main google code page -- it's not really something in the vein of CruiseControl, is it? because it's designed to track manual testing as well as automatic) and it sounds like you're definitely trying to do things The Right Way, which is always great!

I can indirectly recommend James' book, especially after reading his DjangoCon slides, which rocked. Plus I know him from #django and he's a smart cookie.

I'd also recommend my book but it's not quite out yet v:shobon:v and we don't go into the philosophy as heavily as James probably does (ours being more of a well-rounded book instead of focusing solely on app design).

It's the Python Planet feed - my Django Fu is so weak, I don't think I could be there :)

Yes - this is not a Cruise Control application in some sense - think of it as a inventory/tracking system for Test Engineering collateral. Test Cases, Test Plans - things like "run" creation for tests targeted at releases and sprints/etc.

When your book is out, I'll definitely pick it up. The hardest part for me from an application standpoint isn't the back end - hell, I was able to retrofit some links into the 2.6 multiprocessing module just as a lark super-easy. The problem for me is in the templates - the actual user-interface design of things. I get trapped in a fortress of stupid with all of the XHTML/CSS/JavaScript/etc stuff and can't seem to find my way out.

Django makes the back end stupidly easy.

Mashi
Aug 15, 2005

Just wanted you to know your dinner's cold and the children all agree you're a shitheel!
I've been spending some time trying to write a simple application in Django, and doing it "the right way". It's been slow going as I familiarise myself with the Django framework and the myriad of features it has to aid you with things, and I've been suitably impressed. One thing I LOVE is how Django solves a problem that I'd wrestled with in PHP: a modular/component based template system. Template inheritance is awesome.

My Question:

So I'm creating a little Django project, just playing around, and I have an "app" which is going to do a certain thing and I want it to use a template that extends of an outer or "base" template. So within the views for my app I can create templates and return HttpResponses and all that, but there is view logic that needs to be run for the base template that is outside the scope of the app view. Specifically the problem I have is that above the application, the site should have a menu with links, which should be bold or not bold depending on the current URL. I don't know where create and specify this menu without coupling the location of an application to some view logic outside of the application, and I don't know where the usual place is to do view logic for the base template when the request is for /myapp/dosomething.html.

Well I think I'll be pretty impressed if someone is actually able to parse and understand what I've just written! TIA.

bitprophet
Jul 22, 2004
Taco Defender
The main problem with that sort of thing is that at the most basic level, every hit to the site consists solely of three things: the request object, a context dictionary containing some data, and the template (meaning the specific template called, plus any other templates it extends and/or includes).

In other words, your outermost template doesn't have "its own view" -- it's gonna get whatever context dict is passed to the templates extending it. Here's a quick illustration:

Base template (note the user welcome + content block):
code:
<html>
<body>

<!-- nav -->
<div id="nav">
Welcome, {{ user.name }}!
<ul>
<li><a href="/foo">Foo</a></li>
<li><a href="/bar">Bar</a></li>
</ul>
</div>

<!-- content -->
<div id="content">
<h1>Our Site</h1>
{% block content %}{% endblock %}
</div>

<!-- pretend there's a footer here -->

</body>
</html>
Inner template for the 'foo' section of the site, say foo.html:
code:
{% block content %}
<h2>Foo Content</h2>
<p>{{ content }}</p>
{% endblock %}
Finally, here's your view function for /foo/, ignoring for now that you could do this with a generic view and not need an actual function :)
code:
from django.shortcuts import render_to_response

def foo(request):
    return render_to_response('foo.html', {'user': request.user, 'content': 'foo'})
Phew. The end result of all this, and hitting http://mywebsite.com/foo/ is that you'll get both templates rendering as if they were a single, unified template, with the one context dict provided (which gives the user from the request, and the content string). So your base template will happily render the user's name, and the inner template, the content string.

Now, you probably already knew most of that, but my point here is to illustrate the fact that the base template will render only what it is given each time it's used, and so at a naive level, you have to make sure that (for example) request.user is passed in to every. single. one. of your render calls, or else your base template will say "Hello, !" and look silly. There is no "view logic for the base template".


Thankfully, there's still a better solution than having to make sure you pass the same info in to every single view, or do the same logic in every view, etc, and that's to use what's called context processors, essentially middleware functions that apply to (almost) every template rendering, and can add stuff to the context dict.

For example, if you wanted all templates to have easy access to a {{ section }} variable that determined what section of the site you're in -- such as "foo" or "bar" -- you could do this (ignore the specific code if it's not obvious -- point being that it takes the URL and does some string processing on it):
code:
def add_section_string(request):
    section = ''
    parts = request.path.split('/')[1:]
    if len(parts):
        section = parts[0]
    return {'section': section}
If you stick that in a file and point to it in settings.TEMPLATE_CONTEXT_PROCESSORS, it'll get applied to template render calls that want to use this feature (all generic views, or passing a special context subclass to e.g. render_to_response -- see my docs link below for details). Thus, you could then update your base template to do stuff like:

code:
<ul>
<li{% ifequal section "foo" %} class="active"{% endifequal %}><a href="/foo">Foo</a></li>
...
</ul>
Note that I used section there, and yet, we did not modify the view function any -- we only added a context processor. If you had a big ol' site and all the rendering used the correct context subclass (pretty easy to do, and a good practice in general), plopping in a new context processor will instantly update all your templates with the new information.


Details on context processors can be found here.

bitprophet fucked around with this message at 02:35 on Sep 14, 2008

Mashi
Aug 15, 2005

Just wanted you to know your dinner's cold and the children all agree you're a shitheel!
Thanks for taking the time to give such a thorough answer (and im pretty sure that is the answer I was looking for) :).

A followup question if I may: If I add context processors, they are going to get executed regardless of whether my final output actually requires them (even in the admin interface... Actually I find it odd that your Django site and admin interface share settings). In some circumstances there might be somewhat considerable computation going on to generate this context, as well. Is it a good habit to subclass Context so that you can apply your own context processors to match the output?

bitprophet
Jul 22, 2004
Taco Defender

Mashi posted:

A followup question if I may: If I add context processors, they are going to get executed regardless of whether my final output actually requires them (even in the admin interface... Actually I find it odd that your Django site and admin interface share settings).

That's correct, although I wouldn't be too surprised if the admin managed to "turn off" custom context processors, given that it is otherwise generally self-contained. But, yea, it's just another app (albeit a contrib one, and one with perhaps one or two remaining 'hooks' into the framework -- but it's far, far more removed than it used to be) and so it shares the same settings as everything else does. Think of it more like a third-party app you just happen to be including in your site, and less like a core part of the framework, and that makes more sense.

quote:

In some circumstances there might be somewhat considerable computation going on to generate this context, as well. Is it a good habit to subclass Context so that you can apply your own context processors to match the output?

I'm actually not sure -- I haven't seen it done, but I don't have an omniscient view of the entire framework or what people have done with it, so I may well have missed that.

I think a better approach would be to include logic in your context processor that skips the heavy processing when it's not needed; you have access to the request object, which means you can do stuff like
code:
def crazy_processor(request):
    if request.path.startswith('/specific/section/'):
        foo = do_some_crazy_logic()
        return {'foo': foo}
    return {}
That's likely to be a much better idea than tinkering with Context, but the source is open and generally well written, so if you examine RequestContext and see how it manages TEMPLATE_CONTEXT_PROCESSORS, you might be able to make a similar subclass (or a subclass of RequestContext itself, depending) that lets you do whatever you want, maybe something like having a more in-depth context processor mapping. It's all just Python, so go crazy.

deimos
Nov 30, 2006

Forget it man this bat is whack, it's got poobrain!
While I dislike the mascot choice (a pink pony?) this is a neat representation.

mwarkentin posted:

You know the pink "magical pony" thing is a joke, right?

It's a djangocon thing.

deimos fucked around with this message at 23:05 on Sep 15, 2008

Adbot
ADBOT LOVES YOU

mwarkentin
Oct 26, 2004
You know the pink "magical pony" thing is a joke, right?

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply