Відмінності між версіями «Django FAQ»

Матеріал з Wiki Welard
Перейти до навігації Перейти до пошуку
Рядок 269: Рядок 269:
 
== Тестовий поштовий сервер ==
 
== Тестовий поштовий сервер ==
 
  python -m smtpd -n -c DebuggingServer localhost:1025
 
  python -m smtpd -n -c DebuggingServer localhost:1025
 +
 +
== Робота з великими об'ємами даних ==
 +
  1. MyModel.objects.all() – швидкий, для малих об'ємів
 +
  2. MyModel.objects.all().iterator() – середній, для великих об'ємів
 +
  3. queryset_iterator(MyModel.objects.all()) – повільний, для монстрів
 +
 +
<pre>
 +
import gc
 +
 +
def queryset_iterator(queryset, chunksize=1000):
 +
    '''''
 +
    Iterate over a Django Queryset ordered by the primary key
 +
 +
    This method loads a maximum of chunksize (default: 1000) rows in it's
 +
    memory at the same time while django normally would load all rows in it's
 +
    memory. Using the iterator() method only causes it to not preload all the
 +
    classes.
 +
 +
    Note that the implementation of the iterator does not support ordered query sets.
 +
    '''
 +
    pk = 0
 +
    last_pk = queryset.order_by('-pk')[0].pk
 +
    queryset = queryset.order_by('pk')
 +
    while pk < last_pk:
 +
        for row in queryset.filter(pk__gt=pk)[:chunksize]:
 +
            pk = row.pk
 +
            yield row
 +
        gc.collect()
 +
</pre>

Версія за 23:11, 21 жовтня 2010

Основні команди та нюанси при роботі з системою Django

django-admin.py startproject mysite
python manage.py startapp books
python manage.py validate
python manage.py sqlall books
python manage.py syncdb
python manage.py inspectdb

Модуль для роботи із зображеннями

http://www.pythonware.com/products/pil/ 

Створення бази даних

create database exam2 charset=utf8;
ALTER DATABASE exam2 DEFAULT CHARACTER SET 'utf8'

Циклічний перебір

{% cycle 'row1' 'row2' %} 

Перегрупування в шаблоні

     {% regroup people by gender as gender_list %}
     {% regroup people|dictsort:"gender" by gender as gender_list %}
     <ul>
     {% for gender in gender_list %}
        <li>{{ gender.grouper }}
        <ul>
            {% for item in gender.list %}
            <li>{{ item.first_name }} {{ item.last_name }}</li>
            {% endfor %}
        </ul>
        </li>
     {% endfor %}
     </ul>

Шаблон форми

<form method="post" action="">
<dl>
{% for field in form %}
    <dt>{{ field.label_tag }}{% if field.field.required %}*{% endif %}</dt>
    <dd>{{ field }}</dd>
    {% if field.help_text %}<dd>{{ field.help_text }}</dd>{% endif %}
    {% if field.errors %}<dd class="myerrors">{{ field.errors }}</dd>{% endif %}
{% endfor %}
</dl>
<input type="submit" />
</form>

Робота з формою в views.py

instance = Instance(required_field='value')
form = InstanceForm(request.POST, instance=instance)
new_instance = form.save()
instance = form.save(commit=False)
instance.required_field = 'new value'
new_instance = instance.save()

Збереження в змінній форми

allNodes = Form.serialize("myform");

Профілі користувачів

in settings.py:
AUTH_PROFILE_MODULE = 'projectname.UserProfile'

в інших відповідних файлах

class UserProfile(models.Model):
    user = models.OneToOneField(User, related_name='%(class)s', primary_key=True)
from django.contrib.auth.models import User
u = User.objects.get(username='test')
user_profile = u.profile.get()

Pagination - розбиття на сторінки

from django.core.paginator import Paginator
objects = ['john', 'paul', 'george', 'ringo']
p = Paginator(objects, 2)
page1 = p.page(1)
page1.object_list

