Любимые советы и особенности Django?

324

Вдохновленный серией вопросов "Скрытые черты...", мне любопытно узнать о ваших любимых советах Django или менее известных, но полезных функциях, о которых вы знаете.

  • Пожалуйста, укажите только один отзыв для каждого ответа.
  • Добавьте требования к версии Django, если они есть.
Теги:
hidden-features

55 ответов

211

Я собираюсь начать с подсказки от себя:)

Используйте os.path.dirname() в settings.py, чтобы избежать жестких кодировок dirnames.

Не указывайте путь hardcode в параметрах settings.py, если вы хотите запустить проект в разных местах. Используйте следующий код в settings.py, если ваши шаблоны и статические файлы находятся в каталоге проекта Django:

# settings.py
import os
PROJECT_DIR = os.path.dirname(__file__)
...
STATIC_DOC_ROOT = os.path.join(PROJECT_DIR, "static")
...
TEMPLATE_DIRS = (
    os.path.join(PROJECT_DIR, "templates"),
)

Кредиты: я получил этот совет от screencast 'Django From the Ground Up'.

  • 0
    Хм, я никогда не думал об этом ... обычно я обесцениваю людей, которые отвечают на их собственные вопросы, но этот на самом деле полезен.
  • 75
    Вы не должны понижать голос людей, которые отвечают на их собственные вопросы. Это поощряется, даже если это предопределено.
Показать ещё 16 комментариев
130

Установите Django Command Extensions и pygraphviz и затем выполните следующую команду, чтобы получить действительно приятную визуализацию модели Django:

./manage.py graph_models -a -g -o my_project.png
  • 0
    Хорошо, не удалось заставить pygraphviz правильно установить в Windows, но он все еще может скрыться от точечного файла, используя graphviz.
  • 0
    Самое холодное время. Совет. Evar. :)
Показать ещё 3 комментария
114

Используйте django-annoying render_to decorator вместо render_to_response.

@render_to('template.html')
def foo(request):
    bars = Bar.objects.all()
    if request.user.is_authenticated():
        return HttpResponseRedirect("/some/url/")
    else:
        return {'bars': bars}

# equals to
def foo(request):
    bars = Bar.objects.all()
    if request.user.is_authenticated():
        return HttpResponseRedirect("/some/url/")
    else:
        return render_to_response('template.html',
                              {'bars': bars},
                              context_instance=RequestContext(request))

Отредактировано, чтобы указать, что возврат HttpResponse (например, перенаправление) приведет к короткому замыканию декоратора и работе так, как вы ожидаете.

  • 0
    Интересно. Благодарю.
  • 0
    Как вы передаете контекст запроса?
Показать ещё 12 комментариев
103

Есть набор пользовательских тегов, которые я использую по всем шаблонам своего сайта. Ищете способ автозагрузки (DRY, помните?), Я нашел следующее:

from django import template
template.add_to_builtins('project.app.templatetags.custom_tag_module')

Если вы поместите это в модуль, загруженный по умолчанию (например, ваш основной urlconf), у вас будут теги и фильтры из вашего настраиваемого модуля тегов, доступных в любом шаблоне, без использования {% load custom_tag_module %}.

Аргумент, передаваемый в template.add_to_builtins(), может быть любым путем к модулю; ваш пользовательский модуль тегов не должен жить в конкретном приложении. Например, он также может быть модулем в корневом каталоге проекта (например, 'project.custom_tag_module').

  • 0
    @ Stef, вы только что сэкономили мне кучу времени / душевной боли / байтов, спасибо.
  • 0
    Действительно мило. Благодарю. Кроме того, хранилище пользовательских тегов было бы замечательно, чтобы поделиться вещами, не так ли?
Показать ещё 2 комментария
93

Virtualenv + Python = спасатель жизни, если вы работаете над несколькими проектами Django, и есть вероятность, что все они не зависят от той же версии приложения Django/.

  • 15
    Это ТОЛЬКО способ катиться!
  • 0
    да, единственный способ
Показать ещё 2 комментария
84

Не перекодируйте URL-адреса!

Используйте имена URL, а reverse для получения самого URL.

Когда вы определяете свои сопоставления URL-адресов, укажите имена для своих URL-адресов.

urlpatterns += ('project.application.views'
   url( r'^something/$', 'view_function', name="url-name" ),
   ....
)

Убедитесь, что имя уникально для каждого URL.

Я обычно имею согласованный формат "представление проекта-приложения", например. "cbx-forum-thread" для представления потока.

ОБНОВЛЕНИЕ (бесстыдно украсть дополнение ayaz):

Это имя можно использовать в шаблонах с тегом url.

  • 1
    Я согласен на 100% по этому вопросу. Я начал использовать жестко запрограммированные URL-адреса, и это отразилось на моем проекте, когда я немного изменил формат URL-адреса, чтобы учесть некоторые изменения. Я нашел время, чтобы вернуться и копаться во всем и заменить жестко закодированные URL-адреса. Моя единственная большая жалоба заключается в том, что ошибки URL-тегов убивают всю страницу, а жестко запрограммированные только портят индивидуальную ссылку.
  • 21
    Это не должно быть скрытой функцией, это лучшая практика и единственный способ летать.
Показать ещё 4 комментария
80

Не записывайте свои собственные страницы входа. Если вы используете django.contrib.auth.

Настоящий грязный секрет заключается в том, что если вы также используете django.contrib.admin, а django.template.loaders.app_directories.load_template_source находится в ваших загрузчиках шаблонов, , вы также можете получить свои шаблоны!

# somewhere in urls.py
urlpatterns += patterns('django.contrib.auth',
    (r'^accounts/login/$','views.login', {'template_name': 'admin/login.html'}),
    (r'^accounts/logout/$','views.logout'),
)
  • 1
    Здорово! Я не знал, что мы можем повторно использовать страницу входа администратора. Спасибо!
78

Используйте панель инструментов отладки django. Например, он позволяет просматривать все SQL-запросы, выполняемые во время рендеринга, и вы также можете просматривать stacktrace для любого из них.

  • 10
    Который сейчас находится на github.com/robhudson/django-debug-toolbar
  • 0
    ЛЮБОВЬ django-debug-toolbar
70

Контекстные процессоры являются удивительными.

Скажем, у вас есть другая модель пользователя, и вы хотите включить что в каждом ответе. Вместо этого:

def myview(request, arg, arg2=None, template='my/template.html'):
    ''' My view... '''
    response = dict()
    myuser = MyUser.objects.get(user=request.user)
    response['my_user'] = myuser
    ...
    return render_to_response(template,
                              response,
                              context_instance=RequestContext(request))

Контекстные процессы дают вам возможность передавать любую переменную в вашу шаблоны. Обычно я помещаю мой в 'my_project/apps/core/context.py:

def my_context(request):
    try:
        return dict(my_user=MyUser.objects.get(user=request.user))
    except ObjectNotFound:
        return dict(my_user='')

В settings.py добавьте следующую строку в TEMPLATE_CONTEXT_PROCESSORS

TEMPLATE_CONTEXT_PROCESSORS = (
    'my_project.apps.core.context.my_context',
    ...
)

Теперь каждый раз, когда запрос выполняется, он автоматически включает ключ my_user.

Также signals win.

Я написал сообщение в блоге об этом несколько месяцев назад, поэтому я просто собираюсь вырезать и вставить:

Из коробки Django дает вам несколько сигналов, которые невероятно полезно. У вас есть возможность делать что-то заранее и после сохранения, инициализации, удаления или даже когда запрос обработанный. Так что давайте уйти от концепций и продемонстрируйте, как они используются. Скажем, у нас есть блог

from django.utils.translation import ugettext_lazy as _
class Post(models.Model):
    title = models.CharField(_('title'), max_length=255)
    body = models.TextField(_('body'))
    created = models.DateTimeField(auto_now_add=True)

Итак, так или иначе вы хотите уведомить одного из многих блогов услуги weve создали новую должность, перестроят самые последние кеши сообщений и твит. Хорошо с сигналами, которые у вас есть способность делать все это без необходимости добавлять методы для класса Post.

import twitter

from django.core.cache import cache
from django.db.models.signals import post_save
from django.conf import settings

def posted_blog(sender, created=None, instance=None, **kwargs):
    ''' Listens for a blog post to save and alerts some services. '''
    if (created and instance is not None):
        tweet = 'New blog post! %s' instance.title
        t = twitter.PostUpdate(settings.TWITTER_USER,
                               settings.TWITTER_PASSWD,
                               tweet)
        cache.set(instance.cache_key, instance, 60*5)
       # send pingbacks
       # ...
       # whatever else
    else:
        cache.delete(instance.cache_key)
post_save.connect(posted_blog, sender=Post)

Здесь мы идем, определяя эту функцию и используя post_init для подключения функции к модели Post и выполнить его после его сохранения.

  • 4
    Сигналы Django являются обязательной функцией для меня в наши дни при сравнении веб-фреймворков. Скажем, писать слабо связанный форум, который может прослушивать обновления, скажем, из модуля «подпись», но на самом деле не требует, чтобы этот модуль работал, и который также может работать с совместимыми модулями, реализующими ту же функцию. Я не знаю, почему сигналы не так известны и популярны.
  • 0
    все виды развлечений с сигналами: code.google.com/p/django-badges
Показать ещё 5 комментариев
59

Когда я начинал, я не знал, что существует Paginator, убедитесь, что вы знаете о его существовании!!

  • 2
    : D это же для меня! Я провел дни на нумерацию страниц!
49

Используйте IPython, чтобы перейти на ваш код на любом уровне и отлаживать с использованием мощности IPython. После того, как вы установили IPython, просто поместите этот код туда, куда вы хотите отлаживать:

from IPython.Shell import IPShellEmbed; IPShellEmbed()()

Затем обновите страницу, перейдите в окно вашего запуска и вы будете в интерактивном окне IPython.

У меня есть фрагмент, созданный в TextMate, поэтому я просто набираю ipshell и нажимаю вкладку. Я не мог жить без него.

  • 22
    Лучше установить ipdb а затем просто набрать ipdb.set_trace()
  • 0
    Или используйте отладчик Eclipse / PyDev. :-)
Показать ещё 1 комментарий
42

Функция ./manage.py runserver_plus, которая поставляется с django_extensions, действительно потрясающая.

Он создает расширенную страницу отладки, которая, помимо прочего, использует отладчик Werkzeug для создания интерактивных консолей отладки для каждой точки в стеке (см. снимок экрана). Он также предоставляет очень полезный метод удобной отладки dump() для отображения информации об объекте/кадре.

Изображение 921

Чтобы установить, вы можете использовать pip:

pip install django_extensions
pip install Werkzeug

Затем добавьте 'django_extensions' в тэг INSTALLED_APPS в settings.py и запустите сервер разработки с новым расширением:

./manage.py runserver_plus

Это изменит способ отладки.

41

Запустите SMTP-сервер разработки, который просто выведет все, что ему отправлено (если вы не хотите фактически устанавливать SMTP на своем dev-сервере.)

:

python -m smtpd -n -c DebuggingServer localhost:1025
  • 12
    вы можете использовать консоль и файл электронной почты в django 1.2 для той же цели
  • 0
    выдающийся! идеально подходит для регистрации! +1
Показать ещё 1 комментарий
39

Из документация django-admin:

Если вы используете оболочку Bash, рассмотрите возможность установки завершения Django Bash script, который находится в extras/django_bash_completion в дистрибутиве Django. Он позволяет выполнять табуляцию команд django-admin.py и manage.py, поэтому вы можете, например...

  • Введите django-admin.py.
  • Нажмите [TAB], чтобы просмотреть все доступные параметры.
  • Введите sql, затем [TAB], чтобы просмотреть все доступные параметры, чьи имена начинаются с sql.
  • 1
    Это более полезно, чем я ожидал. Спасибо!
  • 0
    Это по умолчанию в более новых Ubuntu по крайней мере. :-) Я был поражен, когда он впервые появился из ниоткуда.
Показать ещё 1 комментарий
38

При попытке обмена данными между Django и другим приложением request.raw_post_data является хорошим другом. Используйте его для получения и пользовательского процесса, скажем, данных XML.

Документация: http://docs.djangoproject.com/en/dev/ref/request-response/

  • 5
    Вот как ты это делаешь. Спасибо +1
37

Мне нравится использовать pdon debugger pdb для отладки проектов Django.

Это полезная ссылка для изучения того, как ее использовать: http://www.ferg.org/papers/debugging_in_python.html

  • 13
    Это находка. Чтобы дать немного больше информации, просто добавьте это: «import pdb; pdb.set_trace ()» в любой строке вашего кода. Обновите свою страницу. Это будет висеть. Теперь перейдите в окно терминала, где вы запускаете сервер разработки. Теперь это должна быть интерактивная оболочка, в которой вы можете получить доступ ко всем переменным в том виде, в каком они находятся в той точке кода, куда вы вставили код отладки.
  • 0
    winpdb предоставляет вам отладчик с графическим интерфейсом: winpdb.org
Показать ещё 1 комментарий
34

Добавьте assert False в свой код просмотра для вывода информации об отладке.

  • 33
    Или просто введите случайное дерьмо и винт синтаксис! ;)
  • 4
    Я думаю, что утверждать Ложь является более интуитивным = D
Показать ещё 7 комментариев
34

Используйте Jinja2 рядом с Django.

Если вы находите язык шаблона Django чрезвычайно ограниченным (например, я!), вам не нужно зацикливаться на нем. Django является гибким, а язык шаблонов слабо связан с остальной частью системы, поэтому просто подключайте другой язык шаблона и используйте его для отображения ваших ответов на http!

Я использую Jinja2, это почти похоже на включенную версию языка шаблонов django, он использует тот же синтаксис и позволяет вам использовать выражения в операторах if! больше не создавать пользовательские теги if, такие как if_item_in_list! вы можете просто сказать %{ if item in list %} или {% if object.field < 10 %}.

Но это не все; у него есть еще много возможностей для облегчения создания шаблонов, которые я не могу выполнить, хотя все они здесь.

  • 0
    Я также использую Jinja2 и наслаждаюсь им, но обнаружил, что есть некоторые связи с приложениями «contrib». В частности, инструмент администратора довольно сильно привязан к шаблонам Django. Кроме того, мне пришлось воссоздать декораторы входа в contrib.auth, чтобы быть дружелюбным к Jinja2, но не слишком сложно.
  • 24
    Не заменяйте систему шаблонов на jinja2, просто «добавьте» ее, не удаляйте шаблоны django. Используйте Jinja2 для своих собственных представлений и позвольте интерфейсу администратора продолжать использовать язык шаблонов django.
Показать ещё 4 комментария
33

Это добавляет ответ выше о именах URL-адресов Django и обратном URL-адресе.

Имена URL также могут быть эффективно использованы в шаблонах. Например, для заданного шаблона URL:

url(r'(?P<project_id>\d+)/team/$', 'project_team', name='project_team')

у вас могут быть следующие шаблоны:

<a href="{% url project_team project.id %}">Team</a>
27

Поскольку Django "представления" должны быть только вызывающими, которые возвращают HttpResponse, вы можете легко создавать представления на основе классов, такие как в Ruby on Rails и других средах.

Существует несколько способов создания представлений на основе классов, здесь мой любимый:

from django import http

class RestView(object):
    methods = ('GET', 'HEAD')

    @classmethod
    def dispatch(cls, request, *args, **kwargs):
        resource = cls()
        if request.method.lower() not in (method.lower() for method in resource.methods):
            return http.HttpResponseNotAllowed(resource.methods)
        try:
            method = getattr(resource, request.method.lower())
        except AttributeError:
            raise Exception("View method `%s` does not exist." % request.method.lower())
        if not callable(method):
            raise Exception("View method `%s` is not callable." % request.method.lower())
        return method(request, *args, **kwargs)

    def get(self, request, *args, **kwargs):
        return http.HttpResponse()

    def head(self, request, *args, **kwargs):
        response = self.get(request, *args, **kwargs)
        response.content = ''
        return response

