Я относительно новичок в 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. Это проблема? Здесь я на самом деле не уверен. Я предполагаю, что это, скорее всего, пустая трата пространства, но я этого не знаю. Этот пример прост, что, если более сложные примеры представляют нам тонны полей, которые обязательно не будут заполнены? Кажется, плохая конструкция.
Я хотел бы услышать некоторые мысли об этих идеях.
Спасибо!