Showing posts with label python. Show all posts
Showing posts with label python. Show all posts

Wednesday, February 6, 2013

Restricting django to one user concurrent session only

Here's the tiny code that helps you avoid multiple users logged using the same account.
# -*- coding: utf-8 -*

from django.conf import settings
from django.core.cache import cache, get_cache
from django.utils.importlib import import_module


class UserRestrictMiddleware(object):
    def process_request(self, request):
        """
        Checks if different session exists for user and deletes it.
        """
        if request.user.is_authenticated():
            cache = get_cache('default')
            cache_timeout = 86400
            cache_key = "user_pk_%s_restrict" % request.user.pk
            cache_value = cache.get(cache_key)

            if cache_value is not None:
                if request.session.session_key != cache_value:
                    engine = import_module(settings.SESSION_ENGINE)
                    session = engine.SessionStore(session_key=cache_value)
                    session.delete()
                    cache.set(cache_key, request.session.session_key, 
                              cache_timeout)
            else:
                cache.set(cache_key, request.session.session_key, cache_timeout)

# vim: ai ts=4 sts=4 et sw=4
Hope you like it.
Remember, to put UserRestrictMiddleware somewhere after Session Middleware in MIDDLEWARE_CLASSES (settings.py)

Friday, September 21, 2012

Django cache templatetag with dynamic backend parameter

I've found a nice project django-adv-cache-tag.

From the project website:

With django-adv-cache-tag you can :
  • add a version number (int, string, date or whatever, it will be stringified) to you templatetag : the version will be compared to the cached one, and the exact same cache key will be used for the new cached template, avoiding keeping old unused keys in your cache, allowing you to cache forever.
  • avoid to be afraid of an incompatible update in our algorithm, because we also use an internal version number, updated only when the internal algorithm changes
  • define your own cache keys (or more simple, just add the primary key (or what you want, it's a templatetag parameter) to this cache key
  • compress the data to be cached, to reduce memory consumption in your cache backend, and network latency (but it will use more time and cpu to compress/decompress)
  • choose which cache backend will be used
  • define {% nocache %}...{% endnocache %} blocks, inside your cached template, that will only be rendered when asked (for these parts, the content of the template is cached, not the rendered result)
  • easily define your own algorithm, as we provide a single class you can inherit from, and simply change options or whatever behaviour you want, and define your own tags for them
I am using template fragments caching a lot, but some parts of website need invalidating depending on products type etc. 
I am invalidating cache on save & delete signals for model.

Here's the example:
Say there are 5 types of products and your website includes listing for them (which needs lots of data processing etc) and you want to cache it.


from django.db import models

PRODUCT_TYPE_CHOICES = (
('type1','type2'),
('type2','type2'),
('typen','typen'),
)

class Product(models.Model):
    attr1 = ...
    attrn = ...
    type =  models.CharField("Product Type", max_length=6, choices=PRODUCT_TYPE_CHOICES)
Using one backend, modifying product of type1 will purge the entire cache backend. Set up more backends:
# settings.py

CACHES= {
    'templates_products_type1': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
        },
    'templates_products_type2': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11212',
        },
}
You can also use Redis for caching, which requires you to run one redis instance with multiple databases. Let's create our own {% my_cache %} templatetag with cache backend name as a first vary_on parameter. (this is the quickest way as you can also use get_pk() or even add your own parameters to {% my_cache %} templatetag. You could also use fragment name but it's not resolvable. Let's get to the code:
#my_cache_tags.py
from adv_cache_tag.tag import CacheTag
from django.core.cache import get_cache
from django import template

register = template.Library()

class MyCacheTag(CacheTag):
    def get_cache_object(self):
        backend = self.vary_on[0]
        return get_cache(backend)
MyCacheTag.register(register, 'my_cache')
Here's the template code:
# assuming products_type variables is assigned
{% load my_cache_tags %}

{% with backend="templates_products_"|add:products_type %}
{% my_cache 0 products backend other_vary_on_variables %}
{% for product in product_list %}
{{ product }}
{% endfor %}
{% endmy_cache %}
When saving or deleting products of some type, just purge template cache for produdcts only of this specified type.
from django.core.cache import get_cache
#function run on model save / delete

