2015-02-18 4 views
3

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

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

class Application(models.Model): 
    first_name = CharField(max_length=255) 
    last_name = CharField(max_length=255) 
    date_of_birth = DateField() 
    married = BooleanField() 
    # ...other stuff 

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

complete = BooleanField() 

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

class CompleteApplication(models.Model): 
    application = ForeignKey(Application) 

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

Метод 1:

completed_applications = Application.objects.filter(complete=True) 

Метод 2:

pks = CompleteApplication.objects.all().values_list("application__pk") 
complete_applications = Application.object.filter(pk__in=pks) 

Способ 2 состоит из двух строк кода VS. один, а также два запроса, тогда как раньше их хватило, поэтому производительность базы данных будет хитом.

Существует третий способ сделать что-то: вместо создания модели, которая отслеживает полные приложения, мы могли бы создать модель метаданных, в которой хранятся любые метаданные, которые мы хотели бы присоединить к модели Application. Для наших целей эта модель может содержать поле, которое отслеживает полноту. Тем не менее, этот подход также имеет преимущество, позволяющее связать произвольное количество полей метаданных с каждым приложением, не требуя для каждой новой таблицы БД (как в случае с методом 2 выше).

class ApplicationMeta(models.Model): 
    application = ForeignKey(Application) 
    complete = BooleanField() 

И, для полноты картины (каламбур), чтобы запросить все законченные приложения, мы будем использовать следующее заявление:

completed_applications = Application.objects.all(applicationmeta__complete=True) 

Хорошие и простой, как метод 1, но запрос, конечно, больше работы для базы данных. Этот метод также имеет еще один недостаток для некоторых приложений. Представьте, например, что мы хотим отслеживать дополнительную информацию о приложениях: они могут быть подтверждены или отклонены. Однако, если приложение не подтверждено, оно NOT обязательно означает, что оно отклонено: оно может быть ожидающим рассмотрения. Кроме того, предположим, что мы хотим отслеживать дату подтверждения и дату отклонения (если это применимо, конечно). Тогда наша модель метаданных становится следующим:

class ApplicationMeta(models.Model): 
    complete = BooleanField() 
    confirmed = BooleanField() 
    rejected = BooleanField() 
    date_confirmed = DateField() 
    date_rejected = DateField() 

Хорошо ... это работает, но это начинает быть беспорядок.Во-первых, мы теперь открыли нашу систему для возможной ошибки: что если какой-то экземпляр ApplicationMeta отклонил и подтвердил установленный True? Мы могли бы сделать некоторые причудливые работы с нашим классом (возможно, переопределить setattr), чтобы выбросить исключение, если произойдет что-то смешное, поэтому мы можем не продолжать работать с БД, но это добавление осложнений, которые, я надеюсь, не нужны. Кроме того, любая модель будет либо иметь не более одного из date_confirmed или date_rejected set. Это проблема? Здесь я на самом деле не уверен. Я предполагаю, что это, скорее всего, пустая трата пространства, но я этого не знаю. Этот пример прост, что, если более сложные примеры представляют нам тонны полей, которые обязательно не будут заполнены? Кажется, плохая конструкция.

Я хотел бы услышать некоторые мысли об этих идеях.

Спасибо!

ответ

1

Если у вас есть огромное количество возможных метаданных, третий подход может иметь смысл по соображениям производительности. Я бы не сделал этого для нескольких столбцов boolean и date. Если вас беспокоит читаемость самих моделей, вы можете разделить любые метаданные на абстрактную базовую модель. Вы даже можете повторно использовать абстрактную модель для других моделей, для которых требуются одни и те же метаданные. Информация будет по-прежнему жить в вашей модели Application.

Если вы выполняете второй или третий подход, я бы использовал OneToOneField, а не ForeignKey. Это гарантирует, что нет двух возможных моделей ApplicationMeta для одного Application и имеет дополнительное преимущество индекса базы данных UNIQUE.

Что касается состояния приложения, то он точно соответствует такому состоянию, как NullBooleanField. Он начинается с None (NULL в дБ), что означает «нет значения». Затем его можно установить на True (принято) или False (отклонено).

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