You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于关联模型字段生成Django模型的custom_id字段

Django模型生成自定义custom_id报错解决

问题背景

需要为CompanyUserPhysicalCard模型生成格式如「123456GOOGLE」的custom_id,由随机字符拼接公司名称组成。使用自定义默认函数company_card_code时触发错误:'ForeignKey' object has no attribute 'company_name'。

相关代码

models.py

class CompanyUserPhysicalCard(models.Model):
    card = models.ForeignKey(Cards, on_delete=models.CASCADE, related_name='company_physical_user_cards')
    company = models.ForeignKey(Company, on_delete=models.SET_NULL, null=True, verbose_name='компания')
    custom_id = models.CharField(max_length=7, unique=True, default=company_card_code, editable=False, null=True,
                                 blank=True)

自定义函数

def company_card_code(company):
    letters = '01234567890QLUBOK'
    result_str = ''.join(random.choice(letters) for i in range(9)) + str(company.company_name)

    return result_str

报错信息

'ForeignKey' object has no attribute 'company_name'

解决方案

错误原因

Django字段的default参数在模型类加载阶段就会执行,此时传入函数的是ForeignKey字段对象,而非实际创建的Company实例,自然无法访问company_name属性。

修正方案:重写模型save方法

放弃default参数,通过重写save方法在实例保存时生成custom_id,此时已能获取关联的Company实例:

import random

class CompanyUserPhysicalCard(models.Model):
    card = models.ForeignKey(Cards, on_delete=models.CASCADE, related_name='company_physical_user_cards')
    company = models.ForeignKey(Company, on_delete=models.SET_NULL, null=True, verbose_name='компания')
    # 调整max_length以容纳随机字符+公司名称,示例设为20可根据实际需求修改
    custom_id = models.CharField(max_length=20, unique=True, editable=False, null=True, blank=True)

    def save(self, *args, **kwargs):
        # 仅当custom_id为空且关联了company时生成
        if not self.custom_id and self.company:
            letters = '0123456789QLUBOK'  # 移除重复的0,避免字符分布不均
            # 生成6位随机字符(匹配示例中的123456格式)
            random_segment = ''.join(random.choice(letters) for _ in range(6))
            # 拼接大写的公司名称
            self.custom_id = f"{random_segment}{self.company.company_name.upper()}"
            
            # 处理唯一约束:若生成的custom_id已存在,重新生成
            while CompanyUserPhysicalCard.objects.filter(custom_id=self.custom_id).exists():
                random_segment = ''.join(random.choice(letters) for _ in range(6))
                self.custom_id = f"{random_segment}{self.company.company_name.upper()}"
        
        # 调用父类save方法完成保存
        super().save(*args, **kwargs)

关键说明

  1. 长度调整:原max_length=7无法容纳随机字符+公司名称,需根据实际公司名称长度调整为合适值。
  2. 去重处理:随机字符串存在重复概率,通过循环检查确保custom_id唯一性。
  3. 判空逻辑:仅在custom_id为空时生成,避免更新实例时覆盖已有值。
  4. 格式统一:将公司名称转为大写,匹配示例中的格式要求。

内容的提问来源于stack exchange,提问作者Zesshi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 09:35:25