Багатомовність

   django-admin.py makemessages -l uk
   django-admin.py compilemessages

Групування в SQL

qs = Schedule.objects.select_related().filter(pub_date__gte=datetime.now())
qs.query.group_by = ['country_id'] #!!!!!!
return {'schedule': qs}
   >>> qs = TumbleItem.objects.all()
   >>> qs.query.group_by = ['item_type']
   >>> qs.query.having = ['COUNT(item_type) > 1']
   >>> item_types = [i.item_type for i in qs]
   >>> item_types

Дописування методів в адмінку

   def remove(self):
       from django.core.urlresolvers import reverse
       return '<a href="%s" class="deletelink">Delete</a>' % reverse( "django.contrib.admin.views.main.delete_stage",
           args = ( self.__class__._meta.app_label, self.__class__.__name__.lower(), self._get_pk_val(), ) )
   remove.allow_tags = True

Приклад WSGI

sys.stdout = sys.stderr
import os, sys
sys.path.append('/usr/lib/python2.4/site-packages/django')
sys.path.append('/var/www/paradise/paradise')
sys.path.append('/var/www/paradise')
os.environ['DJANGO_SETTINGS_MODULE'] = 'paradise.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

Профілі користувачів

from django.contrib import admin
from profile.models import UserProfile
from django.contrib.auth.models import User
class ProfileInline(admin.StackedInline):
    model = UserProfile
    extra = 1
    max_num = 1
class ProfileAdmin(admin.ModelAdmin):
    inlines = (ProfileInline,)
    admin.site.unregister(User)  #!!!
    admin.site.register(User, ProfileAdmin)

Профілі 2

from django.contrib.auth.models import User
User.add_to_class('department',models.CharField(max_length=250,blank=True))
User.add_to_class('position',models.CharField(max_length=250,blank=True))
User._meta.admin.fields += (('Custom', {'fields': ('department','position',)}),)
User._meta.admin.list_display += ('department','position',)
def get_user_name(self):
    if self.first_name or self.last_name:
        return self.first_name + " " + self.last_name
    return self.username
User.add_to_class("get_user_name",get_user_name)

Якщо є яйця в пітоні

/etc/sysconfig/httpd
export PYTHON_EGG_CACHE="/var/cache/python-eggs" 

Кеш в Апачі

добавити в апач конфігурацію

<IfModule mod_expires.c>
    <FilesMatch "\.(jpg|gif|png|css|js)$">
         ExpiresActive on
         ExpiresDefault "access plus 3 days"
    </FilesMatch>
</IfModule>

Кеш в Django

from django.views.decorators.cache import cache_page
....
@cache_page(60 * 15)
def show_page(request, url=None, page_num=0):
    ....
    ....

у файлі admin.py:

from django.core.cache import cache
from django.conf import settings
....     
def save_model(self, request, obj, form, change):
    #cache.delete('views.decorators.cache.cache_header.%s./%s/' % (settings.CACHE_MIDDLEWARE_KEY_PREFIX, obj.url))
    cache._cache.flush_all() # ось так для memcache!!! 
    obj.save()

Корзина

def delete(self, trash=True):
    if not self.trashed_at and trash:
        self.trashed_at = datetime.now()
        self.save()
    else:
        super(SomeModel, self).delete()

Використання unordered_list

['States', ['Kansas', ['Lawrence', 'Topeka'], 'Illinois']], then {{ var|unordered_list }} would return:
<li>States
<ul>
        <li>Kansas
        <ul>
                <li>Lawrence</li>
                <li>Topeka</li>
        </ul>
        </li>
        <li>Illinois</li>
</ul>
</li>

Використання календаря