В базовом представлении вы можете добавить все виды других вещей, таких как обработка условных запросов и авторизация.

После того, как вы настроите свои настройки, urls.py будет выглядеть примерно так:

from django.conf.urls.defaults import *
from views import MyRestView

urlpatterns = patterns('',
    (r'^restview/', MyRestView.dispatch),
)
  • 2
    Кстати, авторы django фактически используют представления на основе классов в нескольких местах, например, contrib.formtools: code.djangoproject.com/browser/django/trunk/django/contrib/…
  • 3
    Если вы добавите метод вызова, вы можете создать класс RestfulResource, а затем указать свой urls.py на экземпляры.
Показать ещё 1 комментарий
23

Вместо того, чтобы использовать render_to_response для привязки вашего контекста к шаблону и его рендеринга (что обычно показывают документы Django), используйте общий вид direct_to_template. Он делает то же самое, что и render_to_response, но также автоматически добавляет RequestContext в контекст шаблона, неявно позволяя использовать контекстные процессоры. Вы можете сделать это вручную, используя render_to_response, но зачем беспокоиться? Это еще один шаг к запоминанию и еще один LOC. Помимо использования контекстных процессоров, наличие RequestContext в вашем шаблоне позволяет вам делать такие вещи, как:

<a href="{{MEDIA_URL}}images/frog.jpg">A frog</a> 

что очень полезно. На самом деле +1 на общих представлениях вообще. Документы Django в основном показывают их как ярлыки для того, чтобы даже не иметь файл views.py для простых приложений, но вы также можете использовать их внутри своих собственных функций просмотра:

from django.views.generic import simple

def article_detail(request, slug=None):
    article = get_object_or_404(Article, slug=slug)
    return simple.direct_to_template(request, 
        template="articles/article_detail.html",
        extra_context={'article': article}
    )
19

Всем известно, что есть сервер разработки, который вы можете запускать с помощью "manage.py runningerver", но знаете ли вы, что существует также представление для обслуживания статических файлов (CSS/JS/IMG)?

Новички всегда недоумевают, потому что Django не имеет возможности обслуживать статические файлы. Это объясняется тем, что команда разработчиков считает, что это работа для веб-сервера реальной жизни.

Но при разработке вы можете не захотеть настроить Apache + mod_wisgi, это тяжело. Затем вы можете добавить следующее в urls.py:

(r'^site_media/(?P<path>.*)$', 'django.views.static.serve',
        {'document_root': '/path/to/media'}),

Ваш CSS/JS/IMG будет доступен на www.yoursite.com/site_media/.

Конечно, не используйте его в рабочей среде.

  • 6
    Я использую это в режиме разработки, и просто чтобы убедиться, что я не забуду отключить это в рабочей среде, я оборачиваю это правило URL только в DEBUG.
19

У меня недостаточно репутации для ответа на комментарий, но важно отметить, что если вы собираетесь использовать Jinja, он НЕ поддерживает символ "-" в именах блоков шаблонов, в то время как Django делает это. Это вызвало у меня много проблем и потрачено время, пытаясь отследить очень неясное сообщение об ошибке, которое оно сгенерировало.

  • 0
    Одно примечание, которое может или не может быть применимо к "непонятным сообщениям об ошибках от jinja". Обязательно установите TEMPLATE_DEBUG = False в settings.py. По какой-то причине это даст вам значимые ошибки из шаблонов Jinja.
19

приложение для веб-дизайна очень полезно при создании вашего сайта. После импорта вы можете добавить это, чтобы сгенерировать образец текста:

{% load webdesign %}
{% lorem 5 p %}
  • 4
    К вашему сведению, для любого, кто использует Jinja2 вместо шаблонов Django, вы можете сделать: {{lipsum (5)}}
19

django.db.models.get_model позволяет вам получить модель без импорта.

Джеймс показывает, насколько это удобно: "Советы Django: напишите лучшие теги шаблона - итерация 4" .

  • 0
    Приятно: O! И здесь я делал ленивый импорт, когда у меня были циклические зависимости.
18

Я узнал об этом из документации для sorl-thumbnails. Вы можете использовать ключевое слово "как" в тегах шаблонов, чтобы использовать результаты вызова в другом месте вашего шаблона.

Например:

{% url image-processor uid as img_src %}
<img src="{% thumbnail img_src 100x100 %}"/>

Об этом упоминается в документации Django templatetag, но только в отношении циклов. Они не называют, что вы можете использовать это в другом месте (где угодно?).

  • 7
    Если ключевое слово as можно использовать с шаблоном-тегом, зависит от этого конкретного тега. Он определяется не самим django, а отдельными тегами, в зависимости от их значения. Загляните в упомянутый URL-тег, чтобы увидеть, как используется «как»: code.djangoproject.com/browser/django/trunk/django/template/…
16

PyCharm IDE - хорошая среда для кодирования и особенно отладки со встроенной поддержкой Django.

16

django.views.generic.list_detail.object_list - Он предоставляет все логические и шаблонные переменные для разбивки на страницы (один из тех, ve-written-that-a-тысяч раз-теперь тяжелые). Обертка позволяет использовать любую логику. Этот жемчуг спас меня много часов отладки по отдельности на моих страницах "Результаты поиска" и делает код просмотра более чистым в этом процессе.

  • 1
    Вы можете найти новую версию главы книги об общих взглядах на djangobook.com/en/2.0/chapter11 . Тот, что в комментарии, относится к версии книги Django pre-1.0 (книга Django 1.0)
