Как связать несколько многоразовых приложений Django вместе?

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

вот пример что я имею в виду: У меня есть приложение для изображений, которое хранит, изменяет размер и отображает изображения. Также у меня есть блог приложение, которое хранит, редактирует и отображает тексты. Теперь я хочу объединить эти два, чтобы показать сообщения в блоге с изображениями.

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

каков наилучший способ сделать это ?

EDIT: Спасибо за ваши очень хорошие ответы, но я все еще ищу более практический пример того, как решить эту проблему. Чтобы завершить мой пример: иногда было бы неплохо использовать приложение без приложения Фото. Но если я жестко закодирую зависимость, это больше невозможно. Так как насчет 3rd app объединить оба ?

4 ответов


введение разговор в нижней части ответа (более прямо к ответу). Я предположу, что у вас есть одно приложение для обработки текста под названием Text и одно приложение для обработки изображений под названием Pictures и третье приложение для ведения блога под названием Blog.

большая картинка

вам нужно будет учиться руководство по языку шаблонов для программистов python. Идея заключается в том, что каждая вещь находится в своем собственном приложении и что у вас есть третье приложение, которое подключается всё. Затем приложения должны предоставить свои модели и представления, как вам нравится (просто не забудьте сосредоточиться на том, что должно делать приложение), а также предоставить набор шаблонов.

как сделать теги включения

сделайте теги включения, и это действительно легко! Это напомнит вам о написании нормальных представлений.

создайте каталог templatetags в папке приложения. Также создайте __init__.py файл в этом templatetags (так что каталог становится python пакет.)

создайте файл python. Имя важно, вы будете использовать это в {% load xyz %} в шаблонах, которые будут использовать ваше приложение. Например, если вызвать файл picturestags.py, вы будете называть
{% load picturestags %} во всех шаблонах, которые будут использовать его.

сначала в файл добавьте некоторые политики, о которых вам не нужно много думать, просто включите это прежде всего:

from django.template import Library
register = Library()

затем добавьте теги, определив функции с тем же именем, что и ваш тег. Я позвоню это display_picture в Примере, и он будет принимать один аргумент url. Функция должна создать словарь,который будет использоваться в шаблоне. Мой пример просто отобразит изображение, на которое указывает url.

@register.inclusion_tag('pictures/display_picture.html')
def display_picture(url):
    return {'picture': url}

создайте шаблоны/изображения пути в вашем приложении и создайте файл display_picture.html внутри содержит:

<img src="{{ picture }}" />

как вы, вероятно, понимаете, @register делает этот тег, что внутри словаря display_picture возвращает то, что вы можно использовать в display_picture.формат html. Очень похоже на ваши обычные функции просмотра.

в конце концов вы получите эти файлы:

pictures/
    __init__.py
    models.py
    views.py
    tests.py
    templates/
        pictures/
            display_picture.html
    templatetags/
        picturetags.py

