Tag: django

0

Web-app CoWorker giver mulighed for alle folk til at benytte sig af kontorlokaler.
Man booker på forhånd et ønsket lokale til en ønsket varighed. For at få adgang til det lokale i det tidsrum, lukker appen døren op for en.

Det er en meget omfattende app, som håndterer bl.a:

  • brugerregistrering
  • registrering kompetencer
  • online betaling
  • booking
  • booking invitationer
  • booking reminders
  • låse kommunikation

CoWorker

CoWorker flow

Denne web-app er en sammensatning af Django, Bootstrap og Javascript.

0

As much as you want to offer localization for your project in your templates, you also want to offer that in your Javascript. When a project supports Spanish you don’t want any alerts from Javascript to be in English, comprendo?
There are several ways to accomplish that, but it would be easy for your translation-team to have all texts in the same PO file, and easy for you to have it all in the same MO file 🙂

Having that done in Django is fairly straightforward: Create a .JS file, as if it was any other document Django renders for you. You have rendered HTML and probably JSON documents before. We build a Javascript document in the very same way. This .JS file contains all the strings you’re using in the client-side of your project. Include this file on all, or the required pages, and all your scripts will be able to access its variables, containing your texts – in Spanish.

Get busy!

Let’s start where everything starts in Django; the URLs:

myproject/urls.py

from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',

    # Admin
    url(r'^admin/', include(admin.site.urls)),

    # JS locale
    url(r'^js/locale.js$', 'myproject.views.js_locale', name='js-locale'),

    # etc your apps here etc
)

In other words: “/js/locale.js” will be rendered by this view: “myproject.views.js_locale”. Let’s create that view:

myproject/views.py

from django.shortcuts import render, render_to_response
from django.template import RequestContext
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.cache import cache_page

@cache_page(60 * 60 * 24)
def js_locale(request, template_name = 'js/vars.js', **kwargs):
    '''
    Javascript document
    containing strings for
    the client-side scripts
   
    '''

    vars = [
        ['var SK',                        'SK || {}', False],
        ['SK.text',                       'SK.text || {}', False],
        ['SK.text.rusure_cancel_booking', _("Are you sure that you want to cancel this booking?"), True],
        ['SK.text.error_occorred',         _("An error occurred"), True],
    ]
    return render_to_response(template_name,
                              {
                                'vars' : vars,
                              },
                              mimetype="text/javascript")

You can see what I’m intending to do: Apart from the document is heavily cached 🙂 I’m sending definitions to a template which looklike they can become Javascript.
In the end the document gets the header “text/javascript”, so everybody knows what we’re talking about.

Let’s have a look at the template:

myproject/templates/js/vars.js

{% for var in vars %}{{ var.0 }}={% if var.2 %}"{% endif %}{{ var.1|escapejs }}{% if var.2 %}"{% endif %};{% endfor %}

So we’re looping over the list where each item (also) is a list with three indexes:

  • 0: variable definition
  • 1: variable value
  • 2: boolean; quote the value (for strings) or not

Accessing the URL “/js/locale.js” will now provide you this:

var SK = SK || {};
SK.text = SK.text || {};
SK.text.rusure_cancel_booking = "Are you sure that you want to cancel this booking?";
SK.text.error_occorred = "An error occurred";

Let’s include that file in our document template (or where ever you need it):

myproject/templates/doc.html

{% load static %}

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">

    <title>What you hear is not a ....</title>

    <script src="{% url 'myproject.views.js_locale' %}" type="text/javascript"></script>
    <script src="{% static 'assets/js/scripts.js' %}" type="text/javascript"></script>
</head>
    <body>
        {% block markup %}
        {% endblock %}
    </body>
</html>

From now on you can access those translated texts from any script.
For example “assets/js/scripts.js” could now display a confirm in Spanish, when translated:

// stuff above

if( confirm( SK.text.rusure_cancel_booking ) ){
    cancel_booking();
}

// stuff below

Keep DRY, not dirty