14

Использовать миграцию базы данных. Используйте South.

14

Используйте xml_models для создания моделей Django, которые используют бэкэнд API REST API (вместо SQL-кода). Это очень полезно, особенно при моделировании сторонних API-интерфейсов - вы получаете все тот же синтаксис QuerySet, к которому вы привыкли. Вы можете установить его из PyPI.

XML из API:

<profile id=4>
    <email>[email protected]</email>
    <first_name>Joe</first_name>
    <last_name>Example</last_name>
    <date_of_birth>1975-05-15</date_of_birth>
</profile>

И теперь в python:

class Profile(xml_models.Model):
    user_id = xml_models.IntField(xpath='/profile/@id')
    email = xml_models.CharField(xpath='/profile/email')
    first = xml_models.CharField(xpath='/profile/first_name')
    last = xml_models.CharField(xpath='/profile/last_name')
    birthday = xml_models.DateField(xpath='/profile/date_of_birth')

    finders = {
        (user_id,):  settings.API_URL +'/api/v1/profile/userid/%s',
        (email,):  settings.API_URL +'/api/v1/profile/email/%s',
    }

profile = Profile.objects.get(user_id=4)
print profile.email
# would print '[email protected]'

Он также может обрабатывать отношения и коллекции. Мы используем его каждый день в сильно используемом коде производства, поэтому, хотя он бета-версия очень удобна. Он также имеет хороший набор заглушек, которые вы можете использовать в своих тестах.

(Отказ от ответственности: пока я не являюсь автором этой библиотеки, теперь я являюсь коммиттером, совершив несколько мелких коммитов)

  • 0
    интересный проект, так держать!
  • 0
    Спасибо, это очень удобно :-)
13

Только что нашел эту ссылку: http://lincolnloop.com/django-best-practices/#table-of-contents - "Лучшие практики Django".

  • 0
    Интересный сайт, но все эти скачки страницы вверх и вниз заставляют меня съеживаться.
12

Если вы вносите изменения в модель

./manage.py dumpdata appname > appname_data.json  
./manage.py reset appname
django-admin.py loaddata appname_data.json
  • 1
    Я люблю этот трюк - это миграции бедного человека
  • 5
    Это подойдет, если ты работаешь один. Но если вы работаете в команде и / или имеете приспособления, которые не хотите модифицировать вручную, - тогда используйте Юг . Это правильный способ справиться с модификациями модели.
12

Вместо того, чтобы оценивать весь запрос, чтобы проверить, были ли вы получены какие-либо результаты, используйте .exists() в Django 1.2+ и .count() для предыдущих версий.

Both exists() и count() очищает порядок по предложениям и извлекает одно целое из DB. Однако exists() всегда будет возвращать 1, когда счетчик может возвращать более высокие значения, какие лимиты будут применяться вручную. Источник has_result, используемый в exists() и get_count, используемый в count() для любопытных.

Поскольку оба они возвращают одно целое число, нет экземпляра модели, загрузки атрибутов модели в памяти и больших текстовых полей, передаваемых между вашей БД и приложением.

Если вы уже оценили запрос,.count() вычисляет len (cached_result) и .exists() вычисляет bool (cached_result)

Неэффективно - Пример 1

books = Books.objects.filter(author__last_name='Brown')
if books:
    # Do something

Неэффективно - Пример 2

books = Books.objects.filter(author__last_name='Brown')
if len(books):
    # Do something

Эффективный - пример 1

books = Books.objects.filter(author__last_name='Brown')
if books.count():
    # Do something

Эффективный - пример 2

books = Books.objects.filter(author__last_name='Brown')
if books.exists():
    # Do something
  • 0
    Учитывая, что взаимодействие с БД является основой большинства приложений Django, даже незначительные улучшения, такие как это, имеют большое значение.
11

Удалить информацию о доступе к базе данных из settings.py

Одна вещь, которую я сделал на моем сайте Django settings.py, - это информация о доступе к базе данных загрузки из файла в /etc. Таким образом, настройка доступа (узел базы данных, порт, имя пользователя, пароль) может отличаться для каждой машины, а конфиденциальная информация, подобная паролю, отсутствует в моем репозитории проектов. Возможно, вы захотите ограничить доступ к работникам аналогичным образом, сделав их подключенными к другому имени пользователя.

Вы также можете передать информацию о подключении к базе данных или даже просто ключ или путь к файлу конфигурации через переменные среды и обрабатывать ее в settings.py.

Например, здесь, как я извлекаю файл конфигурации базы данных:

g = {}
dbSetup = {}
execfile(os.environ['DB_CONFIG'], g, dbSetup)
if 'databases' in dbSetup:
    DATABASES = dbSetup['databases']
else:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            # ...
        }
    }

Излишне говорить, что вам нужно убедиться, что файл в DB_CONFIG недоступен для любого пользователя, кроме админов db и самого Django. Случай по умолчанию должен относить Django к собственной тестовой базе данных разработчика. Также может быть лучшее решение, использующее модуль ast вместо execfile, но я еще не изучил его.

Еще одна вещь, которую я делаю, - это использовать отдельных пользователей для задач администрирования БД и всего остального. В моем manage.py я добавил следующую преамбулу:

# Find a database configuration, if there is one, and set it in the environment.
adminDBConfFile = '/etc/django/db_admin.py'
dbConfFile = '/etc/django/db_regular.py'
import sys
import os
def goodFile(path):
    return os.path.isfile(path) and os.access(path, os.R_OK)
