Лучший дизайн базы данных (модель) для пользовательских таблиц - PullRequest
3 голосов
/ 17 января 2010

Я разрабатываю веб-приложение, используя google appengine и django, но думаю, что моя проблема носит более общий характер.

У пользователей есть возможность создавать таблицы, смотрите: таблицы не представлены в таблице как TABLES. Я приведу вам пример:

First form:
 Name of the the table: __________
 First column name: __________
 Second column name: _________
 ...

Количество столбцов не фиксировано, но существует максимум (например, 100). Тип в каждом столбце одинаковый.

Second form (after choosing a particular table the user can fill the table):
 column_name1: _____________
 column_name2: _____________
 ....

Я использую это решение, но оно неверно:


class Table(db.Model):
    name = db.StringProperty(required = True)

class Column(db.Model):
    name = db.StringProperty(required = True)
    number = db.IntegerProperty()
    table = db.ReferenceProperty(table, collection_name="columns")

class Value(db.Model):
    time = db.TimeProperty()
    column = db.ReferenceProperty(Column, collection_name="values")

когда я хочу вывести таблицу, я беру ее столбцы и из каждого столбца беру их значения:


    data = []
    for column in data.columns:
        column_data = []
        for value in column.values:
            column_data.append(value.time)
        data.append(column_data)
    data = zip(*data)

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

Table as I want:   as I will got:
a z c                 a e c
d e f                 d h f
g h i                 g z i

Лучшие решения? Может быть, используя ListProperty ?

Ответы [ 5 ]

2 голосов
/ 27 января 2010

Вот модель данных, которая может помочь вам:

class Table(db.Model):
 name = db.StringProperty(required=True)
 owner = db.UserProperty()
 column_names = db.StringListProperty()

class Row(db.Model):
 values = db.ListProperty(yourtype)
 table = db.ReferenceProperty(Table, collection_name='rows')

Мои рассуждения: Вам действительно не нужен отдельный объект для хранения имен столбцов. Поскольку все столбцы имеют одинаковый тип данных, вам нужно только сохранить имя, а тот факт, что они хранятся в списке, дает вам неявный номер заказа.

Сохраняя значения в списке в объекте Row, вы можете использовать индекс в свойстве column_names , чтобы найти соответствующее значение в свойстве values ​​.

При хранении всех значений для строки вместе в одном объекте нет возможности появления значений в неправильном порядке.

Предостережение emptor: Эта модель не будет работать хорошо, если к таблице могут быть добавлены столбцы после заполнения данными. Чтобы сделать это возможным, каждый раз, когда добавляется столбец, каждая существующая строка, принадлежащая этой таблице, должна иметь добавленное значение в своем списке values ​​. Если бы было возможно эффективно хранить словари в хранилище данных, это не было бы проблемой, но к списку можно было бы только добавить.

В качестве альтернативы, вы можете использовать Expando ...

Другая возможность состоит в том, что вы можете определить модель Row как Expando, которая позволяет динамически создавать свойства для сущности. Вы можете установить значения столбцов только для столбцов, в которых есть значения, и что вы также можете добавить столбцы в таблицу после того, как в ней есть данные, и ничего не разбивать:

class Row(db.Expando):
    table = db.ReferenceProperty(Table, collection_name='rows')

    @staticmethod
    def __name_for_column_index(index):
        return "column_%d" % index

    def __getitem__(self, key):
        # Allows one to get at the columns of Row entities with
        # subscript syntax:
        # first_row = Row.get()
        # col1 = first_row[1]
        # col12 = first_row[12]
        value = None
        try:
            value = self.__dict__[Row.__name_for_column_index]
        catch KeyError:
            # The given column is not defined for this Row
            pass
        return value

    def __setitem__(self, key, value):
        # Allows one to set the columns of Row entities with
        # subscript syntax:
        # first_row = Row.get()
        # first_row[5] = "New values for column 5"

        self.__dict__[Row.__name_for_column_index] = value
        # In order to allow efficient multiple column changes,
        # the put() can go somewhere else.
        self.put()
1 голос
/ 21 января 2010

Почему бы вам не добавить IntegerProperty в Value для rowNumber и увеличивать его каждый раз, когда вы добавляете новую строку значений, а затем вы можете восстановить таблицу путем сортировки по rowNumber.

0 голосов
/ 26 января 2010

Поместить данные в LongBlob.

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

Я бы предложил просто отформатировать и сохранить все данные от одного пользователя в одном столбце подходящего типа (например, LongBlob). Форматом будет объект со списком столбцов и строк типа. И вы определяете объект на любом языке, который используете для связи с базой данных.

Столбцы в вашей (реальной) базе данных будут такими: User int, TableNo int, Table Longblob. Если у user8 есть 3 таблицы, у вас будут следующие строки:

8, 1, objectcontaintingtable1;
8, 2, objectcontaintingtable2;
8, 3, objectcontaintingtable3;
0 голосов
/ 25 января 2010

Это концептуальная идея, которую я бы использовал: Я бы создал два класса для хранилища данных:

  1. table это послужит словарь, хранящий структуру псевдотаблицы вашего приложения Создайте. было бы два поля: имя_таблицы, имя_столбца, column_order. где column_order даст позицию столбец в таблице

  2. data это будет хранить фактические данные в псевдотаблицы. было бы четыре поля: row_id, table_name, имя столбца, столбец данных. row_id будет то же самое для данных относящиеся к той же строке и будет быть уникальным для данных по всему различные псевдотаблицы.

0 голосов
/ 22 января 2010

Вы сами усложните себе жизнь, если 'таблицы' вашего пользователя не будут храниться как реальные таблицы в реляционной базе данных. Найдите способ создания таблиц и используйте мощь СУБД, или вы изобретаете очень сложное и изощренное колесо.

...