Everything works! But…
As your texts will grow while proceeding your client-side scripts, it will pollute your view with a lot of strings, who don’t really belong there. So let’s move those to a separate file. My approach is to put all the ‘common’ texts in there, and let the text-namespace be defined in the view (or perhaps several views).

myproject/views.py

from django.shortcuts import render, render_to_response
from django.template import RequestContext
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.cache import cache_page

# note this new import
from js_locale import sk_js_vars

@cache_page(60 * 60 * 24)
def js_locale(request, template_name = 'js/vars.js', **kwargs):
    '''
    Javascript document
    containing strings for
    the client-side scripts

    '''

    namespacing = [
        ['var SK',  'SK || {}', False],
        ['SK.text', 'SK.text || {}', False],
    ]
    vars = namespacing + cw_js_vars
    return render_to_response(template_name,
                              {
                                'vars' : vars,
                              },
                              content_type="text/javascript")

myproject/js_locale.py

from django.utils.translation import ugettext_lazy as _

'''
[name, value, value must be quoted or not]
'''


sk_js_vars = [
    ['SK.text.save',                    _("Save"), True],
    ['SK.text.delete',                  _("Delete"), True],
    ['SK.text.add',                     _("Add"), True],
    ['SK.text.remove',                  _("Remove"), True],
    ['SK.text.confirm',                 _("Confirm"), True],
    ['SK.text.confirmed',               _("Confirmed"), True],
    ['SK.text.decline',                 _("Decline"), True],
    ['SK.text.declined',                _("Declined"), True],
    ['SK.text.pending',                 _("Pending"), True],
    ['SK.text.unsaved',                 _("Unsaved"), True],
    ['SK.text.not_invited_yet',         _("Not invited yet"), True],
    ['SK.text.awaiting_invitation',     _("Awaiting invitation"), True],
    ['SK.text.rusure_cancel_booking',   _("Are you sure that you want to cancel this booking?"), True],
    ['SK.text.rusure_make_booking',     _("Are you sure that you want to make this booking?"), True],
    ['SK.text.error_occured',           _("An error occured"), True],
    ['SK.text.could_not_save_booking',  _("Could not save booking"), True],
    ['SK.text.not_enough_credits',      _("You don't have enough credits for this."), True],
    ['SK.text.buy_credits',             _("Buy credits"), True],
    ['SK.text.space_n_location',        _("Space and location"), True],
    ['SK.text.location',                _("Location"), True],
    ['SK.text.for',                     _("for"), True],
    ['SK.text.hours',                   _("hours"), True],
    ['SK.text.at',                      _("at"), True],
    ['SK.text.until',                   _("until"), True],
    ['SK.text.error',                   _("Error"), True],
    ['SK.text.now',                     _("Now"), True],
    ['SK.text.max_exceeded',            _("You have exceeded the allowed maximum"), True],
    ['SK.text.invalid_email',           _("E-mail address not valid"), True],
    ['SK.text.double_entry',            _("Double entry"), True],
]
0

I won’t have to pencil out that when working with dates, that timezone-awareness is crucial.
Here are two pages you might want to look at if that is new for you:

Though I’ve had some headaches the last 24 hrs getting it working with timestamps.
In my (Socify.it) project I’m using timestamps to recieve a (Unix) timestamp through a webservice and have to find a specific file on a FTP server matching that timestamp, with in another format (like “cam1-%Y-%m-%d-%H-%M-%S.jpg“).

Your timestamps must be ‘neutral’. Afterwards you can extract a time-zone dependent date-time.

Just using datetime.utcfromtimestamp(timestamp) will set a date determined by what you have in you Django settings’s TIME_ZONE.
You’ll need to ‘normalize it’ with the timezone that has saved that date-time.

>>> import pytz
>>> from datetime import datetime
>>> from django.utils.timezone import utc
>>> timestamp = 1353574755
>>> tz = 'Australia/Sydney'
>>> tz = pytz.timezone(tz)
>>> utc_dt = utc.localize(datetime.utcfromtimestamp(timestamp))
>>> e_dt = tz.normalize(utc_dt.astimezone(tz))