if len(sys.argv) >= 2 and sys.argv[1] in ["syncdb", "dbshell", "migrate"] \
    and goodFile(adminDBConfFile):
    os.environ['DB_CONFIG'] = adminDBConfFile
elif goodFile(dbConfFile):
    os.environ['DB_CONFIG'] = dbConfFile

Где конфигурация в /etc/django/db_regular.py предназначена для пользователя с доступом только к базе данных Django с SELECT, INSERT, UPDATE и DELETE, а /etc/django/db_admin.py - для пользователя с этими разрешениями плюс CREATE, DROP, INDEX, ALTER, и LOCK TABLES. (Команда migrate от South.) Это дает мне некоторую защиту от jango-кода, который вовлекается в мою схему во время выполнения, и это ограничивает ущерб, который может вызвать атака SQL-инъекций (хотя вы все равно должны проверить и отфильтровать все входные данные пользователя).

(Скопирован из моего ответа на еще один вопрос)

11

Используйте signals, чтобы добавлять методы доступа на лету.

Я видел эту технику в django-photologue: для любого добавленного объекта размера сигнал post_init добавит соответствующие методы в модель изображения, Если вы добавите гигант сайта, методы для получения изображения с гигантским разрешением будут image.get_giant_url().

Методы генерируются вызовом add_accessor_methods из сигнала post_init:

def add_accessor_methods(self, *args, **kwargs):
    for size in PhotoSizeCache().sizes.keys():
        setattr(self, 'get_%s_size' % size,
                curry(self._get_SIZE_size, size=size))
        setattr(self, 'get_%s_photosize' % size,
                curry(self._get_SIZE_photosize, size=size))
        setattr(self, 'get_%s_url' % size,
                curry(self._get_SIZE_url, size=size))
        setattr(self, 'get_%s_filename' % size,
                curry(self._get_SIZE_filename, size=size))

Смотрите исходный код photologue.models для реального использования.

9

Вместо запуска сервера Django dev на localhost запустите его на соответствующем сетевом интерфейсе. Например:

python manage.py runserver 192.168.1.110:8000

или

python manage.py runserver 0.0.0.0:8000

Затем вы можете не только легко использовать Fiddler (http://www.fiddler2.com/fiddler2/) или другой инструмент, например HTTP Debugger (http://www.httpdebugger.com/), чтобы проверить ваши заголовки HTTP, но вы также можете получить доступ к своему сайту-разработчику с других компьютеров в локальной сети для тестирования.

Убедитесь, что вы защищены брандмауэром, хотя сервер dev минимален и относительно безопасен.

  • 0
    «Относительно» - хорошее слово, как только я выставил встроенные статические ресурсы, служащие внешнему слову, и пожалел об этом. Хотя технически это не связано с devserver, оно находится в одном и том же фрагменте кода - Django, поэтому я бы экстраполировал этот опыт и на devserver.
7

панель инструментов Django Debug - это действительно фантастика. На самом деле это не панель инструментов, она фактически отображает боковую панель, которая сообщает вам все виды информации о том, что принесло вам страницу, на которую вы смотрите - запросы к БД, переменные контекста, отправленные в шаблон, сигналы и т.д.

7

Используйте декоратор wraps в декоративных декораторах для сохранения имени, модуля и docstring. Например.

try:
    from functools import wraps
except ImportError:
    from django.utils.functional import wraps  # Python 2.3, 2.4 fallback.

def view_decorator(fun):
    @wraps(fun)
    def wrapper():
        # here goes your decorator code
    return wrapper

Остерегайтесь: не будет работать над представлениями класса (те, у которых определение метода __call__), если автор не определил свойство __name__. В качестве обходного пути используйте:

from django.utils.decorators import available_attrs
...
    @wraps(fun, assigned=available_attrs(fun))
6

Использование папки "apps" для организации ваших приложений без редактирования PYTHONPATH

Это пригодится, когда я хочу организовать свои папки следующим образом:

apps/
    foo/
    bar/
site/
settings.py
urls.py

без перезаписывания PYTHONPATH или добавления приложений для каждого импорта:

from apps.foo.model import *
from apps.bar.forms import *

В файле settings.py добавьте

import os
import sys
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, os.path.join(PROJECT_ROOT, "apps"))

и вы готовы к работе: -)

Я видел это на http://codespatter.com/2009/04/10/how-to-add-locations-to-python-path-for-reusable-django-apps/

5

Автоматически устанавливать атрибут "DEBUG" в рабочей среде (settings.py)

import socket

if socket.gethostname() == 'productionserver.com':
    DEBUG = False
else:
    DEBUG = True

По: http://nicksergeant.com/2008/automatically-setting-debug-in-your-django-app-based-on-server-hostname/

5

Используйте обратную ссылку в urlconf.

Это один из тех трюков, где я не понимаю, почему это не по умолчанию.

Здесь ссылка на то, где я ее поднял: http://andr.in/2009/11/21/calling-reverse-in-django/

Здесь фрагмент кода:

from django.conf.urls.defaults import *
from django.core.urlresolvers import reverse
from django.utils.functional import lazy
from django.http import HttpResponse

reverse_lazy = lazy(reverse, str)

