V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
magine
V2EX  ›  Django

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

  •  
  •   magine ·
    Ma233 · 2014-08-04 11:14:36 +08:00 · 5134 次点击
    这是一个创建于 3559 天前的主题,其中的信息可能已经有所发展或是发生改变。
    类似于这样:

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

    def auto_init(self):
    return len(self.objects.filter(foo))+1
    17 条回复    2015-06-25 10:02:35 +08:00
    mengzhuo
        1
    mengzhuo  
       2014-08-04 11:18:34 +08:00   ❤️ 1
    请检讨一下你的数据库设计
    --------------------------------
    另:这个叫default
    https://docs.djangoproject.com/en/dev/ref/models/fields/#default
    magine
        2
    magine  
    OP
       2014-08-04 11:23:43 +08:00
    https://gist.github.com/52db77e54f6ae9e3ab19.git
    贴一份缩进的代码

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

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

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

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


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

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

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

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

    是不是就不得不放在view中实现了?
    yueyoum
        8
    yueyoum  
       2014-08-04 13:31:38 +08:00   ❤️ 1
    @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
        9
    magine  
    OP
       2014-08-04 14:16:52 +08:00
    @yueyoum

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

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

    每次提问django问题都有你,大神等有机会去成都一定当面道谢啊。
    yueyoum
        10
    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
        11
    magine  
    OP
       2014-08-04 16:55:12 +08:00
    @yueyoum
    我认为应该在删除的时候处理编号。
    yueyoum
        12
    yueyoum  
       2014-08-04 16:59:19 +08:00
    @magine

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

    什么情况被你遇到呢?
    magine
        16
    magine  
    OP
       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
        17
    magine  
    OP
       2015-06-25 10:02:35 +08:00
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2484 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 14:27 · PVG 22:27 · LAX 07:27 · JFK 10:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.