2 дня потратил на всё про всё, думал помру и не одолею я этого исполина…
чтоб не копипастить, всё что я делал я рассписал на форуме поддержки
вот тут ссылка
http://support.djangobb.org/topic/227/
2 дня потратил на всё про всё, думал помру и не одолею я этого исполина…
чтоб не копипастить, всё что я делал я рассписал на форуме поддержки
вот тут ссылка
http://support.djangobb.org/topic/227/
Добрый час я потратил на вот обычную беду, вроде всё сделано верно, но форма передаёт имя файла. а сам файл на сервере не появляется, в дебаг-тулбар был SQL запрос на INSERT а поле bla bla avatar = WHERE blabla= blabla
В итоге я стал понимать что форма шлёт только текстовые поля. и файлы не передаёт на сервер. и сервер ругается мол имя пришло а картинки нету!!!
Говорит
[cc lang=”python”]The ‘avatar’ attribute has no file associated with it.[/cc]
Вот оно и тут… всё дело в свойствах формы, мне не хватало
[cc lang=”html”]enctype=”multipart/form-data”[/cc]
в Django я по прежнему новичок, но что-то стараюсь понять и запомнить.
стояла задача расширить профиль пользователя дополнительными полями, статей на эту тему пресс и малелькая тележка, но не получалось, то у кого-то на сайте парсер html сильно злой и код надо было переписывать, у кого-то были ошибки в примерах и т.п.
но как-то оно получилось, попробую собрать все мысли в кучу в эту статью.
Многие знают о django-registration и вот от автора этого замечательного приложения существует django-profiles котором я и воспользовался.
устанавливаем django-profiles
[cc lang=”bash”]easy_install django-profiles[/cc]
в models.py создадим модель профиля, которая наследуется от штатной User и добавим в ней нужное нам поле
[cc lang=”python”]
from django.contrib.auth.models import User
…
…
class UserProfile(models.Model):
# поле для связки со встроенной моделью пользователя Django
user = models.ForeignKey(User, unique=True)
# наше новое поле
about = models.TextField(blank=True)[/cc]
Далее в settings.py надо указать кто будет новым AUTH_PROFILE_MODULE
[cc lang=”python”]AUTH_PROFILE_MODULE = ‘list.UserProfile'[/cc]
где list это ваше приложение в котором расположена модель расширяющая пользователя
в принципе на этом можно закончить, ибо обращаться теперь можно к
[cc lang=”bash”]{{ user.get_profile.about }}[/cc]
только нужно обратить внимание что надо пользоваться не context а RequestContext
и указать это в
TEMPLATE_CONTEXT_PROCESSORS файла settings.py
[cc lang=”python”]TEMPLATE_CONTEXT_PROCESSORS = (
…
‘django.contrib.auth.context_processors.auth’,
…
) [/cc]
но мы идём дальше
Теперь нам надо подключить django-profiles для просмотра\редактирования профиля
в файле urls.py
подключаем
[cc lang=”python”] …
(r’^profiles/’, include(‘profiles.urls’)),
…[/cc]
в settings.py также подключим приложение
[cc lang=”python”]INSTALLED_APPS = (
…
‘profiles’,
)
[/cc]
теперь создадим таблицы в базе
[cc lang=”python”]python manage.py syncdb[/cc]
приложение profiles использует вот такие шаблоны
[cc lang=”bash”]
profiles/create_profile.html
profiles/edit_profile.html
profiles/profile_detail.html
profiles/profile_list.html[/cc]
по названию понятно что к чему
для начала отредактируем edit_profile.html
[cc lang=”html”]{% extends “base.html” %}
{% block title %}Edit Profile{% endblock %}
{% block content %}
{% endblock content %}[/cc]
сохраняем, теперь можно обратиться к /profiles/edit/ то должно открыться форма редактирования профиля.
бывают ситуации, что в профиле есть какие-то поля, что запрещено редактировать пользователю, реализуется это довольно просто
создаём класс формы, наследуемой от общей формы, в котором перечисляем, то что нам исключить от вывода пользователю
forms.py
[cc lang=”python”]from django.db import models
from django.forms import ModelForm
from PROJ.apps.APP.models import UserProfile
………
class ProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
exclude = (‘user’,’last_name’,)
[/cc]
from PROJ.apps.APP.models import UserProfile
проект и приложение где расположена расширенная модель
теперь в urls.py надо указать, что страницу редактирования профиля надо открывать с нужной нам формой
[cc lang=”python”]from PROJ.APP.forms import ProfileForm
……..
(‘^profiles/edit’, ‘profiles.views.edit_profile’, {‘form_class’: ProfileForm,}),
(r’^profiles/’, include(‘profiles.urls’)),
…….[/cc]
Должно получиться примерно так.. проверяем на странице редактирования профиля (/profiles/edit/).
Теперь сделаем страницу отображения профиля profile/profile_detail.html
вывести можно что угодно из профиля вот так
[cc lang=”python”]
Address 2:
{{ profile.address2 }}
[/cc]
где address2 это дополнительное поле
список пользователей с профилями можно вывести вот так
profiles/profile_list.html
[cc lang=”python”]
{% extends “base.html” %}
{% block content %}
{% for p in object_list %}
{{ p.user }}
{% endfor %}
{% endblock %}
[/cc]
Теперь задача такая, сейчас профиль и пользователь живут почти своей жизнью, при регистрации пользователя профиль сам не создаётся это мы сейчас и решим сигналами.
в models.py добавим
[cc lang=”python”]
from django.db.models import signals
from bucket.signals import create_profile
# When model instance is saved, trigger creation of corresponding profile
signals.post_save.connect(create_profile, sender=User)[/cc]
создадим файл, если он не создан signals.py:
[cc lang=”python”]def create_profile(sender, instance, signal, created, **kwargs):
“””When user is created also create a matching profile.”””
from PROJ.apps.APP.models import UserProfile
if created:
UserProfile(user = instance).save()
# Do additional stuff here if needed, e.g.
# create other required related records
[/cc]
вот и всё, при регистрации нового пользователя автоматически будет создаваться к нему профиль, если у вас уже сейчас много пользователей, то создать для каждого профиль можно вот так
[cc lang=”python”]$ python manage.py shell
from django.contrib.auth.models import User
from bucket.models import Profile
users = User.objects.all()
for u in users:
try:
p = u.get_profile()
except p.DoesNotExist:
Profile(user = u).save()[/cc]
ещё коснусь вопроса редактирования своего email в профиль, пока ещё не совсем разобрался с этим.
пока есть только пример, делается это анналогично через forms.py
[cc lang=”python”]class ProfileForm(ModelForm):
def __init__(self, *args, **kwargs):
super(ProfileForm, self).__init__(*args, **kwargs)
try:
self.fields[’email’].initial = self.instance.user.email
# self.fields[‘first_name’].initial = self.instance.user.first_name
# self.fields[‘last_name’].initial = self.instance.user.last_name
except User.DoesNotExist:
pass
email = forms.EmailField(label=”Primary email”,help_text=”)
class Meta:
model = Profile
exclude = (‘user’,)
def save(self, *args, **kwargs):
“””
Update the primary email address on the related User object as well.
“””
u = self.instance.user
u.email = self.cleaned_data[’email’]
u.save()
profile = super(ProfileForm, self).save(*args,**kwargs)
return profile[/cc]
надеюсь вернусь к этому вопросу
Давным давно, я писал как установить nginx
там же в комментариях подсказали ещё способ
[cc lang=”bash”]
nginx=stable # use nginx=development for latest development version
add-apt-repository ppa:nginx/$nginx
apt-get update
apt-get install nginx[/cc]
получаем последний nginx.
Напомню, что у меня за nginx стоят разные “бэк-энды”
для самого нагруженного сайта я использую php5-fpm
для остальных сайтов я использую apache2
для Django проектов я использовал Apache2 + mod_python но его прожорливость, давала повод задуматься.
в итоге я искал способ освободить ресурсы занимаемые Индейцем.
Такой способ нашёлся 🙂
создаю конфигурационный файл хоста nginx.
[cc lang=”bash”]touch djangosite[/cc]
у меня они лежат в /etc/nginx/sites-available и уже от туда симлинками идут в /etc/nginx/sites-enabled
Конфигурационный файл такого содержания
[cc lang=”bash”]server {
listen 80;
server_name sitename.ru www.sitename.ru;
charset utf-8;
access_log /var/log/nginx/sitename-access.log;
error_log /var/log/nginx/sitename-error.log;
client_max_body_size 300m;
# Это, чтоб стили и статические файлы админки подгружались, проверьте у себя,
# в разных версиях Ubuntu могут быть разные версии Питона.
# ну и в настройках джанго проекта разумеется у нас тоже указан ADMIN_MEDIA как media_admin
location /media_admin {
alias /usr/lib/python2.5/site-packages/django/contrib/admin/media;
}
location / {
#Это как пример как мы запускаем джангоСервер
#python ./manage.py runfcgi method=prefork socket=/tmp/sitemane.sock pidfile=/tmp/sitename.pid
# Общаться будем по сокету, хотя можно и по 127.0.0.1:8000
fastcgi_pass unix:/tmp/sitename.sock;
#Ага и вот этот файлик не забудем создать, о нём ниже
include fastcgi_params_django;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
[/cc]
так же создаём файл
[cc lang=”bash”]touch /etc/nginx/fastcgi_params_django[/cc]
и в него вкладываем вот такие параметры
[cc lang=”bash”]
fastcgi_param PATH_INFO $fastcgi_script_name;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_pass_header Authorization;
fastcgi_intercept_errors off;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
fastcgi_param SERVER_PROTOCOL $server_protocol;
# PHP only, required if PHP was built with –enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;
[/cc]
проверяем верность конфигурации
[cc lang=”bash”]nginx -t[/cc]
если всё ОК идём дальше.
проекты джанго у меня лежат в /home/django
Заходим в нужный нам проект и создадим там скрипт сервера.
[cc lang=”bash”]touch server.sh[/cc]
Вот с таким содержанием
[cc lang=”bash”]#!/bin/bash
case “$1” in
“start”)
#есть 2 варианта запуска сервера, по сети и через unix сокеты
# последний выигрывает по производительности
#python ./manage.py runfcgi method=prefork host=127.0.0.1 port=8000 pidfile=/tmp/sitename.pid
python ./manage.py runfcgi method=prefork socket=/tmp/sitename.sock pidfile=/tmp/sitename.pid
# не забываем, про то, что сокет у нас мог прочитать фронт-энд
# а nginx у меня работает с правами www-data
chown www-data:www-data /tmp/sitename.sock
;;
“stop”)
kill -9 `cat /tmp/sitemane.pid`
;;
“restart”)
$0 stop
sleep 1
$0 start
;;
*) echo “Usage: ./server.sh {start|stop|restart}”;;
esac
[/cc]
Вот и весь скрипт, не забываем только поменять sitename на имя вашего сайта, а то получится, что на один pid или сокет у вас будет ссылаться несколько серверов.
чтоб запустить сервер
[cc lang=”bash”]./server.sh start[/cc]
А вот он и не запустился ругается на Flup
[cc lang=”bash”]No module named flup[/cc]
нам понадобится пакет flup это питоновский пакет, поэтому его я устанавливаю вот так
[cc lang=”bash”]easy_install flup[/cc]
Можно попробовать поставить его из репозитория убунты
[cc lang=”bash”]apt-get install python-flup[/cc]
Но я так не пробовал 😉
Всё сервер запустился, можно перезапустить nginx для применения новой конфигурации
[cc lang=”bash”]/etc/init.d/nginx restart[/cc]
Всё готово, наш сервер запустился.
Теперь по хорошему добавить скрипт запуска сервера в автозагрузку.
“Мопед не мой, я лишь объяву разместил”
У меня пока не хватает кармы, чтоб высылать за такие статьи инвайты на хабр, поэтому видимо кроме меня этого не жалает делать никто, то буду опубликовать тут. ибо информацию считаю полезной, не только для себя.
Доброго времени суток!
Появилась необходимость следующего характера: в движке на django, при публикации новости, чтоб создавался кросс-пост на twitter. Т.е. пишем новость, жмём сохранить и на твиттере появляется пост аля «Название статьи, bit.ly/s/ссылка_на_нашу_новость».
Для реализации потребовались следующие пакеты:
1. python-oauth2 | https://github.com/simplegeo/python-oauth2
2. oauth-python-twitter2 | http://code.google.com/p/oauth-python-twitter2/
3. simplejson | http://pypi.python.org/pypi/simplejson/
4. oauth2 | http://pypi.python.org/pypi/oauth2/
5. bitlyapi | http://pypi.python.org/pypi/bitlyapi/
1-4 пакеты нужны нам для связи с twitter’ом, 5-ый для укорачивания ссылок…
Перед тем как начать предполагаю, что у Вас есть аккаунт в twitter.com и bit.ly. Если нет, то это по минуте на регистрацию на каждом из сервисов.
Начнём с twitter’a…
При-python-им twitter
Проставляем все пакеты и выполняем следующие действия (кстати они описаны выше в руководстве python-oauth2):
Логинимся в браузере в twitter.com, и после этого переходим по ссылке http://twitter.com/apps/new. Далее мы воспользуемся инструкциями из замечательной статьи:
1. Заполняем все поля на свое усмотрение, для Application Type выбираем Client
2. Для Default Access type выбираем Read & Write, Use Twitter for login я оставил не выбранным
3. Вводим капчу и сабмитим
После этого twitter сгенерит CONSUMER_KEY, CONSUMER_SECRET.
Следующие два параметра нам вернет такой скрипт
[cc lang=”python”]from oauthtwitter import OAuthApi
import pprint
CONSUMER_KEY = “*****”
CONSUMER_SECRET = “*****”
twitter = OAuthApi(consumer_key, consumer_secret)
temp_credentials = twitter.getRequestToken()
print(twitter.getAuthorizationURL(temp_credentials))
oauth_verifier = raw_input(‘What is the PIN? ‘)
access_token = twitter.getAccessToken(temp_credentials, oauth_verifier)
print(“oauth_token: ” + access_token[‘oauth_token’])
print(“oauth_token_secret: ” + access_token[‘oauth_token_secret’])
[/cc]
В CONSUMER_KEY, CONSUMER_SECRET вводим значения полученные на предыдущем этапе, запускаем. Скрипт сгенерит url, переходим по нему и копируем PIN который нам вежливо предлагает twitter. Вставляем PIN в скрипт, он как раз его ждет.
На выходе мы получим значения для двух последних параметров OAUTH_TOKEN и OAUTH_TOKEN_SECRET.
Все, теперь у нас есть все что надо для oauth авторизации, осталось немного подправить скрипты.
Готовимся сокращать ссылки вместе с bit.ly
Предельно простой и удобный модуль bitlyapi. Схема простая:
1. Регистрируемся на bit.ly
2. Логинимся
3. Переходим по ссылке
4. Копируем username и api key
Правим модель в Django
Здесь мы не рассматриваем создание модели, предполагается, что Вы это умеете. В шапку добавляем:
[cc lang=”python”]#twitter
import oauth2 as oauth
import bitlyapi
bitly = bitlyapi.BitLy(‘username bitly’, ‘api key bitly’) #вводим данные с прошлого шага
from oauthtwitter import OAuthApi
CONSUMER_KEY = “*****вводим свои данные*****”
CONSUMER_SECRET = “*****вводим свои данные*****”
OAUTH_TOKEN = “*****вводим свои данные*****”
OAUTH_TOKEN_SECRET = “*****вводим свои данные*****”
twitter = OAuthApi(CONSUMER_KEY, CONSUMER_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET)
[/cc]
Переходим к моделе. Логика проста, есть boolean поле twitter_export, если галочка ставится, то новость публикуется при сохранении на твиттере. Если не понятно, то сейчас всё увидите и поймёте ))
[cc lang=”python”]class News(models.Model):
title = models.CharField(max_length=300)
content = models.TextField()
twitter_export = models.BooleanField(default=False)
def save(self):
link = bitly.shorten(longUrl=’http://example.com/news/’ + str(self.id) + ‘/’) #формируем ссылку, которая будет сокращенна
if self.twitter_export: #если стоит галочка на twitter_export
twit = u’%s… | Читать %s’ % (self.title[:70], link[‘url’]) #формируем, что писать в твиттер.. учтите, что длина сообщения в твиттере 160 символов
twitter.UpdateStatus(twit) #публикуем наш твит
self.twitter_export = False #убираем галку twitter_export
super(News, self).save()
[/cc]
Всё готово! Можно тестировать!
Источники
1. Пишем twitter-бота на python
2. Twitter Three-legged OAuth Example