0

我正在 Django 中开发图书馆管理系统。

Book在 appApp1和 Model中有一个模型StudentEmployeeApp2. 学生最多可以发行 3 本书,但员工可以发行任意数量的书籍。

如何在 django 中做到这一点?我想我应该ForeignKey在`Book Model中使用,像这样:

class Book(models.Model):
    ...
    issued_to = models.ForeignKey(Student) # <-- Student or Employee
                                           #     how do I do that?

但是我如何确保最多 3 个Book实例与单个Student实例相关。

4

2 回答 2

1

在我看来,您应该研究 django 模型的clean()方法。当您尝试保存实例时会调用它。对于您的情况,代码可能如下所示(未经测试):

from django.core.exceptions import ValidationError


class Person(models.Model):
    max_books = 1

    def clean(self):
        books_count = self.books.all().count()
        if books_count >= max_books:
            raise ValidationError("This person has too much books !")


 class Book(models.Model):
    issued_to = models.ForeignKey(Person, related_name="books")

这样,您可以创建 Person 模型的子类,并设置自己的 max_books 限制:

class Student(Person)
    max_books = 3

class Employee(Person)
    max_books = 30

但是,要小心,因为使用此解决方案,您将依赖 django 模型的具体继承,这可能会导致性能问题

于 2013-10-10T16:43:59.623 回答
0

另一种解决方案可能是使用 django 信号。

Django 将pre_save在保存任何模型之前发送一个信号,因此您可以挂钩一个函数来对其做出反应并执行您的检查。

类似于(以@Eliot Berriot 解决方案为基础):

from django.db.models.signals import pre_save
from django.core.exceptions import ValidationError

def validate_num_books(sender, **kwargs):
    if isinstance(sender, Student):
        max_books = 3
    elif isinstance(sender, Employee):
        max_books = 30

    books_count = sender.books.all().count()
    if books_count >= max_books:
        raise ValidationError("This person has too much books !")

pre_save.connect(validate_num_books, sender=Employee, dispatch_uid='validate_num_books')
pre_save.connect(validate_num_books, sender=Student, dispatch_uid='validate_num_books')

笔记:

  1. 我不确定 ValidationError 是否会产生预期的效果。希望绕过正在保存的模型就足够了,但也许它并不能完全那样工作,或者在某些情况下会这样做,或者在其他情况下不会......将此片段视为实验性伪代码。

  2. 正如您可能已经从上面的观点猜到的那样,我不习惯信号,而且仍然有点厌倦这些信号。这可能完全没问题,但如果出现更清洁的解决方案,我可能会选择它并完全避免信号。越简单通常越好。

  3. 与艾略特的回答相比,我可以看到这个解决方案的唯一优势是它避免了继承,正如他所说,这会导致性能问题。但是,如果您避免在父类上定义字段,我认为您应该没问题。

如果您决定尝试信号,请从这里开始

于 2013-10-10T18:58:52.597 回答