V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
maloneleo88
V2EX  ›  Python

django models 自定义方法报错,我这哪里写的有问题?

  •  
  •   maloneleo88 · 2022-04-25 21:19:12 +08:00 · 2452 次点击
    这是一个创建于 703 天前的主题,其中的信息可能已经有所发展或是发生改变。
    .....
    
    
    class Detect(models.Model):
        def chioce_id(self):
            data = self.objects.all()
            id = len(data) + 1
            return id
        detect_id = models.BigIntegerField(verbose_name='编号',default=chioce_id)
        .......
    
    

    为什么一直报我错呢? 我想弄个可自填可手改的序号, 这方法在类里不能用吗?有别的法吗?

    34 条回复    2022-04-28 09:57:42 +08:00
    blueaurora
        1
    blueaurora  
       2022-04-25 21:43:31 +08:00
    虽然你没有把错误的 log 贴上来,但是能发现一个错误: data = self.objects.all() .把 self 改成 Detect ,即:

    data = Detect.objects.all()

    因为 objects 是类中的,不是实例中的
    blueaurora
        2
    blueaurora  
       2022-04-25 21:45:44 +08:00
    至于 default=choice_id , 我感觉也是不对的.. 因为 choice_id 方法 却是实例中的,但字段又是类中的..
    maloneleo88
        3
    maloneleo88  
    OP
       2022-04-25 21:46:39 +08:00
    @blueaurora 错误就是找不到定义的函数 , 谢谢!

    类这里永远也搞不明白
    blueaurora
        4
    blueaurora  
       2022-04-25 21:48:43 +08:00
    把 detect_id 的修改逻辑从字段的 default 里摘出来吧。 不要写在 model 类的定义当中了吧
    blueaurora
        5
    blueaurora  
       2022-04-25 21:49:51 +08:00
    @maloneleo88 嗯嗯,default 的这个,我只是感觉可能有问题,但如果你跑通了那就忽略质疑吧, 这就是 python..
    maloneleo88
        6
    maloneleo88  
    OP
       2022-04-25 21:51:11 +08:00
    @blueaurora 所以应该怎么做才对呢, 如你所料

    进添加页面直接报
    chioce_id() missing 1 required positional argument: 'self'
    blueaurora
        7
    blueaurora  
       2022-04-25 21:51:56 +08:00
    在 java 中,类一般都是静态写好的;但在 python 中,动态创建新类和修改类 跟玩似的
    maloneleo88
        8
    maloneleo88  
    OP
       2022-04-25 21:52:49 +08:00
    @blueaurora 真的是到处都弄不明白,我一般是弄不了了就上 js 魔改 - -!
    blueaurora
        9
    blueaurora  
       2022-04-25 21:54:45 +08:00
    @maloneleo88 啊,比如这里 default 就是 0 或 -1 ; 然后 detect_id 的变化逻辑,写在业务中,比如重写 model 的 save ,在 save 时 去修改 detect_id
    maloneleo88
        10
    maloneleo88  
    OP
       2022-04-25 22:01:37 +08:00
    @blueaurora 你的意思是在 views 里直接拿到 queryset 再往表单 val 里填吧
    gotounix
        11
    gotounix  
       2022-04-25 22:01:42 +08:00
    函数写到类外面,不用参数,self 换成 Detect
    westoy
        12
    westoy  
       2022-04-25 22:12:03 +08:00
    你这个 chioce_id 的生成有点太暴力的啊..........
    maloneleo88
        13
    maloneleo88  
    OP
       2022-04-25 22:18:17 +08:00
    @gotounix 放外面不行 NameError: name 'Detect' is not defined
    maloneleo88
        14
    maloneleo88  
    OP
       2022-04-25 22:19:02 +08:00
    @westoy 哈哈 给出个招
    maloneleo88
        15
    maloneleo88  
    OP
       2022-04-25 22:20:37 +08:00
    @gotounix 反正是扔上面找不到类, 扔下面好不到函数。 扔里面就报错
    mimzy
        16
    mimzy  
       2022-04-25 22:21:08 +08:00
    @classmethod
    def choice_id(cls):
    ....data = cls.objects.all()
    ....return len(data) + 1

    确实太暴力了。
    mimzy
        17
    mimzy  
       2022-04-25 22:23:18 +08:00
    @classmethod
    def choice_id(cls):
    ....count = cls.objects.count()
    ....return count + 1
    maloneleo88
        18
    maloneleo88  
    OP
       2022-04-25 22:30:45 +08:00
    @mimzy 大佬! 然后怎么调用? 这个没学到过
    mimzy
        19
    mimzy  
       2022-04-25 22:31:26 +08:00
    @mimzy #16 #17 这两种写法应该有幻读( Phantom Read )的问题
    westoy
        21
    westoy  
       2022-04-25 22:49:10 +08:00
    @maloneleo88

    metaclass 要在类定义里搞到类名要用黑魔法的

    比如你这个
    from werkzeug.utils import import_string

    ......

    choice_id = models.IntegerField(
    default = (lambda m=f"{__module__}.{__qualname__}": lambda:import_string(m).objects.aggregate(current=models.Count("pk")+1)['current'])()
    )

    不过不建议使用, 代码还是写的清楚一点比较好
    maloneleo88
        22
    maloneleo88  
    OP
       2022-04-25 22:59:59 +08:00 via iPhone
    @westoy
    @mimzy
    搞不定啊,不会弄。我也感觉这样不好,太复杂了。你们写的我都看不懂,哎 太难了。。。

    我莫不如挂个 js 看看上一条编号是几然后 val+1
    westoy
        23
    westoy  
       2022-04-25 23:02:26 +08:00
    @maloneleo88

    直接 default=lambda : Detect.objects.aggregate(current=models.Count("pk")+1)['current'] 啊
    xhzhang
        24
    xhzhang  
       2022-04-26 09:04:44 +08:00
    这是要实现 id 递增吗?为什么不用 sequence 之类的,要用这么暴力的方法呢
    xhzhang
        25
    xhzhang  
       2022-04-26 09:10:33 +08:00
    看你这个是要支持自填,非自填情况下要取当前总条数+1 。
    这个 id 如果是有唯一要求,自填的 id 还要先检查是否已有 ,并抛出错误。
    如果没有唯一性要求,那就没有必要加个 choice_id 这种方法,用 uuid ,rangdom 之类的生成随机序列作为编号,另外加一个字段建立 sequence 用于区分不同的数据。
    主要是不懂为何会有你现在这种需求,没有业务目标直接写代码,感觉怪怪的
    ray5173
        26
    ray5173  
       2022-04-26 09:58:44 +08:00
    写外面没问题的,不知道你用的那个版本的 django ,我用 1.10 ,代码里有一个类似的需求(默认取当前最大值+1),就是通过 chioce_id 函数放外面实现的。
    dicc
        27
    dicc  
       2022-04-26 10:19:34 +08:00
    楼主听我的,django 默认有个 id 就是自增的,所以如果不是特别需要,你这个 id 字段没有必要创建。
    第二, 你这个 id 的算法有严重的问题!!!!!!

    假设,你有数据库有 30 条数据,那么第 31 条 id 就是 31.
    此时进行了一次删除,数据库就又剩 30 ,那么第 32 条的 id 又是 31 了
    wnh3yang
        28
    wnh3yang  
       2022-04-26 11:19:17 +08:00
    bug 就是這麽來的
    nonduality
        29
    nonduality  
       2022-04-26 11:54:16 +08:00
    如果没有特殊要求,最好用数据库的自增 id (整数或 uuid 都可以),只需把字段增加一属性 primary=True 。没事别自己 hack 。
    wingor2015
        30
    wingor2015  
       2022-04-26 17:54:35 +08:00
    dicc 的意见非常重要,自己定义 id 没有这么简单,但是如果你一定要这么做呢,也能实现

    chioce_id 这个方法应该放到 class Detect 定义的外面,才能正确找到,但是放到外面就无法获取到 objects.count (不要用 all 再 len )
    要实现的这个逻辑的话,你可以放到 save 方法里
    detect_id = models.BigIntegerField(verbose_name='编号',default=None)

    def save(self, *args, **kwargs):
    if not self. detect_id:
    self. detect_id = self.__class__.objects.count() + 1
    super(Detect, self).save(*args, **kwargs)
    maloneleo88
        31
    maloneleo88  
    OP
       2022-04-27 08:24:21 +08:00 via iPhone
    感谢大家回复,其实我后来想了下也是没必要的。就是个编号问题,甚至不需要写库里,直接 html 循环出编号就可以了 😐😐😐
    954
        32
    954  
       2022-04-28 09:32:30 +08:00
    @westoy
    这个能过 migrate 吗...
    官方原文:lambda 不能用于 default 等字段选项,因为它们不能被 迁移序列化。
    954
        33
    954  
       2022-04-28 09:46:05 +08:00
    @mimzy
    这个直接 Unresolved reference 了吧...
    954
        34
    954  
       2022-04-28 09:57:42 +08:00
    @wingor2015
    用 count 做也不合理,最好用最后一个的 id + 1 来做吧...
    除非顺手再把 delete 重写了,不然删除后会导致重复 choice_id 。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5319 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 36ms · UTC 08:07 · PVG 16:07 · LAX 01:07 · JFK 04:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.