[Python, Django] Зачем вам может понадобиться SITE_ID в настройках Django
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Если вы не используете все возможности Django, то, очень вероятно, вы не пользуетесь SITE_ID. Этому способствуют как убогая официальная документация Sites framework, так и несогласованное с Sites развитие кода Django.
Предположу, что Sites скоро будет бездумно снесен свежими «разработчиками» Django, как это уже произошло с модулями Comments (Dj 1.6) или Formtools (Dj 1.8). А, пока этого не произошло, предлагаю вам поразмышлять о возможностях Django Sites framework.
Вспомните, в своем первом проекте 1.xxx версий Django, скорее всего, вы даже не обратили внимания на автоматически созданные строчки, в settings.py:
'django.contrib.sites', # включаем framework Sites
........
SITE_ID = 1 # задаем значение SITE_ID по умолчанию
В новых версиях Django 3.хх упоминание о SITES_ID вы встретите, только когда захотите включить еще одного кандидата на вылет «flatpages app». Читайте об этом в разделе установка.
На работу самих «Flatpages», Sites особо не влияет, но без миграции из django.contrib.sites не обойтись.
Так зачем вообще может понадобиться настройка SITES_ID?
Если читать документацию по «Sites framework», которая не поменялась c Django 1.4, то вам расскажут, как можно настроить одну панель администратора для управления содержимым нескольких сайтов. Скажу больше, разумное использование Sites позволяет ограничивать доступ к данным на уровне запросов к базе данных, когда права доступа на уровне объектов Python/Django неизвестны, т.к. объектов еще не создано.
Вы можете попробовать сделать это самостоятельно:
Для этого запустите несколько раз django server своего проекта для разных портов с указанием атрибута --settings=every_time_another_settings_name, в каждом новом settings.py укажите другой SITE_ID.
И вы увидите, что ничего не изменилось. Пока.
Чтобы ощутить разницу, вам предстоит внести изменения в проект.
- Добавить поле site=ForeignKey(Site) к любой вашей модели.
- Унаследовать менеджера данных этой модели от CurrentSiteManager
- Обновить схему модели и выполнить миграцию
from django.db.models import Model, CharField, ForeignKey
from django.contrib.sites.managers import CurrentSiteManager
from django.contrib.sites.models import Site
from django.conf import settings
class MyModelManager(CurrentSiteManager):
pass
class MyModel(Model):
title = CharField(max_length=255)
site = ForeignKey(Site, default=settings.SITE_ID, editable=False, on_delete=CASCADE)
objects = MyModelManager() # можно сразу тут передать имя поля.
Опять запустите несколько раз сервер на разных портах, запустите Админ панель, создайте объекты в администраторе измененной модели.
Как видите, администратор модели отображает только объекты для своего SITE_ID
Обобщим первый опыт:
Менеджер, унаследованный от CurrentSiteManager дает предварительную автоматическую фильтрацию данных своей модели по определенному признаку: obj.site_id=settings.SITE_ID
Если вы добрались до этого момента, то вы встретите первую недоработку SITES framework.
в CurrentSiteManager жестко зашита проверка наличия ForeignKey(Site) в текущей модели. Похоже, что для использования всех удобств Sites в старых версиях Django мы вынуждены иметь ForeignKey(Site) в каждой модели.
Но если подумать, то при доработке CurrentSiteManager напильником можно все сделать как надо:
class MyModelManager(CurrentSiteManager):
site_field_name = 'othermymodel__site'
def __init__(self, *args, **kwargs):
super(MyModelManager, self).__init__(*args, **kwargs)
if self.site_field_name:
self._CurrentSiteManager__is_validated = True #для старых Django
self._CurrentSiteManager__field_name = self.site_field_name
def _check_field_name(self): #для новых Django
return []
Mожете сами поискать с какой версии Django этот код останется работосособным, но станет избыточным.
В новых версиях Django код уже пробовали исправить, но так и не доделали. Причина в том, что django.contrib.sites — это уже неуловимый Джо для разработчиков Django.
Что должно получиться в итоге:
Вы вставили в ключевые модели поле ссылки на Site, в менеджерах связанных моделей ссылку на это поле в атрибуте site_field_name.
При заходе по адресу одного сайта вы видите и правите данные только этого сайта, при заходе на другой — видите и правите данные только другого сайта.
Сервер надо запустить несколько раз. Но база и код в единственном экземпляре.
В проектах моей фирмы Менеджеры «сайтовых данных» унаследованы от исправленного CurrentSiteManager с правильно прописанными site_field_name и несколько моделей имеют ссылку на ForeignKey(Site). При этом дополнительных JOIN в запросах удалось избежать.
Немногим позже вы заметите, что знания только site_id мало. Например, в шаблонах вы захотите отображать не цифру, как у меня на примере выше, а красивое имя сайта. Этому может поспособствовать CurrentSiteMiddleware из django.contrib.sites.middleware.
Благодаря ей любой request получит вычисленный атрибут site, хранящий объект из модели Sites. CurrentSiteMiddleware позволит не прописывать SITES_ID в settings, и вычисление атрибута site будет выполняться с учетом текущего запроса, и это очень круто. Только эта функция работает не всегда и не так, как ожидается:
- Атрибут site вычисляется сразу. Не важно, используете вы его в дальнейшем, или нет. Да, в коде предприняты корявые попытки уменьшить количество обращений к базе, но непонятно, что мешало разработчикам Django использовать lazy-объект.
- Если вы сильно заморочены на типизации, то заметите, что атрибут site может содержать instance двух абсолютно не связанных классов. Причем явно переопределить один из этих классов (RequestSite) вы не можете. Но если подумать, то подмена класса у instance возможна позже.
- SITES_ID в settings не знает о модели Site и наоборот. Запуск сервера с новым SITES_ID, удаление строки таблицы — все это приведет к появлению Server Error. Я считаю это изначальной архитектурной ошибкой Sites framework
- Хотя это и разрешено, не указывать SITES_ID в settings, но любой CurrentSiteManager и django.contrib.FlatPages перестанут работать.
- Вычисленный на лету объект в site никак не влияет на работу «Current»SiteManager. Хотя название класса как бы обязывает.
Последний пункт превращает sites framework в тыкву бессмысленный атавизм из ветки Django 1.xxx. Но если подумать… то этих «если подумать» и так уже слишком много.
Разумеется, у вас уже мог появиться вопрос: да кому вообще нужен этот SITES_ID, это старье уже никто не использует! И я с этим не соглашусь.
Я знаю несколько современных проектов, использующих подобную структуру.
Пример из недавнего — это проект SHUUP, c доработкой Multivendor Marketplace. Его мы совсем недавно портировали на Python-3.9.1/Django-3.1.6
Ребята сделали copy-paste-find-replace в django.contrib.sites, у них вместо модели Site модель Shop, вместо SITES_ID стоит DEFAULT_SHOP, и вместо CurrentSiteMiddleware — ShuupMiddleware, в которой они к request крепят не site а shop.
Как по мне, так все же лучше использовать существующий код, чем повторять его еще раз. Но заново изобретенный разработчиками SHUUP «proxy model» подсказывает, что:
На этой ноте я завершу размышления о том, на что влияет SITES_ID в settings.
Какой же из всего этого можно сделать вывод:
В Django заложена возможность создания мультидоменных платформ, подобных wix.com, ucoz.ru, shopify.com с единым административным интерфейсом и простым и быстрым разграничением доступа к данным. Эта возможность заложена в CurrentSiteManager из django.contrib.sites, остается только правильно её реализовать.
Я готов рассказать в следующей статье, об этой доработке, если это будет интересно читателям.
===========
Источник:
habr.com
===========
Похожие новости:
- [Системное администрирование, Python, IT-инфраструктура, Help Desk Software] Root cause анализ инцидентов на корреляциях между временными рядами метрик ИТ-инфраструктуры
- [Open source, Python, Natural Language Processing, Голосовые интерфейсы] Новые возможности для Python-разработчиков: SmartApp Framework в open source
- [Python, Big Data, GitHub] Я спарсил больше 1000 топовых Github-профилей по машинному обучению и вот что я узнал (перевод)
- [Python, SQL] Создаем схему базы данных на SQLAlchemy
- [Python, Машинное обучение, Искусственный интеллект, Data Engineering, TensorFlow] Рецепт обучения нейросетей (перевод)
- [Python, Программирование, Django] Конвертеры маршрутов в Django 2.0+ (path converters)
- [Python, Графический дизайн] Python, Треугольник Серпинского, и не только…
- [Python, Программирование] Использование статистических методов для анализа временных рядов
- [Python, API] LongPoll в vk_api
- [Python, Машинное обучение] Оценка важности «фичей» для нелинейных моделей
Теги для поиска: #_python, #_django, #_django, #_python, #_malo_kto_ponimaet_django (мало кто понимает django), #_python, #_django
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 07:35
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Если вы не используете все возможности Django, то, очень вероятно, вы не пользуетесь SITE_ID. Этому способствуют как убогая официальная документация Sites framework, так и несогласованное с Sites развитие кода Django. Предположу, что Sites скоро будет бездумно снесен свежими «разработчиками» Django, как это уже произошло с модулями Comments (Dj 1.6) или Formtools (Dj 1.8). А, пока этого не произошло, предлагаю вам поразмышлять о возможностях Django Sites framework. Вспомните, в своем первом проекте 1.xxx версий Django, скорее всего, вы даже не обратили внимания на автоматически созданные строчки, в settings.py: 'django.contrib.sites', # включаем framework Sites
........ SITE_ID = 1 # задаем значение SITE_ID по умолчанию В новых версиях Django 3.хх упоминание о SITES_ID вы встретите, только когда захотите включить еще одного кандидата на вылет «flatpages app». Читайте об этом в разделе установка. На работу самих «Flatpages», Sites особо не влияет, но без миграции из django.contrib.sites не обойтись. Так зачем вообще может понадобиться настройка SITES_ID? Если читать документацию по «Sites framework», которая не поменялась c Django 1.4, то вам расскажут, как можно настроить одну панель администратора для управления содержимым нескольких сайтов. Скажу больше, разумное использование Sites позволяет ограничивать доступ к данным на уровне запросов к базе данных, когда права доступа на уровне объектов Python/Django неизвестны, т.к. объектов еще не создано. Вы можете попробовать сделать это самостоятельно: Для этого запустите несколько раз django server своего проекта для разных портов с указанием атрибута --settings=every_time_another_settings_name, в каждом новом settings.py укажите другой SITE_ID.
И вы увидите, что ничего не изменилось. Пока. Чтобы ощутить разницу, вам предстоит внести изменения в проект.
from django.db.models import Model, CharField, ForeignKey
from django.contrib.sites.managers import CurrentSiteManager from django.contrib.sites.models import Site from django.conf import settings class MyModelManager(CurrentSiteManager): pass class MyModel(Model): title = CharField(max_length=255) site = ForeignKey(Site, default=settings.SITE_ID, editable=False, on_delete=CASCADE) objects = MyModelManager() # можно сразу тут передать имя поля. Опять запустите несколько раз сервер на разных портах, запустите Админ панель, создайте объекты в администраторе измененной модели. Как видите, администратор модели отображает только объекты для своего SITE_ID Обобщим первый опыт: Менеджер, унаследованный от CurrentSiteManager дает предварительную автоматическую фильтрацию данных своей модели по определенному признаку: obj.site_id=settings.SITE_ID Если вы добрались до этого момента, то вы встретите первую недоработку SITES framework. в CurrentSiteManager жестко зашита проверка наличия ForeignKey(Site) в текущей модели. Похоже, что для использования всех удобств Sites в старых версиях Django мы вынуждены иметь ForeignKey(Site) в каждой модели. Но если подумать, то при доработке CurrentSiteManager напильником можно все сделать как надо: class MyModelManager(CurrentSiteManager):
site_field_name = 'othermymodel__site' def __init__(self, *args, **kwargs): super(MyModelManager, self).__init__(*args, **kwargs) if self.site_field_name: self._CurrentSiteManager__is_validated = True #для старых Django self._CurrentSiteManager__field_name = self.site_field_name def _check_field_name(self): #для новых Django return [] В новых версиях Django код уже пробовали исправить, но так и не доделали. Причина в том, что django.contrib.sites — это уже неуловимый Джо для разработчиков Django. Что должно получиться в итоге: Вы вставили в ключевые модели поле ссылки на Site, в менеджерах связанных моделей ссылку на это поле в атрибуте site_field_name. При заходе по адресу одного сайта вы видите и правите данные только этого сайта, при заходе на другой — видите и правите данные только другого сайта. Сервер надо запустить несколько раз. Но база и код в единственном экземпляре. В проектах моей фирмы Менеджеры «сайтовых данных» унаследованы от исправленного CurrentSiteManager с правильно прописанными site_field_name и несколько моделей имеют ссылку на ForeignKey(Site). При этом дополнительных JOIN в запросах удалось избежать.
Немногим позже вы заметите, что знания только site_id мало. Например, в шаблонах вы захотите отображать не цифру, как у меня на примере выше, а красивое имя сайта. Этому может поспособствовать CurrentSiteMiddleware из django.contrib.sites.middleware. Благодаря ей любой request получит вычисленный атрибут site, хранящий объект из модели Sites. CurrentSiteMiddleware позволит не прописывать SITES_ID в settings, и вычисление атрибута site будет выполняться с учетом текущего запроса, и это очень круто. Только эта функция работает не всегда и не так, как ожидается:
Последний пункт превращает sites framework в тыкву бессмысленный атавизм из ветки Django 1.xxx. Но если подумать… то этих «если подумать» и так уже слишком много. Разумеется, у вас уже мог появиться вопрос: да кому вообще нужен этот SITES_ID, это старье уже никто не использует! И я с этим не соглашусь. Я знаю несколько современных проектов, использующих подобную структуру.
Пример из недавнего — это проект SHUUP, c доработкой Multivendor Marketplace. Его мы совсем недавно портировали на Python-3.9.1/Django-3.1.6 Ребята сделали copy-paste-find-replace в django.contrib.sites, у них вместо модели Site модель Shop, вместо SITES_ID стоит DEFAULT_SHOP, и вместо CurrentSiteMiddleware — ShuupMiddleware, в которой они к request крепят не site а shop. На этой ноте я завершу размышления о том, на что влияет SITES_ID в settings. Какой же из всего этого можно сделать вывод: В Django заложена возможность создания мультидоменных платформ, подобных wix.com, ucoz.ru, shopify.com с единым административным интерфейсом и простым и быстрым разграничением доступа к данным. Эта возможность заложена в CurrentSiteManager из django.contrib.sites, остается только правильно её реализовать. Я готов рассказать в следующей статье, об этой доработке, если это будет интересно читателям. =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 07:35
Часовой пояс: UTC + 5