Отображение частичных табличных встроенных моделей в Django - PullRequest
0 голосов
/ 30 июня 2010

Давайте посмотрим, смогу ли я объяснить, у меня есть следующие модели:

class BillHeader(models.Model):
    number = models.CharField(_('Bill number'), max_length=10, unique=True, \
    default=__number)
    client = models.ForeignKey(ClienteYProveedor, verbose_name=_('Client'))
    date = models.DateTimeField(_('Date'), default=datetime.now)

    def __unicode__(self):
        return str(self.number)

    class Meta:
        abstract = True

class BillFooter(models.Model):           
    base_import = models.DecimalField(_('Base import'), max_digits=12, \
    decimal_places=2)

    class Meta:
        abstract = True

class BillBody(models.Model):        
    description = models.CharField(_('Description'), max_length=200)
    amount = models.DecimalField(_('Amount'), max_digits=6, decimal_places=2)
    discount = models.DecimalField(_('Discount'), max_digits=4, \
    decimal_places=2)
    price = models.DecimalField(_('Price'), max_digits=12, decimal_places=2)
    unitaryprice = models.DecimalField(_('Unitary Price'), max_digits=12, \
    decimal_places=2)

    def __unicode__(self):
        return self.description
    class Meta:
        abstract = True

class EmittedBill(BillHeader, BillBody, BillFooter):
    pass

class ReceivedBill(BillHeader, BillBody, BillFooter):
    pass

Когда пользователь добавляет счет Emmited или Received, мне нужно показать BillHeader как обычный набор полей, но BillBodyи BillFooter должно быть TabularInline.

Если я добавлю их как TabularInline в admin.py, возникнет ошибка, говорящая о том, что им нужно ForeignKey для связанных моделей.Конечно, я не могу поставить эти внешние ключи, потому что они объявлены внизу.Я думаю, что вы, ребята, называете это «обратными внешними ключами».

Мой вопрос таков: как я могу сделать это, чтобы показать TabularInlines в админе, не создавая беспорядка ?.Я могу сделать это без абстрактных базовых классов, но потом возникает другая проблема, он показывает другой ForeignKey в TabularInline (если вы находитесь на EmmitedBills, он показывает FK для ReceivedBills в TabularInline и наоборот), и я не смог исключитьих.

Извините, если это глупый вопрос, но я не программист (это просто хобби), и я действительно путаюсь с моделями данных.


Я объясню лучше:

У меня есть два типа счетов, Emitted и Received, и оба они отображаются в админке (поэтому я не использовал BooleanField, чтобы пометитьих).Оба типа имеют одинаковые поля, за исключением одного, номера счета, который в Emmitted будет создан автоматически.Каждый счет состоит из 1 заголовка с номером, клиентом и датой, 1 или более встроенных записей тела с описанием, суммой, ценой и т. Д. И 1 встроенным нижним колонтитулом, показывающим общую стоимость без учета налогов, примененных налогов и т. Д.1025 *

Обновление

Я сделал все, но у меня проблема, в моей новой модели BillBody есть два FK (EmmitedBill и ReceivedBill), и они отображаются в TabularInline.Как я могу их скрыть? Field.exclude () выдает ошибку.

1 Ответ

2 голосов
/ 30 июня 2010

Я не до конца понимаю ваш вопрос, но вы можете использовать

ForeignKey('ModelName')

вместо

ForeignKey(ModelName)

, если модель ModelName еще не объявлена. Может быть, это решит вашу проблему.

Встроенные администраторы (например, TabularInline) используются только при наличии отношения «один ко многим», которое создается ForeignKey на стороне many . Если у вас нет такого внешнего ключа, вы не можете использовать встроенного администратора. Наследование определенно отличается от ForeignKey.

Однако я думаю, что ваша модель данных неверна. Кажется, вы хотите хранить счета. Существует два типа счетов: emitted и received. Счета emitted и received имеют одинаковые поля. Кроме того, вы хотите, чтобы каждый счет состоял из заголовка с номером, клиентом и датой, 1 или более записей тела, где каждая запись хранит информацию, которую вы храните в BillBody и 1 или более десятичных знаков base_number.


Вероятно, лучшая модель данных для вас

class Bill(models.Model):
    number = models.CharField(_('Bill number'), max_length=10, unique=True, default=__number)
    client = models.ForeignKey(ClienteYProveedor, verbose_name=_('Client'))
    date = models.DateTimeField(_('Date'), default=datetime.now)

    def get_total_price(self):
        return sum([entry.price for entry in self.entries])

class BillEntry(models.Model):
    bill = models.ForeignKey(Bill, related_name='entries')

    description = models.CharField(_('Description'), max_length=200)
    amount = models.DecimalField(_('Amount'), max_digits=6, decimal_places=2)
    discount = models.DecimalField(_('Discount'), max_digits=4, decimal_places=2)
    price = models.DecimalField(_('Price'), max_digits=12, decimal_places=2)
    unitaryprice = models.DecimalField(_('Unitary Price'), max_digits=12, decimal_places=2)

Я пропустил __unicode__ методы.

Теперь у вас есть внешний ключ от BillEntry до Bill, и вы можете использовать табличную строку. Я не понял, как вы используете base_import, поэтому я пропустил это.

Расчет цены

Если ваш price должен всегда равняться чему-то вроде amount*unitaryprice - discount или amount*(unitaryprice-discount), тогда вы не должны помещать это в поле, а вычислять его, когда это необходимо, в Python или в базе данных. Если вы хотите сделать это в Python, вы можете использовать метод, подобный get_total_price. Если вы хотите вычислить их при запросе к базе данных, то немного сложнее заставить ее работать с Django.

В последнем случае вы можете взглянуть на представления SQL, но я думаю, что это немного сложно для новичка. Другой вариант - использовать пользовательское выражение SQL:

BillEntry.objects.extra(select={'price': 'amount*unitaryprice-discount'})

Это вычислит цену для всех записей во время выбора.

Update

Если вы добавляете два подкласса для выставленных и полученных счетов и используете наследование нескольких таблиц , то вы можете использовать один внешний ключ от BillEntry до Bill.

class EmittedBill(Bill):
    pass

class ReceivedBill(Bill):
    pass

Возможно, вам также следует подумать о модели базы данных, сгенерированной Django. Обычно вы хотите хранить только элементарные данные в базе данных, а не вычисленные данные (как вы хотите сделать в нижнем колонтитуле). Таким образом, если цены рассчитываются с использованием некоторой формулы и с использованием unitaryprice, amount и т. Д., Вы не должны хранить результат этой формулы, а пересчитывать его при необходимости (и в конечном итоге кэшировать, чтобы избежать повторных вычислений). Если вы этого не сделаете, есть вероятность, что вы в какой-то момент обновите что-то (например, amount) и забудете обновить вычисленные значения (price), что приведет к несогласованности в вашей базе данных (и, следовательно, к ошибкам в ваше приложение). Хорошая база данных имеет ограничения, поэтому невозможно хранить противоречивые базы данных, не нарушив хотя бы одно ограничение.

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

...