2015-02-14 2 views
1

Я относительно новичок в уровне абстракции базы данных Django. Честно говоря, у меня нет такого большого опыта взаимодействия с базами данных через любую систему. В любом случае, я работаю над личным проектом и не доволен своим текущим дизайном, по крайней мере, по отношению к моим запросам. Я думал, что обращусь к сообществу за советом о том, как справиться с моей проблемой.Интеллектуальное структурирование Django Модели и запросы

Здесь приведен упрощенный случай, чтобы начать обсуждение. Предположим, мы моделируем информацию о стране. Мы можем придумать следующее:

class Country(models.Model): 
    ... 

class Region(models.Model): 
    country = models.ForeignKey(Country) 
    ... 

class State(models.Model): 
    region = models.ForeignKey(Region) 
    ... 

class County(models.Model): 
    state = models.ForeignKey(State) 
    ... 

class City(models.Model): 
    state = models.ForeignKey(County) 
    ... 

Хорошо. Я доволен этой структурой, потому что нет избыточной информации. ура. Однако, когда дело доходит до создания многих запросов, которые я хочу сделать, я получаю заявление, как это:

# get the country a city is in 
def get_country(city): 
    return Country.objects.get(region__state__county__city=city) 

Это работает, но это беспокоит меня совсем немного по следующей причине: когда я указал мои модели , Я дал Djano структуру моей базы данных. А именно, система уже знает, что город находится в округе, графство находится в состоянии, государство находится в регионе и, наконец, регион находится в стране. Когда я пишу запрос выше, я предоставляю избыточную информацию; структура уже предполагает, что существует только одна страна, связанная с каждым городом. Поэтому, учитывая город, очевидно, в какой стране он находится. Почему я должен указать его еще раз?

Необходимость в этом имеет негативное влияние на развитие по ряду причин. Сначала рассмотрим, например, a get_region() функция:

#get the region a city is in: 
def get_region(city): 
return Region.objects.get(state__county__city=city) 

Все об этом почти идентична функции get_country; в запросе get_country уже содержится информация, необходимая для получения моего региона, так что я снова , информирующий систему о том, что города находятся в округах, находящихся в государствах, находящихся в регионах.

Далее рассмотрим следующий сценарий: я понимаю, что я неправильно понял первоначальные требования, и мне даже не нужно учитывать «регионы». Итак, протрите эту модель и измените модель состояния, чтобы вместо этого ссылаться на страну. Проблема в том, что теперь мы должны также переписать все запросы.

Это становится уродливым быстро. Предположим, нам нужны вспомогательные методы на наших моделях для получения соответствующей информации о иерархии. Например, у страны могут быть методы get_states(), get_counties(), get_cities(). Государства будут иметь get_country(), а также get_county() и get_cities(). И так далее, каждый получает картину. Это кажется разумным, поскольку он предоставит API, с помощью которого другие части системы могут получить доступ к этой географической информации таким образом, который не соответствует макету базы данных. Однако это также означает, что из-за того, как мы пишем запросы, питающие эти функции, каждая модель должна иметь макроскопическое понимание базы данных. Эта неспособность отделить семантику географии от внедрения нашей базы данных снова приведет к много повторной информации и потребует больших усилий, если в эту структуру необходимо внести изменения.

Итак, друзья, пожалуйста, просветите меня. Я не думаю правильно о взаимоотношениях между моделями? Разве я не понимаю философию слоя базы данных Django? Я пропустил некоторые подмножества функций, которые помогут мне прояснить это?

+1

Вы действительно хотите, чтобы поля OneToOne здесь вообще? Это подразумевает не только то, что город может находиться только в одной стране, но в стране может быть только один город, что звучит не так. –

+0

Ах, извините. Я изменил свой пример миллион раз и забыл вернуться к ForeignKey. –

+0

'Страна' определяется два раза. – allcaps

ответ

0

IMO, это ситуация, когда полностью нормализованное решение является «правильным», но может быть слишком громоздким для задачи. Я мог бы немного объяснить денормализацию и сохранить fkeys для отношений, которые мне нужно использовать часто.Например:

class City(models.Model): 
    county = models.ForeignKey(County) 
    region = models.ForeignKey(Region) 
    state = models.ForeignKey(State) 
    country = models.ForeignKey(Country) 

    def save(self, *args, **kw): 
     self.region = self.county.region 
     self.state = self.county.region.state 
     self.country = self.county.region.state.country 
     super(City, self).save(*args, **kw) 

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

В любом случае, я бы сказал, что вы бы не хотите, чтобы Django предположил, что City должен ссылаться на страну, вы бы хотели указать это явно. Что делать, если вы добавили таблицу, связанную с городом и страной, и ваше приложение сломалось, потому что Django предположил, что города и страны связаны иначе?

0

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

+0

Я задавался вопросом о подобном подходе, но не знал о его достоинствах. Люди делают такие вещи? Конечно, могут возникнуть проблемы с производительностью, если каждый запрос вызывает поиск через график моделей, хотя на данном этапе это не было бы такой проблемой. . Более серьезная проблема заключается в том, что уже сказал @dylrei: если я использую такой автоматический подход, существует опасность того, что будущие изменения в структура модели может привести к определенной двусмысленности –

+0

В вашей базе данных не будет дополнительного запроса, в каждом запросе будет только другое условие «WHERE». И, на мой взгляд, это один из случаев, когда QuerySet должен быть настроен – GwynBleidD

+0

«И, на мой взгляд, это один из случаев, когда QuerySet должен быть настроен». Разве эта проблема не возникает относительно часто? Если да, то почему это еще не встроено в Django? Меня не беспокоит сама работа над подклассификацией; Я просто хочу убедиться, что я понимаю тонкости этих проектных решений. Спасибо! –

Смежные вопросы