Что такое свойство `_container` http.response Django? - PullRequest
0 голосов
/ 10 марта 2020

Я не могу найти один хороший источник, который на самом деле пытается это объяснить. Топ 5 результатов поиска - это просто разные ссылки на исходный код. Прямо сейчас я пытаюсь прочитать PDF, который возвращается из запроса GET, и я хочу знать, почему он находится в response._container, когда ответ имеет тип HttpResponse. Этот PDF даже то, что я ищу? Почему это второй элемент в списке _container?

1 Ответ

2 голосов
/ 10 марта 2020

Во-первых, это не «свойство», а «атрибут» - в Python «свойство» является встроенным типом, реализующим поддержку обобщенного c вычисляемого атрибута и HttpResponse._container фактически используется в качестве поддержки реализации для свойства HttpResponse.content.

Так что это подробности реализации (как вы можете заметить по единственному нижнему подчеркиванию), и, следовательно, действительно не документировано (документация пакета или инфраструктуры касается только API, а не реализация). Итак, лучшая документация здесь - это исходный код. FWIW, исходный код всегда является окончательной документацией, даже если не всегда самым удобным для пользователя; -)

Надеюсь, эта часть довольно проста для понимания (код из текущей ветки master, но эта часть довольно стабильно):

https://github.com/django/django/blob/master/django/http/response.py#L308

class HttpResponse(HttpResponseBase):

    # ....


    @property
    def content(self):
        return b''.join(self._container)

    @content.setter
    def content(self, value):
        # Consume iterators upon assignment to allow repeated iteration.
        if hasattr(value, '__iter__') and not isinstance(value, (bytes, str)):
            content = b''.join(self.make_bytes(chunk) for chunk in value)
            if hasattr(value, 'close'):
                try:
                    value.close()
                except Exception:
                    pass
        else:
            content = self.make_bytes(value)
        # Create a list of properly encoded bytestrings to support write().
        self._container = [content]

    def __iter__(self):
        return iter(self._container)

    def write(self, content):
        self._container.append(self.make_bytes(content))

    # ...

    def writelines(self, lines):
        for line in lines:
            self.write(line)

Как видите, содержимое ответа отображается как свойство (чтение / запись) content, но на самом деле хранится в атрибуте _container. Это используется для того, чтобы 1 / убедиться, что содержимое сохранено в ожидаемом формате, 2 / разрешить поддержку операций response.write() и iter(response).

Две точки об использовании списка здесь:

1 / использование списка для динамического построения строк - довольно распространенная идиома Python - добавление в список и присоединение к нему в конце обычно быстрее, чем объединение строк

2 / это также позволяет сделать объект HttpResponse «файловым» объектом - HttpResponse имеет аналогичные close, write, writelines, flush , tell и __iter__ операций.

Почему это второй элемент в списке _container?

Возможно, потому что он записан как второй элемент.

...