Начинающий: пытаясь понять, как приложения взаимодействуют в Django - PullRequest
28 голосов
/ 09 декабря 2008

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

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

Рассмотрим следующий пример. На самом деле я бы сам не написал приложение для комментариев, так как хороший код для этого уже существует в Интернете, но это для демонстрационных / практических целей:

MySite / блог / models.py

from django.db import models

class post(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=200)
    content = models.TextField()

MySite / комментарии / models.py

from django.db import models
from mysite.blog.models import post

class comment(models.Model):
    id = models.AutoField()
    post = models.ForeignKey(post)
    author = models.CharField(max_length=200)
    text = models.TextField()

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

Обновление
Согласно рекомендации в одном ответе, я читаю документацию для contrib.contenttypes. Если я правильно читаю, я могу переписать пример приложения для комментариев следующим образом:

from django.db import models  
from django.contrib.contenttypes.models import ContentType
from django.contrib.contentypes import generic

class comment(models.Model):  
    id = models.AutoField()  
    author = models.CharField(max_length=200)  
    text = models.TextField()  
    content_type = models.ForeignKey(ContentType)  
    content_object = generic.GenericForeignKey(content_type, id)  

Это будет правильно?

Ответы [ 4 ]

21 голосов
/ 09 декабря 2008

Взгляните на встроенную в django структуру contenttypes :

django.contrib.contenttypes

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

Например, если у вас есть какой-либо контентный объект, который вы хотите «прикрепить» к другим контентным объектам разных типов, например, разрешив каждому пользователю оставлять «любимую» звезду в сообщении блога, изображении или профиле пользователя, вы можно создать Favorite модель с родовым полем отношения примерно так:

from django.db import models
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic

class Favorite(models.Model):
    user = models.ForeignKey(User)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

Таким образом, вы можете добавить Favorite звезду от любого пользователя к любой модели в вашем проекте. Если вы хотите добавить доступ к API через класс модели получателя, вы можете либо добавить поле обратной родовой связи в модель получателя (хотя это будет «связывание» двух моделей, которых, как вы сказали, вы хотите избежать ) или выполните поиск по модели Favorite с content_type и object_id экземпляра получателя, см. официальную документацию для примера.

3 голосов
/ 09 декабря 2008

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

Вы можете добиться слабой связи с фреймворком contenttypes. Это позволяет приложению быть по-настоящему портативным / подключаемым, но все же интегрированным с другими приложениями.

Я написал приложение для комментариев (да, я заново изобрел колесо), которое можно интегрировать в любое другое приложение, с несколькими строками в шаблоне страницы, где должны публиковаться комментарии (с использованием пользовательских тегов).

Скажем, вы хотите, чтобы "нить" модели была подключена к любой другой модели. Идея состоит в том, чтобы создать общий внешний ключ (см. Документацию по django) и написать небольшую функцию, которая принимает любой объект и возвращает соответствующий ему «поток» (или создает его при необходимости), а также пишет собственный тег шаблона, который использует эту функциональность, например, {% get_thread for arbitrary_object as thread %}. Все сообщения связаны с темой, связанной с объектом, которая может быть любого типа.

Вы можете рассматривать объект «поток» как своего рода прокси-сервер, поэтому вместо того, чтобы сообщение относилось к определенной «статье» или «сообщению в блоге», оно просто связано с потоком, который является абстрактным в каком-то смысле, что является потоком? Это просто коллекция постов. Затем поток позволяет себе быть связанным с любым объектом независимо от его типа. (хотя он делает больше, он может содержать дополнительную информацию, такую ​​как разрешение / запрещение одних сообщений, закрытие / открытие комментариев на странице и т. д.) *

EDIT

Вот как вы можете создать общий внешний ключ с помощью структуры типов контента:

from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType

class Thread( models.Model ):
    object_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    object = generic.GenericForeignKey('object_type', 'object_id')

Вы можете сделать его более «прозрачным», используя неявный «общий» интерфейс, который django предполагает реализовать во всех объектах.

    #inside the Thread class:
    def __unicode__(self):
        return unicode(self.object)
    def get_absolute_url(self):
        return self.object.get_absolute_url()
3 голосов
/ 09 декабря 2008

«То, что я написал выше, импорт модели из другого приложения и установка ее в качестве внешнего ключа, как взаимодействуют приложения Django?»

Да. У меня работает.

У нас есть около 10 приложений, которые заимствуют друг друга.

Это приводит к некоторой зависимости в нашем скрипте модульного теста.

Похоже на это.

  • "собственность". У нас есть простое приложение для владения данными, которое определяет некоторые основные концепции владения, от которых зависят другие приложения. Здесь есть несколько простых таблиц.

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

  • "таблицы". [Не настоящее имя]. Некоторые из наших пользователей создают довольно сложные автономные модели (возможно, с помощью электронных таблиц) и загружают результаты этого моделирования в «таблицы». Это кластер довольно сложных таблиц. Это зависит от "собственности".

  • * 1024 "результат" *. [Не настоящее имя]. Наши результаты основаны на вещах, которые имеют владельцев. Результаты основаны на вещах и таблицах и являются ответами на запросы клиентов. Это не слишком сложно, возможно, только две или три основные таблицы. Это зависит от «вещей» и «таблицы». Нет, это не полностью автономно. Тем не менее, он подвержен большим изменениям, чем другие вещи, от которых он зависит. Вот почему это отдельно.
  • "обработка". Мы планируем и следим за крупными пакетными заданиями. Это в этом приложении. Это действительно универсальный и может быть использован различными способами. Он полностью изолирован.

  • "Добро пожаловать". У нас есть «приветственное» приложение, которое представляет кучу в основном статических страниц. Это не слишком много таблиц. Но это во втором воплощении, потому что первое было слишком сложным. Он полностью обособлен.

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

2 голосов
/ 09 декабря 2008

Ваш код кажется правильным. Я бы оставил пост и комментарий в приложении blog . Я не говорю, что это способ Джанго, но эти модели достаточно близки, чтобы быть в одном приложении.

Как разделить проект

Я бы отделил приложение, если;

  • Я планирую разработать его повторно. (и попробуйте ослабить сцепление)
  • (для больших проектов) Состоит из основного раздела проекта.

С другой стороны; наличие множества крошечных приложений (таких как приложение с одной моделью и двумя представлениями) трудно читать и поддерживать ИМХО.

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

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

Если вы хотите сделать приложение многоразовым и универсальным, например приложение для комментирования, вам может потребоваться интегрировать некоторый механизм настройки. Может быть, какие-то новые настройки или дополнительная конфигурация URL, или специальная директива / метод для ваших моделей ... django.contrib.admin является хорошим примером для этого.

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

...