urlpatterns = patterns('',
url(r'^comehere/', lambda request: HttpResponse('Welcome!'), name='comehere'),
url(r'^$', 'django.views.generic.simple.redirect_to',
{'url': reverse_lazy('comehere')}, name='root')
)
  • 4
    Что это значит и зачем мне это делать?
  • 1
    Обратное похоже на тег URL, который «возвращает абсолютный URL (т. Е. URL без имени домена), соответствующий заданной функции просмотра и необязательным параметрам». Я избегаю жесткого кода абсолютных URL. Когда я запускаю развертывание на веб-сервере, приложение может не быть корневой точкой монтирования, поэтому на тестовом сервере может работать URL-адрес, такой как / app / url /, но на сервере развертывания это может быть / mountpoint / app / url , Обратный работает в views.py. Но это не работает в urls.py. Это выдает ошибку: «Включенный urlconf foo.urls не имеет никаких шаблонов». Этот трюк избавляет вас от необходимости оборачивать URLconf в представление.
Показать ещё 1 комментарий
5

Используйте djangorecipe для управления вашим проектом

  • Если вы пишете новое приложение, этот рецепт позволяет легко протестировать его за пределами проекта.
  • Он позволяет вам управлять зависимостями для проекта (например, какую версию какого-либо приложения он должен зависеть)

Все, что вам нужно сделать, чтобы начать, это:

  • Создайте папку для нового веб-сайта (или библиотеки)
  • Создайте buildout.cfg со следующим содержимым в нем:

    
    [buildout]
    parts=django
    
    [django]
    recipe=djangorecipe
    version=1.1.1
    project=my_new_site
    settings=development
    
  • Возьмите bootstrap.py, чтобы получить локальную установку buildout и поместить ее в свой каталог. Вы можете либо пойти с официальным (извините, Markdown не понравилось часть полной ссылки: -/) или с той, которая использует распространяйте вместо setuptools, как описано Reinout van Rees.
  • python bootstrap.py (или python bootstrap_dev.py, если вы хотите использовать дистрибутив).
  • ./bin/buildout

Что это. Теперь у вас должна быть новая папка "my_new_site", которая является вашим новым проектом django 1.1.1, а в. /bin вы найдете django - script, который заменяет manage.py на обычную установку.

Какая польза? Скажем, вы хотите использовать что-то вроде django-comment-spamfighter в своем проекте. Все, что вам нужно сделать, это изменить файл buildout.cfg примерно так:


[buildout]
parts=django

[django]
recipe=djangorecipe
version=1.1.1
project=my_new_site
settings=development
eggs=
    django-comments-spamfighter==0.4

Обратите внимание, что все, что я сделал, это добавить последние 2 строки, которые говорят, что в django-part также должен быть пакет django-comments-spamfighter в версии 0.4. В следующий раз, когда вы запустите ./bin/buildout, buildout загрузит этот пакет и изменит. /bin/django, чтобы добавить его в свой PYTHONPATH.

djangorecipe также подходит для развертывания вашего проекта с помощью mod_wsgi. Просто добавьте параметр wsgi=true в django-часть вашего файла buildout.cfg, и в вашей папке. /bin появится "django.wsgi": -)

И если вы установите параметр test в список приложений, djangorecipe создаст для вас хорошую обертку, которая проведет все тесты для указанного приложения в вашем проекте.

Если вы хотите создать отдельное приложение в автономной среде для отладки и т.д., у Якоба Каплана-Мосса есть вполне полный учебник по его блог

5

Создать форму через шаблон django вместо as_ (ul | table | p)().

В этой статье показано, как использовать шаблон для рендеринга CusstomForms вместо as_p(), as_table()...

Чтобы заставить его сменить работу

  • from django import newforms as forms до from django import forms
  • from django.newforms.forms import BoundField from django.forms.forms import BoundField
4

Изменение свойств поля формы Django в init

Иногда полезно передавать дополнительные аргументы классу Form.

from django import forms
from mymodels import Group

class MyForm(forms.Form):
    group=forms.ModelChoiceField(queryset=None)
    email=forms.EmailField()
    some_choices=forms.ChoiceField()


    def __init__(self,my_var,*args,**kwrds):
        super(MyForm,self).__init__(*args,**kwrds)
        self.fields['group'].queryset=Group.objects.filter(...)
        self.fields['email'].widget.attrs['size']='50'
        self.fields['some_choices']=[[x,x] for x in list_of_stuff]

источник: фрагменты Dzone

  • 0
    Brilliant! Я только что обернул свои классы Form в функции, которые кажутся не такими Pythonic, как этот.
4

Это действительно простой способ никогда не импортировать еще одну модель в свою оболочку python.

Сначала установите IPython (Если вы не используете IPython, что с тобой случилось?). Затем создайте python script, ipythonrc.py в каталоге проекта django со следующим кодом:

from django.db.models.loading import get_models 
for m in get_models(): 
     globals()[m.__name__] = m 
#NOTE: if you have two models with the same name you'll only end up with one of them

Затем в файле ~/.ipython/ipythonrc поместите следующий код в раздел "Файлы и файлы Python для загрузки и выполнения":

execfile /path/to/project/ipythonrc.py

Теперь каждый раз, когда вы запускаете IPython или запускаете ./manage.py shell, у вас будут все ваши модели, уже импортированные и готовые к использованию. Не нужно снова импортировать другую модель.

Вы также можете поместить любой другой код, который вы выполняете в файле ipythonrc.py, чтобы сэкономить время.

  • 7
    рассмотрите возможность использования «расширений команд django», в которые добавляется команда ./manage.py shell_plus, которая делает это за вас (также несколько других интересных вещей).
2