def clear_products_template_cache(type):
    cache_name = "templates_products_" + type
    cache = get_cache(cache_name)
    cache.clear()
NOTE: This is a SIMPLIFIED solution. I just wanted to point out that you can easily use different backends for one template cache tag. It's your job to make some additional processing code (especialy get_cache_object() for selecting cache backend etc.

Tuesday, June 19, 2012

Django verbose_name in your template

There are many situations when you want to display model field verbose_name in template when displaying tables and other data. Ideally you would put this value in header section of your table for DRY purposes.
The problem is that it's unable to use model _meta in templates. You can achive the same using an example verbose_name_tags.py templatetag.
# verbose_name_tags.py

from django import template

register = template.Library()

def get_field_verbose_name(instance, arg):
    return instance._meta.get_field(arg).verbose_name
register.filter('field_verbose_name', get_field_verbose_name)

def get_queryset_field_verbose_name(queryset, arg):
    return queryset.model._meta.get_field(arg).verbose_name
register.filter('queryset_field_verbose_name', get_queryset_field_verbose_name)

you can get your header names rendered the DRY way.
Assuming your model looks like this:
class Product(models.Model):
    name = models.CharField(_(u"Name"), max_length=20)
    weight = models.PositiveIntegerField(_(u"Weight"))

Your template would be similar to the one below:
{% load verbose_name_tags %}

<table>
  <thead>
  <tr>    
    <th>{{ object_list|queryset_field_verbose_name:"name" }}</th>
    <th>{{ object_list|queryset_field_verbose_name:"weight" }}</th>
  </tr>
  </thead>
  <tbody>
{% for product in object_list %}    
  <tr>
    <td>{{ product.name }}</td>
    <td>{{ product.weight }}</td>
  </tr>
{% endfor %}
</table>

What if you need sorting ?
For some time I've been using a django-sorting for sorting my tabular data.
The new code
{% load sorting_tags %}
{% autosort object_list %}