Now let’s do that the other way around. In this example I’ll try to keep the timestamp ‘neutral’, in order to be able to extract a time-zone dependent date-time, later on : Calendar.timegm() is our friend here, where time.mktime() isn’t.

Let’s import that and try:

>>> import calendar
>>> utc_dt = utc.localize(datetime(2012, 11, 24,0,0,0))
>>> timestamp = calendar.timegm(utc_dt.timetuple())

Check yourself by converting it back. Also try time.mktime() in stead of calendar.timegm() and see the unwanted difference!

0

After I upgraded my Mac OS to Mountain Lion, I immediately noticed Apache needed to be reconfigured (just as last time).
This link and this one too helped me out pretty much.

But after a while it was time to work locally with my favourite weapon of choice, Django.
Django seemed to be wiped away too, including PIP.

Below is how I tested and retrieved it, it might come handy when you’re in the same situation. See if it’s usefull for you:

# django installed?
$ python
>>> import django

# ..or..

# present in current python version's packages, find path
$ python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"

# what other python versions do you have?
$ python[tab][tab]

# perhaps django finds in another version
$ python2.5 -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"

# if so, try..
$ python2.5 manage.py shell

## fresh django install ##

# install pip
$ sudo easy_install pip

# install django
$ sudo pip install Django

# test
$ python
>>> import django
>>> django.VERSION
0

Endnu en ‘socification’ af en begivenhed ved hjælp af produktet Socify.it.
På Lanzarote Running Challenge 2012 har vi postet fotos af løbere ‘in action’ live på Facebook sammen med deres timing-results.

socify.it flow Running Challenge

I detaljer

Opsætning er magen til den fra IronMan Lanzarote 2012 tilbage i maj måned.
Men nu har vi (Rasmus Johnsen og jeg) involveret co-starfisher Stian Eide, for at realisere en ‘kamera-løsning’. Ved hjælp af et IP kamera har vi etableret en løsning der tager billeder af løberne, når de passerer kameraet, som postes direkte til Facebook.

Off-line løsning

Ved udfald af netforbindelse et eller andet sted i netværket, kan løbet ‘genafspilles’ på hvilket som helst tidspunkt. Løsningen er dermed ‘bulletproof’ i uheldige situationer, hvor internetforbindelsen falder ud.

Internet på bjergtoppen

Ved et af løbene havde vi placeret et kamera på en bjergryg. Netværk specialisten Stian Eide havde skaffet internetforbindelse via et link fra Club La Santa komplekset helt op til bjergryggen!! Herfra postede vi billeder live til Facebook!

Resultater på Facebook:

socifyit-running-challenge-2012-10k-road-race

socifyit-running-challenge-2012-Ridge-Run

socifyit-running-challenge-2012-21K-La-Vuelta-de-Tinajo

socifyit-running-challenge-2012-heroes

0

I august og september måned har sejKo udvidet produktet “Socify.it” (beskrevet i tidligere indlæg).
Kort sagt er Socify.it i stand at poste data, modtaget fra eksterne ‘sensorer’, på ens vegne, på ens sociale profil.

Integration til TracTrac

Til Eurosaf Youth European Championship 2012 kapsejlads, har vi tilføjet en ny sensor til Socify.it; TracTrac.
TracTrac er verdens førende leverandør indenfor GPS tracking og meget engageret i sejlsporten.
Alle både har en GPS tracker om bord, og TracTrac fortæller Socify.it hvornår de har startet, rundet bestemte mærker og finished, som vi poster på deltagernes Facebook profiler.

Poste billeder

Den seneste feature er at Socify.it kan poste billeder med relateret data på vegne af en bruger.
Til KIA Cold Hawaii Worldcup windsurfing var Socify.it en del af et innovationsprojekt, hvor den nye feature blev taget i brug for første gang. Vi har sat en integration op med iScore, PWAs nye scoring system (sejKo har for to år siden har præsenteret PWA en prototype for sådan et system), som kan fortælle os hvem der har vundet og med hvor mange point (forskel). Et billede af vinderen bliver postet på dens Facebook (Fanpage) timeline, alt styret via integrationen til PWA iScores API.


Eurosaf Youth European Championship 2012


Find de 3 socifications…
Svar: 1) Kenneth Danielsen starter sin heat -højre i timeline. 2) Kenneth Danielsen har vundet sin heat -ventre i timeline. 3) Martin ten Hoeve starter sin heat -øverst i tickeren!

2

SejKo og co-starfisher Rasmus Johnsen er sammen om produktet, Socify.it. ‘Socifying’ er et verbum fra et nyt begæb vi har indført, “socification”, der stammer fra “social notification”. Produktet kan poste på vegne af mennesker på deres sociale media profiler, når de har gang i noget betydningsfuld for dem, men ikke selv er i stand til at poste. Deres livs skrapbog bliver vedligeholdt med deres vigstigste begivenheder.
Data som Socify.it sender ud kommer fra en ‘signal provider’, der har styr på hvad vedkommende præcis har foretaget sig,

Socify.it er en slags ‘middleware’ der kobler sociale profiler og signal providers sammen. Se på Socify.it som en adapter; et enhvert system kan nemt sende data til Socify.it som laver relevante posts på sociale medier.
Til Ironman Lanzarote 2012, har vi koblet deltagerens Facebook profiler sammen men Club La Santas tidtagningssystem: Alle deltagere har en chip på sig. Hver gang en registrede deltager passer en tidtagensport sender systemet data (course, tid brugt, nuværende placering) til Socify.it som poster det ud på vedkommendes Facebook timeline / wall. Famile og venner ‘der hjemme’ hepper løs på Facebook via kommentarer og likes. Deltagerne bliver til helte i deres eget miljø, uanset hvor godt de klarer sig i løbet.
Se Rasmus Johnsens præsentation af “socifying Ironman Lanzarote 2012”.

Her et par screenshots af nogle Facebook profiler, som Socify.it har fyldt op:

Facebook timeline af amatøren Ole Storm

Facebook timeline af pro-løber (og vinderen af dette løb) Michelle Vesterby

0

GPS-tracking-platformen TRACKMate er blevet udvidet med nye kort-features: Kortet kan håndtere flere trackere, ud over kaldenavnet kan hver tracker tildeles sin egen farve på kortet. Via Hurtig historik kan man ved hjælp af en mini-kalender lynhurtigt se historiken for den pågældende tracker.

Det meste arbejde er foregået i OpenLayers (javascript mapping API) (Hvad er det??)

0

For første gang nogensinde i worldcup windsurfing introducerer sejKo live scoring. Hidtil giver dommerne point ved at skrive dem ned på et stykke papir, efter vinderen er regnet ud bliver scoresne kasseret.

Sejko har til KIA PWA Coldhawaii Worldcup 2010 vist hvad man kan digitalt via et beta produkt, ScoreShare. Dette første udkast er bygget i 2,5 uge efter en ugens brainstorm, i Django (som ejer sig for ‘agile webdevelopment‘). Det er ikke den endelige produkt endnu, men håndtere basic input og outout.
Produktet er et platform til indtastning af scores, via en for dommerne let tilgængelig interface, som bliver gemt i en database. Data er tilgængelig via en API, hvormed man kan alt, som fx. lave en facebook app til deltagerne som viser deres dagens højeste score, eller lave et analyse produkt til coaches. Vi har brugt til at lave en WordPress widget som viser resultaterne så snart at de er gjort tilgængelig.

Produktet er prøvet af og taget godt imod af en af PWA dommerne, Frank Roguet, som kom med feedback til videreudvikling. Lad os se hvad der kommer til at ske med det!

0

Platformen til TRACKMate er nu delt 100% op i en kerne og ‘pluginsites’. Alle kundesites kan plugges ind på denne kerne, og leve med deres egen logik, sider, tekster/sprog og grafik. Et plugin-site kan trække på templates og funktioner fra kernen og ‘extende’ disse, men kan også bare anvende sit eget 100%.

På denne måde ligger TRACKMates eget site nu ved siden af, men 100% uafhængig af, Kronings’ site.