PyCharm и Wingware IDE - отличный инструмент, если у вас есть деньги для оплаты лицензии.

Поскольку я плохой разработчик, я использую PyDev с Eclipse.

2

django_extensions из https://github.com/django-extensions/django-extensions просто отлично.

Несколько приятных команд ./manage.py:

  • shell_plus - автоимпортирует модели из всех INSTALLED_APPS
  • show_urls - печатает все URL-адреса, определенные во всех приложениях проекта
  • runscript - запускает любой script в контексте проекта (вы можете использовать модели и другие связанные с Django модули)
1

Прочитайте Unbreaking Django, если вы еще этого не сделали. Он содержит много полезной информации о ловушках джанго.

1

Используйте асинхронные задачи. Используйте Celery

1

Немного поздно на вечеринку. Но Django Canvas недавно вышел, и он заслуживает места здесь.

Не запускайте проект с помощью django-admin.py startproject. Вместо этого вы можете использовать что-то вроде Django Canvas, чтобы помочь собрать вместе пустой проект с необходимыми модулями.

Вы переходите на этот сайт, отметьте некоторые параметры, а затем загрузите пустой проект, настолько простой.

В нем есть все распространенные вещи, такие как миграции южной схемы и расширения команд, а также множество других передовых методов, упомянутых здесь. Кроме того, у него отличный start.sh/shart.bat script, который установит python, virtualenv, pip, django и все, что вам нужно, чтобы начать с новой копии окон, osx или linux.

1

Создание динамических моделей для наборов устаревших таблиц с одинаковой структурой:

class BaseStructure(models.Model):
    name = models.CharField(max_length=100)
    address = models.CharField(max_length=100)

    class Meta:
        abstract=True

class DynamicTable(models.Model):
    table_name = models.CharField(max_length=20)

    def get_model(self):
        class Meta:
            managed=False
            table_name=self.table_name

        attrs = {}
        attrs['Meta'] = Meta

        # type(new_class_name, (base,classes), {extra: attributes})
        dynamic_class = type(self.table_name, (BaseStructure,), attrs) 
        return dynamic_class

customers = DynamicTable.objects.get(table_name='Customers').get_model()
me = customers.objects.get(name='Josh Smeaton')
me.address = 'Over the rainbow'
me.save()

Это предполагает, что у вас есть устаревшие таблицы с одинаковой структурой. Вместо создания модели для обертывания каждой из таблиц вы определяете одну базовую модель и динамически создаете класс, необходимый для взаимодействия с конкретной таблицей.

1

Используйте isapi-wsgi и django-pyodbc для запуска Django в Windows с использованием IIS и SQL Server!

  • 5
    Если вы в этом ;-)
0

У Django нет настроек приложения, поэтому я сделал свое собственное обнаружение app_settings.py. В нижней части settings.py я добавил этот код:

import sys, os
# Append application settings without triggering the __init__.
for installed_app in INSTALLED_APPS:
    # Ignore django applications
    if not installed_app.startswith('django.'):
        # Find the app (and the settings file)
        for path in sys.path:
            path = os.path.join(path, installed_app, 'app_settings.py')
            if os.path.isfile(path):
                # Application settings found
                exec open(path).read()

Он обнаруживает app_settings.py во всех INSTALLED_APPS. Вместо того, чтобы импортировать его, он будет читать содержимое файла app_settings и будет выполнять его inline. Если импортируется приложение app_settings, все типы ошибок импорта Django будут подняты (поскольку Django еще не инициализирован).

Итак, приложение app/app_settings.py будет выглядеть так:

MIDDLEWARE_CLASSES += (
    'app.middleware.FancyMiddleware',
)

Теперь приложение нужно добавить в INSTALLED_APPS вместо поиска всех параметров приложения и добавить их в settings.py(промежуточное ПО, URL-адреса...)

Примечание. Было бы лучше, если бы у Django был крючок для добавления дополнительных настроек, поэтому параметры приложения можно было добавить при запуске (или во время выполнения).

0

dir() и повысит значение ValueError()

Для отладки/изучения состояния вещей во время разработки я использую следующий трюк:

...
  to_see = dir(inspect_this_thing)
  to_see2 = inspect_this_thing.some_attribute
  raise ValueError("Debugging")
...

Это особенно полезно, когда вы работаете над частями django, которые не особенно хорошо документированы (form.changed_fields - это тот, который я использовал в последнее время).

locals().

Вместо того, чтобы записывать каждую переменную для контекста шаблона, используйте команду python builtin locals(), которая создает для вас словарь:

#This is tedious and not very DRY
return render_to_response('template.html', {"var1": var1, "var2":var2}, context_instance=RequestContext(request))

#95% of the time this works perfectly
return render_to_response('template.html', locals(), context_instance=RequestContext(request))

#The other 4.99%
render_dict = locals()
render_dict['also_needs'] = "this value"
return render_to_response('template.html', render_dict, context_instance=RequestContext(request))
0

При передаче переменных из представления в шаблон ответный словарь может стать утомительным для ввода. Мне очень приятно просто передать все локальные переменные сразу, используя locals().

def show_thing(request, thing_id):
    thing = Thing.objects.get(pk=thing_id)
    return render_to_response('templates/things/show.html', locals())

(Не скрытая функция сама по себе, но тем не менее она полезна при использовании новых для Python и Django.)

Изменить: Очевидно, что лучше быть явным, чем неявным, но этот подход может быть полезен во время разработки.

  • 0
    Лучше быть явным.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню