关于django admin自定义列后传值会按照自定义列的方法名传值,导致修改数据库字段无效的解决方案

一、问题描述(嫌啰嗦的可以直接滚动到最下方):

 首先放出模型:

class User(MenusMixin, AbstractBaseUser, PermissionsMixin, BaseModel):
    USERNAME_FIELD = "username"
    username = models.CharField("用户名", max_length=32, unique=True)
    password = models.CharField(
        "密码", null=True, blank=False, default=None, max_length=128
    )
    name = models.CharField("姓名", max_length=32, null=True, blank=True)
    mobile = models.CharField("手机号", max_length=13, default=None, null=True, blank=True)
    groups = models.ManyToManyField(
        Group, verbose_name=_("组"), blank=True, related_name="user_set"
    )
    status = models.BooleanField("状态", default=True)

然后我在django admin页面list_display中使用了一个自定义状态列添加了一些自定义逻辑。代码如下:

@admin.register(User)
class UserAdmin(admin.ModelAdmin):
    """账号管理"""

    # form = UserForm
    list_display = [
        "username",
        "mobile",
        "create_time",
        "status_display",
    ]
    def status_display(self, obj):
        return obj.status if not obj.is_superuser else ""  # 对于超级管理员返回空

    status_display.short_description = "状态"

页面显示效果:

但是我发现使用了自定义列后,在djangoadmin列表页面回显的状态列(这里他会自动生成一个开关),点击开启或关闭,发送的请求是status_display 这个字段,然后呢这个字段在数据库中又没有,所以虽然会返回修改成功,但是实际上并不会修改状态成功,这是我请求的数据:
那么好解决方案来了:

二、解决方案:

实现的逻辑介绍一下:当点击开关状态时会自动调用django的save方法,我们需要在这里重写model模型中的save方法(写在你的模型中)代码如下:
 

    def save(self, mini_login=False, *args, **kwargs):
        # 根据list_display传值做相对应的处理,判断如果传的字段是自定义列status_display的则使用此字段
        if hasattr(self, 'status_display') and getattr(self, 'status_display', None):
            self.status = getattr(self, 'status_display')
        elif hasattr(self, 'status') and getattr(self, 'status', None):
            # 如果 status_display 为空但是 status 不为空,将 status 赋值给自身的 status 字段
            self.status = getattr(self, 'status')
        super().save(*args, **kwargs)

上面的代码是我需要考虑到在新增账号页面时,是不会有status_display 这个字段传过去的,所以添加了其他逻辑,如果你不需要其他逻辑,那么只需要这样写:

def save(self, *args, **kwargs):
        if self.status_display:
            self.status = self.status_display
        super(YourModel, self).save(*args, **kwargs)

好了,本次分享结束。如果有其他django admin + simplepro 开发过程中遇到的问题,欢迎询问!
我会尽我所能回答。
2024/5/14,补充:如果是外键的外键也是可以进行修改的,例如有一张表通过user字段关联此user表,具体如下

class ProviderExtra(models.Model):
    user = models.ForeignKey(
        "user.User",
        db_constraint=False,
        null=True,
        blank=True,
        on_delete=models.CASCADE,
        verbose_name="服务商",
        limit_choices_to={"mini_role__lt": 100},
    )
    area = models.CharField("管理区域", max_length=200, null=True, blank=True)
    province = models.ForeignKey(
        "region.Province",
        null=False,
        blank=False,
        on_delete=models.CASCADE,
        verbose_name="省份",
    )
    city = models.ForeignKey(
        "region.City",
        null=False,
        blank=False,
        on_delete=models.CASCADE,
        verbose_name="市/县",
    )
    county = models.ForeignKey(
        "region.County",
        null=False,
        blank=False,
        on_delete=models.CASCADE,
        verbose_name="区",
    )
    town = models.ForeignKey(
        "region.Town",
        null=True,
        blank=True,
        on_delete=models.CASCADE,
        verbose_name="街道/社区",
    )

然后自定义save方法,这里我使用了django的事务处理,确保两张表数据一致,要么都成功要么都失败,避免出现数据不一致:

from django.db import transaction

其他代码....模型代码....

def save(self, *args, **kwargs):
        if self.user:
            # 判断传入的字段名
            status_field = 'status_display' if hasattr(self, 'status_display') else 'status'
            status_value = getattr(self, status_field, None)
            if status_value:
                # 使用事务确保数据的一致性
                with transaction.atomic():
                    self.user.status = status_value
                    self.user.save()  # 保存关联的用户实例
        super().save(*args, **kwargs)


 

  • 15
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值