class EventSplitDateTime(forms.SplitDateTimeWidget):
    def __init__(self, attrs=None):
        widgets = [forms.TextInput(attrs={'class': 'vDateField'}), 
                   forms.TextInput(attrs={'class': 'vTimeField'})]
        # Note that we're calling MultiWidget, not SplitDateTimeWidget, because
        # we want to define widgets.
        forms.MultiWidget.__init__(self, widgets, attrs)

    def format_output(self, rendered_widgets):
        return mark_safe(u'%s<br />%s' % (rendered_widgets[0], rendered_widgets[1]))

class EventForm(forms.Form):
    start = forms.DateTimeField(label=ugettext("Start"), widget=EventSplitDateTime())
    end = forms.DateTimeField(label=ugettext("End"), widget=EventSplitDateTime())

Рестарт WSGI без апача

@never_cache
def restart(request):
    ''' Перезапуск демона '''
    if request.META['mod_wsgi.process_group'] != '':
        import signal, os
        os.kill(os.getpid(), signal.SIGINT)
        ret = 'restarted'
    else:
        ret = 'not find porcess_group'
        
    return HttpResponse(ret, mimetype='text/plain')

Фільтрація в моделі в зовнішньому ключі

models.ForeignKey(Test, limit_choices_to = {'pub_date__lte': datetime.now})

Django & Cron

# -*- coding: utf-8 -*-
import sys
import settings
from django.core.management import setup_environ
setup_environ(settings)
module_name = sys.argv[1]
exec('import %s' % module_name)
exec('%s.%s' % (module_name, ' '.join(sys.argv[2:])))

И теперь при помощи этого скрипта мы можем вызывать функции наших “вьюшек” из командной строки и из cron:

# python /path/to/project/run.py report.views "send_emails()"

Багато з'єднань з базою

from django.db import load_backend
myBackend = load_backend('postgresql_psycopg2') # or 'mysql', 'sqlite3', 'oracle'
myConnection = myBackend.DatabaseWrapper({
    'DATABASE_HOST': '192.168.1.1',
    'DATABASE_NAME': 'my_database',
    'DATABASE_OPTIONS': {},
    'DATABASE_PASSWORD': "",
    'DATABASE_PORT': "",
    'DATABASE_USER': "my_user",
    'TIME_ZONE': "America/New_York",})
# Now we can do all the standard raw sql stuff with myConnection.
myCursor = myConnection.cursor()
myCursor.execute("SELECT COUNT(1) FROM my_table;")
myCursor.fetchone()

Автоматична перегрузка коду (для Apache)

в конфіг добавляємо

WSGIScriptReloading On
WSGIReloadMechanism Process
$ touch my_project.wsgi

Доступ до url адмінки

from django.core import urlresolvers
url = urlresolvers.reverse('admin:mysite_product_change', args=(obj.id,))

Фільтрація по датам

extra_data = {"d": "date(created)"}
result = MyModel.objects.extra(extra_data).values('d').annotate(cnt=Count('pk')).order_by()

RAW SQL

authors = Author.objects.raw("SELECT *, age(birth_date) as age FROM library_authors")
for author in authors:
    print "%s is %s." % (author.first_name, author.age)

Тестовий поштовий сервер

python -m smtpd -n -c DebuggingServer localhost:1025

Робота з великими об'ємами даних

  1. MyModel.objects.all() – швидкий, для малих об'ємів
  2. MyModel.objects.all().iterator() – середній, для великих об'ємів 
  3. queryset_iterator(MyModel.objects.all()) – повільний, для монстрів
import gc

def queryset_iterator(queryset, chunksize=1000):
    '''''
    Iterate over a Django Queryset ordered by the primary key

    This method loads a maximum of chunksize (default: 1000) rows in it's
    memory at the same time while django normally would load all rows in it's
    memory. Using the iterator() method only causes it to not preload all the
    classes.

    Note that the implementation of the iterator does not support ordered query sets.
    '''
    pk = 0
    last_pk = queryset.order_by('-pk')[0].pk
    queryset = queryset.order_by('pk')
    while pk < last_pk:
        for row in queryset.filter(pk__gt=pk)[:chunksize]:
            pk = row.pk
            yield row
        gc.collect()