tags:

views:

376

answers:

3

Hello, i'm new to Django and started an application, i did the models, views, templates, but i want to add some kind of archive to the bottom of the page, something like this http://www.flickr.com/photos/ionutgabriel/3990015411/.

So i want to list all years and next to them all the months from that year. The months who have posts to be links and other no. Also i want to translate the months names cause i need them in romanian.

What i've done so far is:

in my view:

def archive(request): 
    arch = Post.objects.dates('date', 'month', order='DESC') 

    archives = {} 
    for i in arch: 
        tp = i.timetuple() 
        year = tp[0] 
        month = tp[1] 
        if year not in archives: 
            archives[year] = [] 
            archives[year].append(month) 
        else: 
            if month not in archives[year]: 
                archives[year].append(month) 
    return render_to_response('blog/arhiva.html', {'archives':archives})

and in my template:

    {% for years, months in archives.items %} 
                    {{ years }} 
                    {% for month in months %} 
                   <a href="{{ years }}/{{ month }}">{{ month }}</a> 
                    {% endfor %} 
            <br /> 
                {% endfor %}

this returns something like:

       2008               10 
       2009               10               9 
       2007               10

but i can't sort them at all...by year or by anything, and also i don't know how to add all months(the names), i want them like this:

   2009 Ian Feb Mar Apr Mai Iun Iul Aug Sept Oct Noi Dec       
   2008 Ian Feb Mar Apr Mai Iun Iul Aug Sept Oct Noi Dec
   2007 Ian Feb Mar Apr Mai Iun Iul Aug Sept Oct Noi Dec

with link on the months who have entries.

Thank you for your help!

p.s. sorry for my English

LE: Maybe i put the question in a wrong way, i know how to obtain dates, but i don't know how to format them to look like these:

   2009 Ian Feb Mar Apr Mai Iun Iul Aug Sept Oct Noi Dec       
   2008 Ian Feb Mar Apr Mai Iun Iul Aug Sept Oct Noi Dec
   2007 Ian Feb Mar Apr Mai Iun Iul Aug Sept Oct Noi Dec

all i can get from arch = Post.objects.dates('date', 'month', order='DESC')

with

{{ archives }} in template is something like:

[datetime.datetime(2009, 10, 1, 0, 0), datetime.datetime(2009, 9, 1, 0, 0), datetime.datetime(2008, 10, 1, 0, 0), datetime.datetime(2007, 10, 1, 0, 0)]

then i've tried a loop:

{% for archive in archives %}

{{ archive }}

{% endfor %}

and got:

2009-10-01 00:00:00 2009-09-01 00:00:00 2008-10-01 00:00:00 2007-10-01 00:00:00

After that tried something like this:

{% for archive in archives %}

{{ archive|date:"Y: m" }}

{% endfor %}

and got:

2009: 10 2009: 09 2008: 10 2007: 10

Here i'm stuck and don't know how to format the data so i can get distinct years with all the months and only the months who have entries to be links...

Any ideas?

Thank you in advance!

+1  A: 

You might want to consider starting with a generic view and building off that. http://docs.djangoproject.com/en/dev/ref/generic-views/#date-based-generic-views

Matt Baker
thanks for answering but is not actually what i'm searching for.
cig212
Alasdair should get the answer for this, I'm not sure if it lets you "un-accept" but if possible give it to him.
Matt Baker
+4  A: 

Firstly, the datetime format strings are given in the django docs. I think you want capital instead of lowercase 'M'.

Since you want to display all 12 months of a year, even if only some have posts, we'll create an archives object to pass to the template. I've chosen to use a dictionary where

  • the keys are the years
  • the values are a list of 12 [datetime, bool] pairs, where datetime represents a month, and bool is True if there are posts for that month.

Here's how we build the archives object in the view.

from datetime import date

def archive(request):
    arch = Post.objects.dates('date', 'month', order='DESC')

    archives = {}

    for i in arch:
        year = i.year
        month = i.month
        try:
            archives[year][month-1][1]=True
        except KeyError:
            # catch the KeyError, and set up list for that year
            archives[year]=[[date(y,m,1),False] for m in xrange(1,13)]
            archives[year][month-1][1]=True

    return render_to_response('blog/arhiva.html', 
              {'archives':sorted(archives.items(),reverse=True)})

In the template, we loop through the months for each year, and display the link if appropriate.

{% for year, month_list in archives %}
  {{ year }} archives: 
  {% for month, has_link in month_list %}
    {% if has_link %}<a href="/{{ month.year }}/{{ month.month }}/">{% endif %}
      {{ month|date:"M" }}
    {% if has_link %}</a>{% endif %}
  {% endfor %}
{% endfor %}

I haven't checked all the code so there might be a couple of bugs. It would be better to use the url template tag for the link, instead of hardcoding the url format. I have a feeling my answer might be overly complicated, but I've spent a while typing it up, so I may as well share it with the world.


Internationalization

I haven't used the internationalization features of Django, so I can't really help with the translation. I recommend you have a look at the documentation, and ask another question if there's a particular bit you don't understand.

Having said that, if you want to display the months is Romanian only, here's an ugly way to do it.

First, add the following line to the top of your archive function in the view.

rom_months = ['Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', 
              'Iul', 'Aug', 'Sept', 'Oct', 'Noi', 'Dec']

Then substitute the following line into your view

archives[year]=[[date(y,k+1,1),False,rom] for k, rom in enumerate(rom_months)]

Finally substitute the following into the template

...
{% for month, has_link, rom_month in month_list %}
  {% if has_link %}<a href="/{{ month.year }}/{{ month.month }}/">{% endif %}
  {{ rom_month }}
...
Alasdair
Hey man WOW, you rock! This works but i also want to display all 12 months even there aren't entries for them and also with their names translated.Thank you again for your help, i've been struggling with this for a week.
cig212
Again WOW, such a nice answer. my url pattern is /2009/10. I don'y know if i can thank you enough for this.Any ideas how to translate the month names? or something? Thank you in advance!
cig212
I've added a hacky way to add the months in Romanian, but I recommend you check out the internationalization features of Django first.
Alasdair
ok, got it but i have an error from your first answer...i got:'int' object is not iterableon this linearchives[year][month-1]+=1anything about it?Thank you!
cig212
I've fixed a couple of bugs try it now.
Alasdair
Thanks a lot again, but final working code looks like this:in template:{% for year, month_list in archives.items %} {{ year }} archives: {% for month, has_link in month_list %} {% if has_link %}<a href="/{{ month.year }}/{{ month.month }}/">{% endif %} {{ month|date:"M" }} {% if has_link %}</a>{% endif %} {% endfor %} <br />{% endfor %}
cig212
Thanks a million! All nice and done like a pro! You're GOLD! Hope i can help you with something someday! All this was awesome like django itself, started with rails but from now on Django is the way. Have a nice day/night!
cig212
I'm glad we finally go it working! I might clean up the code and turn it into a template tag sometime.
Alasdair
A: 

Ok... so the final code that works for me is:

in view:

 rom_months = ['Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', 
'Iul', 'Aug', 'Sept', 'Oct', 'Noi', 'Dec']

def arhiva(request):
    arch = Post.objects.dates('data', 'month', order='DESC')

    archives = {}

    for i in arch:
        year = i.year
        month = i.month
        try:
            archives[year][month-1][1] = True
        except KeyError:

            archives[year]=[[datetime.date(year,k+1,1),False,rom] for k, rom in enumerate(rom_months)]
            archives[year][month-1][1] = True

    return render_to_response('blog/arhiva.html', {'archives':sorted(archives.items(),reverse=True)})

and in template:

{% for year, month_list in archives %}
    {{ year }} Arhive: 
    {% for month, has_link, rom_month in month_list %}
        {% if has_link %}<a href="/{{ month.year }}/{{ month.month }}/">{% endif %}
             {{ rom_month }}
        {% if has_link %}</a>{% endif %} 
    {% endfor %}
    <br />
{% endfor %}

and the result:

2009 Arhive: Ian Feb Mar Apr Mai Iun Iul Aug Sept Oct Noi Dec 
2008 Arhive: Ian Feb Mar Apr Mai Iun Iul Aug Sept Oct Noi Dec 
2007 Arhive: Ian Feb Mar Apr Mai Iun Iul Aug Sept Oct Noi Dec 
2003 Arhive: Ian Feb Mar Apr Mai Iun Iul Aug Sept Oct Noi Dec

Thanks a lot again for help. You're the best! I'm the n00b! :)

cig212