Django использует один и тот же объект для нескольких представлений

В django я делаю свое первое приложение. Я пытаюсь найти способ поделиться объектом между несколькими методами просмотра.

например В моих views.py у меня есть

def lights_on(request):
    hue_connector = HueConnector()
    print(hue_connector.turn_all_lights_on())
    return redirect('/')

def lights_off(request):    
    hue_connector = HueConnector()
    print(hue_connector.turn_all_lights_off())
    return redirect('/')

def light_on(request, light_id):
    hue_connector = HueConnector()
    hue_connector.set_light_on_state(light_id, "true")
    html = "<html><body>" + light_id + "</body></html>"
    return redirect('/')

Допустим, мне нужно еще 10 представлений в моем views.py, которым нужен HueConnector.

Как мне создать тот, который можно использовать всеми методами?

Если вам нужно сохранить одно состояние HueConnector во всем приложении, можно сделать его (HueConnector) одноэлементным.

Julkar9 08.04.2023 18:00

Что вы имеете в виду, когда говорите о совместном использовании объекта? Вы хотите избежать строки создания экземпляра hue_connector в каждом представлении?

EDG956 08.04.2023 18:48

@ EDG956 Да, я не хочу создавать новый в каждом методе.

Sven van den Boogaart 08.04.2023 19:04
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
3
62
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

У вас есть несколько вариантов. Здесь я опишу два: использование одного объекта, созданного во время импорта (как предлагается в других ответах), и представления на основе классов.

Один экземпляр

Предположим, что HueConnector может быть создан во время импорта, и это зависит только от некоторых настроек (django или внешних). Вы можете просто создать экземпляр один раз и использовать его в своих представлениях. То есть:

# app/views.py
hue_connector = HueConnector()

def lights_on(self, request):
    print(hue_connector.turn_all_lights_on())
    return redirect('/')

def lights_off(self, request):
    print(hue_connector.turn_all_lights_off())
    return redirect('/')

def light_on(self, request, light_id):
    hue_connector.set_light_on_state(light_id, "true")
    html = "<html><body>" + light_id + "</body></html>"
    return redirect('/')

Это простой, но не потокобезопасный (хотя сделать его потокобезопасным не так уж и сложно).

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

Вы можете сгруппировать обработчики представлений методов http в представления на основе классов, единственная проблема заключается в том, что ваши представления, вероятно, используют общие методы HTTP, поэтому вам придется решать внутри обработчика, что делать. I:E: вызовите либо lights_on, либо lights_off внутри post() в зависимости от некоторого условия.

Поскольку вы используете отдельные функции, я предполагаю, что вы используете разные URL-адреса, поэтому, немного смешивая подход DRF с сопоставлением http-метод-действие ViewSet, вы можете создать свой собственный View класс которые понимают такое отображение.

Реализация очень голых костей может быть примерно такой (внезапно я не проверял это):

from typing import Mapping, Optional

from django.utils.decorators import classonlymethod
from django.views.generic import View

class ViewWithActions(View):
    @classonlymethod
    def as_view(cls, actions: Optional[Mapping[str, str]] = None, **initkwargs):
        self = cls(**initkwargs)
        self.setup(request, *args, **kwargs)
        if not hasattr(self, "request"):
            raise AttributeError(
                "%s instance has no 'request' attribute. Did you override "
                "setup() and forget to call super()?" % cls.__name__
            )
        if actions:
            for method, action in actions.items():
                handler = getattr(self, action)
                setattr(self, method, handler)

        return self.dispatch(request, *args, **kwargs)

Ключевым выводом является то, что подклассы этого класса могут определять столько методов, сколько необходимо, и позволяют программисту решать для каждого маршрута, какие методы HTTP сопоставляются с каким методом представления класса. Аргумент actions для as_view определяет, какая функция экземпляра класса вызывается для каждого метода http.

Вот пример того, как их использовать:

# app/views.py
from hue_connector import HueConnector  # Whatever package you're using

from project.views import ViewWithActions

class LightsView(ViewWithActions):
    def lights_on(self, request):
        print(self.hue_connector.turn_all_lights_on())
        return redirect('/')

    def lights_off(self, request):
        print(self.hue_connector.turn_all_lights_off())
        return redirect('/')

    def light_on(self, request, light_id):
        self.hue_connector.set_light_on_state(light_id, "true")
        html = "<html><body>" + light_id + "</body></html>"
        return redirect('/')

    @property
    def hub_connector(self) -> HueConnector:
        return HueConnector()
# app/urls.py
from django.urls import path

from app.views import LightsView
...

urlpatterns = [
    ...,
    path("lights/on", LightsView.as_view({"post": "lights_on"})),
    path("lights/off", LightsView.as_view({"post": "lights_off"})),
    path("lights/<int:light_id>/on", LightsView.as_view({"post": "light_on"})),
    ...,
]

...

Это был бы мой предпочтительный вариант, потому что, изменив класс так, чтобы он принимал класс HueConnector (или фабрику hueconnector) в качестве зависимости, это упростило бы тестирование, передавая ему поддельные реализации во время тестов вместо исправления обезьяны.

Один из способов, который вы можете сделать, это иметь hue_connector = HueConnector() в другом файле, скажем, utils.py, затем импортировать его и использовать по своему усмотрению во всех видах, которые вы хотите.

# utils.py

hue_connector = HueConnector()
# views.py

from .utils import hue_connector
### Proceed using in your views

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

def lights_on(request):
    global hue_connector
    hue_connector = HueConnector()
    print(hue_connector.turn_all_lights_on())
    return redirect('/')

Другие вопросы по теме