это все, что вам нужно добавить в приложение фотографию. Чтобы использовать это в своем блоге, вам нужно добавить фотографии в INSTALLED_APPS. Затем в шаблонах, где вам нужно использовать свой собственный недавно испеченный тег, сначала загрузите его:{% load picturestags %} тогда просто добавьте тег {% display_picture https://www.google.com/intl/sv_ALL/images/logos/images_logo_lg.gif %} как это:

{% load picturestags %}
<html>
    <body>
        {% display_picture https://www.google.com/intl/sv_ALL/images/logos/images_logo_lg.gif %}
    </body>
</html>

результаты

это всего лишь маленький пример, но вы можете видеть, что это очень легко расширить. Ваш блог может подключить приложение Text and Pictures, импортировав их модели и внешний ключ. Существует текст подключения и фотографии для определенного сообщения в блоге. Ваш блог.html-шаблон может выглядеть как (упрощенный):

{% load picturestags %}
{% load texttags %}
<html>
    <body>
        <h1>{{ subject }}</h1>
        <div class="article">{% article_to_html articleid %}</div>
        <div class="article_picture">{% display_picture %}</div>
    </body>
</html>

обратите внимание, что только блог имеет зависимости, и это зависимости, которые он должен иметь (без блога текст и картинки...но картинки могут жить и без текста). Внешний вид и размещение должны и могут контролироваться CSS и DIV/SPAN-тегами. Таким образом, вы можете взять свое приложение для фотографий и дать его кому-то, кто понятия не имеет о текстовом приложении и использовать его, отображая изображения по-разному, вероятно, даже не касаясь кода!

включения теги-это единственное, что я знаю, так как я только вчера узнал. Я думаю, что это удобство, предоставляемое Django, чтобы сделать жизнь простой. На на странице документации есть намного больше (включая то, как сделать "реальные" теги сложным способом без "ярлыков"). Поэтому, если вы найдете этот метод ограниченным, прочитайте документацию...у него есть много примеров. В нем также обсуждается, как сделать фильтры, simple_tags, соображения потока и другие продвинутые вещи.

введение

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

я также получил много вдохновения от Google Tech Talk Многоразовые Приложения. В конце (43 минуты) он упоминает некоторые хорошие примеры, такие как django-пометка что он говорит модель для того, как писать многоразовые приложения. Это дало мне идею для всего этого, потому что именно так django-tagging решает эту самую проблему, которую мы имели/имеем.


подумайте об этом так же, как вы использовали бы любое стороннее приложение в своем проекте. "Повторно использовать "не означает"без зависимостей". Напротив, вам будет сложно найти приложение, которое не имеет хотя бы одной зависимости, даже если оно зависит только от библиотек Django или core Python. (В то время как основные библиотеки Python обычно рассматриваются как "безопасные" зависимости, т. е. все будут иметь его, вещи иногда меняются между версиями Python, поэтому вы все еще блокируете свое приложение в конкретный момент времени).

цель повторного использования такая же, как и у DRY: вы не хотите писать один и тот же код снова и снова. В результате имеет смысл вырваться из функциональности, такой как приложение picture, потому что вы можете использовать его снова и снова в других приложениях и проектах, но ваше приложение picture будет иметь зависимости, и другие пакеты будут зависеть от него, пока нет круговых зависимостей, вы хороши (круговая зависимость будет означать, что у вас нет фактически разделили функциональность).


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

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

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

Это все просто немного здравого смысла. Можете ли вы сделать свои приложения тонкими? Если да, то попробуйте создать их, чтобы их можно было использовать повторно. Но не бойтесь принимать зависимости, когда они имеют смысл. Также пробовать разрешить точки расширения, чтобы вы могли потенциально поменять зависимости на другие. Прямой внешний ключ здесь не поможет, но, возможно, что-то вроде сигналов или Restful APIs может.


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

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

планировка

project_root/
    core/
        models/
            mixinmodels1.py
            mixinmodels2.py
            ...
        utils.py
        ...
    app1/
        models/
            __init__.py
            base.py
            basemixins.py
            mixins.py
            concrete.py
        /signals
            __init__.py
            handlers.py
        utils.py
        ...
    app2/
        ...
    ...

модели приложения

base.py: этот модуль реализует только "причину существования" этого приложения в абстрактных классах. Правила таковы:

  • этот модуль обычно импортируется только из core app. Обычно он ничего не импортирует из других приложений в том же проекте.

  • исключение к вышеуказанному правилу когда " причина для существование предполагает существование другого приложения. Например,group приложение предполагает, что есть user приложение где-то. В этом случае способ связать их:

    # project_root/settings.py
    
    AUTH_USER_MODEL = 'app_label.UserModel'
    
    # project_root/groups/models/base.py
    
    from django.conf import settings
    

    , а затем с помощью параметров.AUTH_USER_MODEL для ссылки на user модель

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

    # project_root/settings.py
    
    GROUP_MODEL = 'app_label.GroupModel'
    
  • если вы используете вышеуказанный шаблон, только предполагайте функциональность предоставлено base.py другое приложение с которой вы связаны. Не предполагайте функциональность сложных конкретных классов (я буду обсуждать, где поставить конкретные классы в ближайшее время)

  • конечно, импорт из django, сторонних приложений и пакетов python разрешен.

  • убедитесь, что предположения, которые вы делаете в base.py любого приложения является твердым камнем и не будет многое изменится в будущем. Хороший пример -django-registration Джеймс Беннетт. Его старое приложение, но его привлекательность не ослабла, потому что он сделал твердые предположения. Поскольку хорошие многоразовые приложения делают одну вещь хорошо, нетрудно найти этот набор предположений.

basemixins.py: этот модуль должен реализовывать вилки для конкретных моделей этого приложения. "Вилка" к модели M-это любая модель, содержащая внешний ключ к модели M. Например:

# project_root/groups/models/basemixins.py

from django.conf import settings
from django.db import models

class BaseOwnedByGroup(models.Model):
    """
    This is a plug to the group model. Use this
    to implement ownership like relations with 
    the group model
    """
    owner = models.ForeignKey(settings.GROUP_MODEL,
        related_name = '%(app_label)s_%(class)s_owner',
        verbose_name = 'owner')

    # functionality and manager definitions go here.

    class Meta:
        abstract = True
        app_label = 'groups'

BaseOwnedByGroup является "вилкой" для group модель. Правила здесь следующие: так же, как base.py`

  • при определении "подключается" в basemixins.py, только предполагают функциональность, предоставляемую base.py.
  • импорт только из core, django, сторонние приложения и пакеты python.

mixins.py : этот модуль должен использоваться для двух целей

  • чтобы определить сложные "вилки", который предполагает функциональность сложных конкретных классов, но не отношения с другими приложениями. Сложный штепсельные вилки должны в идеале наследовать один из "базовых разъемов", определенных в basemixins.py.

  • чтобы определить модели mixin (которые не являются "вилками"), которые могут использоваться конкретными классами этого приложения.

concrete.py: этот модуль должен использоваться для определения (вы догадались) конкретных классов этих приложений и для настройки отношений с другими приложениями. Короче говоря, этот модуль предполагает ваш проект и все функциональность, которую вы хотите предоставить в он.

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

  • создать one to one или many to one отношения с моделью M приложения another_app сделайте следующее:

    # project_root/another_app/utils.py
    
    def plug_to_M_factory(version_label):
        """
        This is a factory method which returns
        the plug to model M specified by 
        version_label
        """
        if version_label == 'first_version':
            from another_app.models.basemixins import BasePlugToM
            return BasePlugToM
        if version_label == 'second_version':
            from another_app.models.mixins import PlugToM
            return PlugToM
        ...
    
    # project_root/groups/models/concrete.py
    
    from groups.models.base import BaseGroup
    from another_app.utils import plug_to_M_factory
    
    PlugToMClass = plug_to_M_factory(version_label = 'second_version')
    
    class ConcreteGroup(BaseGroup, PlugToMClass):
        # define your concrete model
    
        class Meta:
            app_label = 'groups'
    
  • создать many to many отношения, рекомендуемый способ-использовать through модель. Наследовать правильный плагин в through модель точно так же (как мы сделали в ConcreteGroup модель)

signals: при настройке отношений часто приходится выполнять операции над моделью M приложения app1, когда модель N приложения app2 изменения. Вы можете использовать сигналы, чтобы справиться с этим. Ваши обработчики могут предполагать функциональность конкретного отправителя, но часто им это не нужно. Предположение базовой версии отправителя в base.py достаточно. Вот почему это хорошая идея, чтобы всегда использовать settings.ModelName для обозначения конкретной модели. Вы можете извлечь класс модели из settings.ModelName строку, либо с помощью ContentType или с помощью проекта wide