怎样在 models.Model 新建时自动赋值

2014-08-04 11:14:36 +08:00
 magine
类似于这样:

class A(models.Model):
num = models.IntegerField(auto_init=auto_init)

def auto_init(self):
return len(self.objects.filter(foo))+1
5177 次点击
所在节点    Django
17 条回复
mengzhuo
2014-08-04 11:18:34 +08:00
请检讨一下你的数据库设计
--------------------------------
另:这个叫default
https://docs.djangoproject.com/en/dev/ref/models/fields/#default
magine
2014-08-04 11:23:43 +08:00
https://gist.github.com/52db77e54f6ae9e3ab19.git
贴一份缩进的代码

@mengzhuo
数据库的设计出问题了?
mengzhuo
2014-08-04 11:27:46 +08:00
@magine

初始化用的数值不应该放到model里,
应该在views里面加入,
等你需要迁移的时候就知道这样设计有多坑了
yueyoum
2014-08-04 12:21:28 +08:00
@mengzhuo

初始化的数值 就要放到 models中, 这样看 Model定义才清楚明了。

比如 age = models.IntegerField(default=0)
magine
2014-08-04 12:58:53 +08:00
@yueyoum
表示赞同


@mengzhuo
问一下你们都怎么高效查看文档的……
表示个人英语水平还是不差的,
我也一直在那个页面找的,但是我搜的是“auto”,然后就只能找到自动设置时间,然后就坑了。
果然还是经验太少了么……
yueyoum
2014-08-04 13:16:53 +08:00
django 文档很优秀了。 右侧有导航。

不过要学习一个新东西,最有效的方式就是 把文档一个字一个字的看一边。
而不是直接按照自己的想法 去搜索
magine
2014-08-04 13:18:40 +08:00
@yueyoum

文档里说,The default cannot be a mutable object。

我希望default接受的是一个动态的函数结果,类似于这样:
https://gist.github.com/12ac8b2525f0fb6301fa

是不是就不得不放在view中实现了?
yueyoum
2014-08-04 13:31:38 +08:00
@magine gist 半天没打开,挂代理也没用。

我大概知道你什么意思。 如果一个字段要提供 动态变化的默认值
可以在views里做,不过还是不推荐。

如果是和其他业务逻辑没什么关联的,推荐重写Model的 save 方法


class Question(models.Model):
num = models.SmallIntegerField()

def save(self, *args, **kwargs):
self.num = Question.objects.filter(paper=self.paper).count() + 1
super(Question, self).save(*args, **kwargs)


但其实这段代码并不安全,

如果有两个 Question.objects.create() 并发执行了, 那么新存入的 这两个 的num有可能一样。

所以安全做法还是用 signals

from django.db.models.signals import post_save

class Question(models.Model):
num = models.SmallIntegerField()


def save_handler(instance, change, **kwargs):
if change:
return

instance.num = Question.objects.filter(paper=instance.paper).count() + 1
instance.save()

post_save.connent(save_handler, sender=Question)



上面代码是凭记忆写的, 有些参数可能错误。
magine
2014-08-04 14:16:52 +08:00
@yueyoum

第一种方法对我来说暂时是安全的,
因为只有使用教师帐号登陆之后才会拥有创建考卷的权利,
而且新建的考卷中有外键指向这一帐号。
(一般不会出现一个老师帐号多人登陆还修改同一套试卷的坑爹状况吧……)

额……第二种方法我还没看懂!QAQ

每次提问django问题都有你,大神等有机会去成都一定当面道谢啊。
yueyoum
2014-08-04 16:27:38 +08:00
@magine

不是大神………………

我觉得你 Question 中的 num (题号) 的生成方式有 隐患
比如 已经生成了 1,2,3,4 个 Question, 他们的num分别是 1,2,3,4
然后把 3号 Question删除了, 再创建一个新的 Question

那么这个新 Question的num 也是4,
这组题目中就有两个 题号为4 的 题目了。


想要题号不重复,应该是这么做:

from django.db.models import Max

if Question.objects.count() == 0:
....new_num = 1
else:
....num_num = Question.objects.aggregate(Max(num))['num__max'] + 1


这种情况下, 删除3号,再创建新的 Question,其num为 5,
但是 虽然题号没重复,但是 已经不连续了。

所以最好 在 Question 的 Listview admin 上提供一个按钮,
自动重置题号, 会自动将这些 nums 依次递增排列。
magine
2014-08-04 16:55:12 +08:00
@yueyoum
我认为应该在删除的时候处理编号。
yueyoum
2014-08-04 16:59:19 +08:00
@magine

恩,也行。
magine
2014-08-04 18:21:48 +08:00
@yueyoum
而且我觉得删除的话应该以试卷为单位,当然,这就是业务逻辑的问题了。
总之谢谢你啊!
magine
2015-06-24 16:51:35 +08:00
@yueyoum
我来看你的signal了,这种情况还是被我遇上了orz
inlineformset。
yueyoum
2015-06-24 18:04:54 +08:00
@magine

什么情况被你遇到呢?
magine
2015-06-25 10:00:19 +08:00
@yueyoum
```
ItemFormSet = forms.models.inlineformset_factory(
Order, Item,
)

class AddOrderView(CreateView):
template_name = 'new_order.html'
form_class = OrderForm

def get_context_data(self, **kwargs):
context = super(AddOrderView, self).get_context_data(**kwargs)
if self.request.POST:
context['item_formset'] = ItemFormSet(self.request.POST)
else:
context['item_formset'] = ItemFormSet()
return context

def formset_invalid(self, form):
return self.render_to_response(self.get_context_data(form=form))

def form_valid(self, form):
context = self.get_context_data()
formset = context['item_formset']
if formset.is_valid():
self.object = form.save(self.request.user)
# set the order_fk for items
formset.instance = self.object
formset.save()
return redirect(reverse('core:list_orders'))
else:
self.formset_invalid(form)


# 在存储Item(项目)的时候,自动设置其位于Order(订单)中的序号。
```
magine
2015-06-25 10:02:35 +08:00

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/125997

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX