Django 支持的图书馆借阅系统
我正在开发一个图书馆系统来管理我们办公室的某些项目,我不需要一个成熟的集成图书馆系统,所以我决定使用 Django 手动创建一个。
下面是我的模型的简化版本:
class ItemObjects(models.Model):
# Static Variables
IN_STATUS = 'Available'
OUT_STATUS = 'Checked out'
MISSING = 'Missing'
STATUS_CHOICES = (
(IN_STATUS, 'Available'),
(OUT_STATUS, 'Checked out'),
(MISSING, 'Missing'),
)
# Fields
slug = models.SlugField(unique=True)
date_added = models.DateField(auto_now_add=True)
last_checkin = models.DateTimeField(editable=False, null=True)
last_checkout = models.DateTimeField(editable=False, null=True)
last_activity = models.DateTimeField(editable=False, null=True)
status = models.CharField(choices=STATUS_CHOICES, default=IN_STATUS, max_length=25)
who_has = models.OneToOneField(User, blank=True, null=True)
times_out = models.PositiveIntegerField(default=0, editable=False)
notes = models.CharField(blank=True, max_length=500)
history = models.TextField(blank=True, editable=False)
pending_checkin = models.BooleanField(default=False)
pending_transfer = models.BooleanField(default=False)
首先,我使用 ItemObject
上的方法来处理向用户签出项目的过程,而 who_has
是一个 EmailField< /code> 因为我无法使用
CharfField
来填充登录用户的名称,但我认为使用 OneToOneField
可能更接近“正确”的方式这样做..同时who_has
是一个 EmailField
,以下方法有效:
def check_out_itemobject(self, user):
user_profile = user.get_profile()
if self.status == 'Available' and self.who_has == '':
self.status = 'Checked out'
self.who_has = user.email
self.last_checkout = datetime.datetime.now()
self.last_activity = datetime.datetime.now()
self.times_out += 1
if self.history == '':
self.history += "%s" % user_profile.full_name
else:
self.history += ", %s" % user_profile.full_name
if user_profile.history == '':
user_profile.history += self.title
else:
user_profile.history += ", %s" % self.title
else:
return False # Not sure is this is "right"
user_profile.save()
super(ItemObjects, self).save()
现在我使用的是 OneToOneField
这不起作用,所以我开始考虑使用ModelForm
的子类,但我在这里看到的所有案例似乎都不适合我想做的事情;我的表单是一个按钮,仅此而已。以下是我查看的一些问题:
(Django) (外键问题) model.person_id 可能not be NULL
我走在正确的轨道上吗使用某种改变的 save() 方法,或者 ModelForm 子类是可行的方法吗?
编辑/更新:非常感谢@ChrisPratt!
因此,我试图让 Chris Pratt 关于显示 ItemHistory 的建议起作用,但是当我尝试在页面上呈现它时,我收到一个 AttributeError
,指出“'User'对象没有属性'timestamp'” 。所以我的问题是,当 last_activity
是 ItemObject
对象上的属性时,为什么它会抱怨 User
对象?
我的观点:
@login_required
def item_detail(request, slug):
item = get_object_or_404(Item, slug=slug)
i_history = item.last_activity
user = request.user
return render_to_response('items/item_detail.html',
{ 'item' : item,
'i_history': i_history,
'user' : user })
我不明白为什么此时会出现 User
对象。
EDIT2:没关系,历史显然是一个 M2M 领域,其目标是用户。这就是为什么!
I am working on a library system to manage certain items in our office, I don't need a full-blown integrated library system so I decided to hand roll one with Django.
Below is a simplified version of my model:
class ItemObjects(models.Model):
# Static Variables
IN_STATUS = 'Available'
OUT_STATUS = 'Checked out'
MISSING = 'Missing'
STATUS_CHOICES = (
(IN_STATUS, 'Available'),
(OUT_STATUS, 'Checked out'),
(MISSING, 'Missing'),
)
# Fields
slug = models.SlugField(unique=True)
date_added = models.DateField(auto_now_add=True)
last_checkin = models.DateTimeField(editable=False, null=True)
last_checkout = models.DateTimeField(editable=False, null=True)
last_activity = models.DateTimeField(editable=False, null=True)
status = models.CharField(choices=STATUS_CHOICES, default=IN_STATUS, max_length=25)
who_has = models.OneToOneField(User, blank=True, null=True)
times_out = models.PositiveIntegerField(default=0, editable=False)
notes = models.CharField(blank=True, max_length=500)
history = models.TextField(blank=True, editable=False)
pending_checkin = models.BooleanField(default=False)
pending_transfer = models.BooleanField(default=False)
At first I was using a method on ItemObject
to process checking out an item to a user and who_has
was an EmailField
because I couldn't get a CharfField
to populate with the logged in user's name, but I figured using a OneToOneField
is probably closer to the "right" way to do this.. While who_has
was an EmailField
, the following method worked:
def check_out_itemobject(self, user):
user_profile = user.get_profile()
if self.status == 'Available' and self.who_has == '':
self.status = 'Checked out'
self.who_has = user.email
self.last_checkout = datetime.datetime.now()
self.last_activity = datetime.datetime.now()
self.times_out += 1
if self.history == '':
self.history += "%s" % user_profile.full_name
else:
self.history += ", %s" % user_profile.full_name
if user_profile.history == '':
user_profile.history += self.title
else:
user_profile.history += ", %s" % self.title
else:
return False # Not sure is this is "right"
user_profile.save()
super(ItemObjects, self).save()
Now that I am using a OneToOneField
this doesn't work, so I started looking at using a subclass of ModelForm
but none of the cases I saw here on SO seemed to apply for what I am trying to do; my form would be a button, and that's it. Here are some of the questions I looked at:
Django: saving multiple modelforms simultaneously (complex case)
(Django) (Foreign Key Issues) model.person_id May not be NULL
So was I on the right track with a sort of altered save() method, or would a ModelForm subclass be the way to go?
EDIT/UPDATE: Many thanks to @ChrisPratt!
So I am trying to get Chris Pratt's suggestion for showing ItemHistory to work, but when I try to render it on a page I get an AttributeError
that states "'User' object has no attribute 'timestamp'". So my question is, why is it complaining about a User
object when last_activity
is an attribute on the ItemObject
object ?
My view:
@login_required
def item_detail(request, slug):
item = get_object_or_404(Item, slug=slug)
i_history = item.last_activity
user = request.user
return render_to_response('items/item_detail.html',
{ 'item' : item,
'i_history': i_history,
'user' : user })
I do not see why a User
object is coming up at this point.
EDIT2: Nevermind, history is clearly a M2M field whose target is User. That's why!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
假设用户将自己登录并签出书籍,那么您最可能需要的是
User
的ForeignKey
。一本书在任何给定时间都只有一个用户
,但大概用户
也可以查看其他项目。如果存在某种限制,即使该限制实际上是每个用户一个,最好在模型的clean
方法中验证这一点。例如:现在,您的结帐方法存在许多问题。首先,
status
应该是一组定义的选择,而不仅仅是随机字符串。然后,您可以运行检查,如下所示:
如果您愿意,也可以使用字符串和
CharField
来代替。关键是将静态文本与代码分离,这可以为您的应用程序提供更大的灵活性。接下来,
history
需要是ManyToManyField
。现在,您的“历史记录”只是最后一次签出该项目的人或用户最后一次签出的项目是什么,因此毫无用处。然后,您可以获取完整的历史记录:
要添加新的历史记录,您可以执行以下操作:
auto_now_add
属性确保在创建关系时自动设置时间戳。然后,您实际上可以完全摆脱
last_checkout
和last_activity
字段并使用如下所示的内容:然后,您可以正常使用它们:
最后,您的结帐方法是不是
save
的覆盖,因此不适合调用super(ItemObject, self).save()
。只需使用 self.save() 即可。Assuming users will log in and check out books to themselves, then what you most likely want is a
ForeignKey
toUser
. A book will only have oneUser
at any given time, but presumablyUser
s could check out other items as well. If there is some limit, even if the limit is actually one per user, it would be better to validate this in the model'sclean
method. Something like:Now, you checkout method has a number of issues. First,
status
should be a defined set of choices, not just random strings.Then, you can run your checks like:
You could use strings and a
CharField
instead if you like, as well. The key is to decouple the static text from your code, which allows much greater flexibility in your app going forward.Next,
history
needs to be aManyToManyField
. Right now, your "history" is only who last checked the item out or what the last item the user checked out was, and as a result is pretty useless.Which then allows you to get full histories:
To add a new history, you would do:
The
auto_now_add
attribute ensures that the timestamp is automatically set when the relationship is created.You could then actually get rid of the
last_checkout
andlast_activity
fields entirely and use something like the following:And, you can then use them as normal:
Finally, your checkout method is not an override of
save
so it's not appropriate to callsuper(ItemObject, self).save()
. Just useself.save()
instead.