<table>
  <thead>
  <tr>    
    {# _("Name").. need to specify the display name all the time.. bad.. #}
    <th>{% autosort 'name' _("Name") %}</th>
    <th>{% autosort 'weight' _("Weight") %}</th>
  </th></tr>
  </thead>
  <tbody>
{% for product in object_list %}  
  <tr>
    <td>{{ product.name }}</td>
    <td>{{ product.weight }}</td>
  </tr>
{% endfor %}
  </tbody>
</table>

Great, but this is not DRY! You can do this the other way. Note: I think {% autosort %} should take verbose_name by default (maybe will take a look into the code later, but for now we can achieve the same using a {% with %} and verbose_name_tags.py template tags.
{% load sorting_tags %}
{% load verbose_name_tags %}

{% autosort object_list %}

{% endfor %}
<table>
  <thead>
  <tr>
    {% with name=object_list|queryset_field_verbose_name:"name" %}    
    <th>{% autosort 'name' name%}</th>
    {% endwith %}
    {% with weight=object_list|queryset_field_verbose_name:"weight" %}
    <th>{% autosort 'weight' weight %}</th>
    {% endwith %}
  </tr>
  </thead>
  <tbody>
  <tr>
    <td>{{ product.name }}</td>
    <td>{{ product.weight }}</td>
  </tr>
  </tbody>
</table>

Now we can just change verbose_name in models.py and we don't have to worry about the table headers.
You can also use a "field_verbose_name" for model instances:
{# assuming {{ product }} is an instance of Product model #}
{% load verbose_name_tags %}

{{ product|field_verbose_name:"name" }}: {{ product.name }}

Some might wonder why didn't I simply use one templatetag name which would identify if it checks for queryset or instance field. I decided to use different names to quickly see If I act with querysets or instances. Hope you like it.

Tuesday, March 27, 2012

Gunicorn + Nginx - a much better way to deploy your Django website

I've been a lighttpd + FastCGI django user for a long time.
Now there's a better solution -> gunicorn.

What is a gunicorn?
Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX. It's a pre-fork worker model ported from Ruby's Unicorn project. The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resources, and fairly speedy.
If you are a fastcgi user, please check gunicorn asap. I'm sure you will get much more from your hardware :-)
Ps: Note that you get the most if database is not the bottleneck. That's why you should use cache everywhere if possible.

Here's my script for gunicorn + daemontools for supervising:
#!/bin/sh

# SITE_PATH is a directory where settings.py is stored
SITE_PATH=/var/www/django/projects/my_project/; export SITE_PATH
USER=www-data
TCP=127.0.0.1:8888

exec setuidgid $USER /usr/bin/gunicorn_django -b ${TCP} -w 3 --max-requests=1000 ${SITE_PATH}settings.py 2>&1

Seems like wsgi is also recommended with the new 1.4 version of Django
If you’re new to deploying Django and/or Python, we’d recommend you try mod_wsgi first. In most cases it’ll be the easiest, fastest, and most stable deployment choice.
Check django site for more information.

UPDATE:
Forgot to mention that I've switched from lighttpd to Nginx.
You can use the script above with the following nginx config:
server {
    listen   xx.xx.xx.xx:80;
    server_name domain.com www.domain.com;
    root /var/www/django/projects/my_project/public;
    access_log /var/log/nginx/domain-access.log;

    rewrite ^/admin(.*) https://domain.com/admin$1 permanent;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /media {
        root /var/www/django/projects/my_project/django/contrib/admin;
    }
    location /static {
        root /var/www/django/projects/my_project/site_media;
        access_log off;
    }
    location /site_media {
        root /var/www/django/projects/my_project;
    }
    location / {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Forwarded-For  $remote_addr;
        proxy_set_header X-Scheme $scheme;
        proxy_connect_timeout 10;
        proxy_read_timeout 10;
        proxy_pass http://127.0.0.1:8888/;
    }

}

There's a trick you need to apply to get the real ip of the request source as seen in the line:
proxy_set_header X-Forwarded-For  $remote_addr;

Here's a code I'm using:
class XForwardedForMiddleware(object):
       def process_request(self, request):
        if "HTTP_X_FORWARDED_FOR" in request.META:
            ip = request.META["HTTP_X_FORWARDED_FOR"]
            if ip.startswith('::ffff:'):
                ip = ip[len('::ffff:'):]
            request.META["REMOTE_ADDR"] = ip
            request.META["REMOTE_HOST"] = None

Add XForwardedForMiddleware to your settings.py MIDDLEWARE_CLASSES setting.

Friday, March 2, 2012

Django HTML5 date input widget with i18n support and jQueryUI DatePicker fallback

Here's my manual for creating a HTML5 form date input with jQueryUI Datepicker and multilingual support.

What we need is:
1. django-floppyforms
2. jQueryUI Datepicker + jQuery 3. Modernizr javascript library
and of course - Django
You need to have some basic python, django & jquery knowledge.
Make sure multilingual support is enabled:
USE_I18N = True

and request context available for template
#settings.py

TEMPLATE_CONTEXT_PROCESSORS = (
  # ...
  'django.core.context_processors.request',
  # ...
)
In your base template, you can use LANGUAGE_CODE variable.
<html lang="{{ LANGUAGE_CODE }}">

There are 3 ways to get this running

1. Totally django way - prividing django form & widget with the "lang" variable"

Your calendar widget needs to gain information about the language, so you need to pass a variable to your form, which then sends this variable to the widget.
def add_view(request):
    
    form = SomeForm(data = request.POST, lang=request.LANGUAGE_CODE)
    if form.is_valid():
        do_some_stuff()

from django import forms
from common.widgets import DatePicker

class SomeForm(forms.ModelForm):
    data = forms.CharField()
    when = forms.DateField()

    def __init__(self, *args, **kwargs):
        lang = kwargs.pop('lang')
        super(SomeForm, self).__init__(*args, **kwargs)
        
        self.fields['when'].widget = DatePicker(lang=lang)
import floppyforms as forms
from django.conf import settings

class DatePicker(forms.DateInput):
    template = "common/datepicker.html"

    def __init__(self, *args, **kwargs):
        self.lang = kwargs.pop('lang')
        super(DatePicker, self).__init__(*args, **kwargs)
    
    def get_context(self, name, value, attrs):
        ctx = super(DatePicker, self).get_context(name, value, attrs)
        ctx['lang'] = self.lang
        ctx['STATIC_URL'] = settings.STATIC_URL
        return ctx
The below, could be attached to python render() method in the widget, but I think this is more elegant way, and thanks to floppyforms we get native HTML5 date widget if available. I am aware of that floppyforms has an example of html5 datepicker, but the way the floppyforms author checks for date type doesn't seem to work - that's why I've used modernizr.
{# "common/datepicker.html" #}
{% include "floppyforms/input.html" %}

<script type="text/javascript">
    if (!Modernizr.inputtypes.date) {
       $(function () {
         $.datepicker.setDefaults($.datepicker.regional['{{ lang }}']);
         $('#{{ attrs.id }}').datepicker({showOn: "both", buttonImageOnly: true, dateFormat: "yy-mm-dd", buttonImage: "{{ STATIC_URL }}new/img/calendar.gif"})} )}
</script>

What the above code does is check if
<input type="date" />
is available. If not, it runs the jqueryUI calendar widget.
The javascript attached is to the specified selector. I've decided to go this way as I needed the calendar widget on ajax loaded content.
This is a Django (well.. not the sortest way).

2. Javascript way. Less django form messing.

You can achieve the similar effect without prividing both SomeForm & DatePicker widget with the lang variable.
import floppyforms as forms

class DatePicker(forms.DateInput):
    template = "common/datepicker.html"
Let the form know the widget it should use
from django import forms
from common.widgets import DatePicker

class SomeForm(models.Model):
    data = forms.CharField()
    when = forms.DateField(widget=DatePicker)
In the widget template code, you need jQuery for language detection.
{# "common/datepicker.html" #}
{% include "floppyforms/input.html" %}

<script type="text/javascript">
    if (!Modernizr.inputtypes.date) {
       
         $(function () {
         var lang = $('html').attr('lang');
         $.datepicker.setDefaults($.datepicker.regional[lang]);
         $('#{{ attrs.id }}').datepicker({showOn: "both", buttonImageOnly: true, dateFormat: "yy-mm-dd", buttonImage: "{{ STATIC_URL }}new/img/calendar.gif"})} )}
</script>
but I'm affraid this might not work on ajax loaded content where you need your calendar widget.

3. Django way, without messing the widget code too much.

Another way could be simply providing the form with data-lang attribute. The form would then look as follows:
from django import forms
from common.widgets import DatePicker

class SomeForm(forms.ModelForm):
    data = forms.CharField()
    when = forms.DateField()

    def __init__(self, *args, **kwargs)
        lang = kwargs.pop('lang')
        super(SomeForm, self).__init__(*args, **kwargs)

        self.fields['when'].widget = DatePicker(attrs={'data-lang': lang})
and then in the datepicker.html
{# "common/datepicker.html" #}
{% include "floppyforms/input.html" %}

<script type="text/javascript">
    if (!Modernizr.inputtypes.date) {
       $(function () {
         $.datepicker.setDefaults($.datepicker.regional[$('#{{ attrs.id }}').attr('data-lang'));
         $('#{{ attrs.id }}').datepicker({showOn: "both", buttonImageOnly: true, dateFormat: "yy-mm-dd", buttonImage: "{{ STATIC_URL }}new/img/calendar.gif"})} )}
</script>

The 2 ways above have no {{ STATIC_URL }} in widget template available. You need to get it yourself, via templatetag, or simply using hardcoded url.

Hope someone gets some tips from this manual

There for sure are many other ways, feel free to share them. Remember to include javascript modernizr, jQuery and jQuery files!

Monday, March 3, 2008

Django ModelForm - replacement for form_for_model & form_for_instance

Each commit, Django gets more amazing.

I wrote about newforms library before. The library was a big step in Django form displaying and validating.

The first approach was to use forms.form_for_model() and forms.form_for_instance() respectively.

As Django programmer I found this a little confusing. Both were similar. The only difference was that form_for_instance() took an object instance for saving instead
of creating a new one. Recently django developers came up with a great idea - forms.ModelForm which combines both into one. It's great!

Just take a look at the example below.
Assume you want to create a new view function for creating & editing an object.
You only want to edit 3 fields (name, last_name, status). Also, you've created a
customized field type for "status", and want to use that.

Scenario #1: (forms.form_for_model && forms.form_for_instance)


def f_callback(field, **kwargs):
if field.name == "status":
return MyStatusField(**kwargs)
else:
return field.formfield(**kwargs)

def create_edit_customer(request, customer_id=None):

# check if object_id is None and if object exists
if object_id is None:
CustomerForm = forms.form_for_model(Customer,
formfield_callback=f_callback,
fields=('name','last_name','status')
else:
customer = get_object_or_404(Customer, id=customer_id)
CustomerForm = forms.form_for_instance(customer,
formfield_callback=f_callback,
fields=('name','last_name','status')

if request.method == "POST":
form = CustomerForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('customer/added/')
else:
form = CustomerForm()

return render_to_response("customers/customer_form.html", {'form' : form })




You could create your own form_for_model & form_for_instance subclass (using forms.BaseForm for example), but it would be too complicated. Hope you don't use this form often :-)

Scenario #2 (ModelForm)

1. Longer version.


class CustomerModelForm(forms.ModelForm):

class Meta:
model = Customer
fields = ('name','last_name','status')

status = MyCustomerField()

def create_edit_customer(request, customer_id=None):

if customer_id is not None:
customer = get_object_or_404(Customer, id=customer_id)
else:
customer = None


if request.method == "POST":
form = CustomerModelForm(data=request.POST, instance=customer)
if form.is_valid():
form.save()
return HttpResponseRedirect("/customer/added/")
else:
form = CustomerModelForm(instance=customer)

return render_to_response("customers/customer_form.html", {'form' : form })



2. Shorter version.


class CustomerModelForm(forms.ModelForm):

class Meta:
model = Customer
fields = ('name','last_name','status')

status = MyCustomerField()

def create_edit_customer(request, customer_id=None):

if customer_id is not None:
customer = get_object_or_404(Customer, id=customer_id)
else:
customer = None

form = CustomerModelForm(data=request.POST or None, instance=customer)

if form.is_valid():
form.save()
return HttpResponseRedirect("/customer/added/")

return render_to_response("customers/customer_form.html", {'form' : form }



We are using one form class for editing & creating objects.
We can also subclass CustomerModelForm and edit/change the way the form looks
and behave (by adding field clean() method.

Django forms library looks better each day :-)

Monday, February 25, 2008

Some very usable django apps

I was looking for some easy to plug-in django apps
for my new service.

Here are some I decided to use:

django-tagging
django-registration
django-threadedcomments
django-voting

They seem to be rock stable, and easy to use.

Check back soon for more info about the new website.

Thursday, April 26, 2007

[EN] Django extending User, custom User methods

Django doesn't allow to subclass the User model yet.

Each Django model lets you easily create model methods.
Behind the scene, each django model has its own methods, f.e. save()
which saves the model data into the database.

Django provides the lightweight User framework in "django/contrib/auth/",
where "User" model is defined with fields:

username, password, is_staff, first_name, last_name, email, date_joined, last_login,
is_superuser, is_active

What if we need the user model with additional data like: age, location ?

The answer is: "extending the User model" by creating a new model
and linking it with "User" model via ForeignKey.

Example:

from django.contrib.auth.models import User

class Userprofile(models.Model):
user = models.ForeignKey(User, unique=True)
age = models.IntegerField()
location = models.CharField(maxlength="100", verbose_name"Country")


To create a new user, django comes with a special "create_user" method.
user = User.objects.create_user('robert', 'rsome@email', 'somepassword')
user.save()


You could do this also using the standard model create like:
user = User(username='someusername', is_active=True, email='some@email', first_name='john', last_name='doe')
user.save()
user.set_password('somepassword')
user.save()


As we have a new User record, to create a new "linked" UserProfile you would:
user = User.objects.get(name='someusername')
user.userprofile_set.create(age=22, location='Poland')


Django will automagically create the new UserProfile with "user" ForeignKey pointing
to the right User instance. Cool !

Question! How do I work on two separated models? Do I need to grab the UserProfile
instance for each request.user I operate in my views ?

Answer: Normally, you woule have to use the code below:
userprofile = Userprofile.objects.get(user=request.user)


Django comes with a special settings.py variable "AUTH_PROFILE_MODULE' which should point to your Userprofile model.

Example:
AUTH_PROFILE_MODULE = 'yourapp.Userprofile'

which lets you easily get into the "UserProfile" by using the "get_profile()" method.

Example: (in your either views.py or template):

location = request.user.get_profile().location
{{ user.get_profile.location }}

Note:
user_profile() does not only allows you to get the model data.
It allows you to get the model methods as well.

Example:

class Userprofile(models.Model):
user = models.ForeignKey(User, unique=True)
age = models.IntegerField()
location = models.CharField(maxlength="100")

def __str__(self):
return self.location

def is_of_age(self):
if self.age < 18:
return False
else:
return True


This lets you do some conditioning in your views:
if request.user.get_profile().is_of_age():
print "Yes, I will sell you this beer"



Delicious!

Another +1 for Django !

Links for reading:
http://www.djangoproject.com/documentation/authentication/

Wednesday, April 25, 2007

[EN] Django model managers, Do Not Repeat Yourself !

I've recently come up with a great django feature "model Managers".

Each django model has it's own manager class, which can be overriden by your custom class.

Let's say there's a model containing fields:

class Person(models.Model):
name = models.CharField(maxlength="100", blank=False, verbose_name="Your name")
age = models.IntegerField(verbose_name="Your age")

def __str__(self):
return self.name



You need to use this model in many places, and you need to select people by age and mark
them as child, teen, older.

Each time you select them you would need to crate a queryset like:

children = Person.objects.filter(age__lt=13)
teen = Person.objects.filter(age__gte=13).filter(age__lt=18)
older = Person.objects.filter(age__gte=18)


Anytime you use this function, you would need to write the filter statements.

Thanks to model managers, you can do it once, and use it in your code anywhere.

class PersonManager(models.Manager):
def get_children(self):
return self.filter(age__lt=13)
def get_teens(self):
return self.filter(age__ge=13).filter(age_lt=18)
def get_olders(self):
return self.filter(age__gte=18)


and put:
objects = PersonManger() in your model class so the class looks like:

from django.db import models

class Person(models.Model):
name = models.CharField(maxlength="100", blank=False, verbose_name="Your name")
age = models.IntegerField(verbose_name="Your age")

objects = PersonManger()

def __str__(self):
return self.name


To select teens, you can use: Person.objects.get_teens().
You can use any standard queryset options like .filter, .exclude etc, for example:

To get teens, with name not starting with "s".
Person.objects.get_teens.exclude(name__startswith: "s")

Also, you can change parameters for model managers functions.

Let's say you want to select teens, olders, children with name starting with some letter.

Modify your model manager functions, so they look like (I will modify just the one here).

def get_teens(self, name_filter_letter=None):
if name_filter_letter is None:
return self.filter(age__ge=13, age_lt=18)
else:
return self.filter(age__ge=13).filter(age__lt=18).filter(name__startswith=name_filter_letter)


And use it like:
Person.objects.get_teens("s")

Custom managers can do many other things, they are a standard python methods.

Note that you don't need to use the name:
objects = PersonManager()

You can use your own name as well:
persons = PersonManager()

which results in:
Person.persons.get_teens()

One more thing:
You can go deeply and override the models.Manager get_query_set() method, for example:

You want to grab teens from the model:

Create model subclass like:

class PersonTeensManager(models.Manager):
def get_query_set(self):
return super(PersonTeensManager, self).get_query_set().filter(age__lt=18).filter(age__gte=3)


and put:

teens = PersonTeensManager() in your model class.

In your views, use the queryset:

teens = Person.teens.all()

Isn't that simple?!

For more documentation take a look here:
http://www.djangoproject.com/documentation/models/custom_managers/
http://www.djangoproject.com/documentation/models/get_object_or_404/