一、问题描述(嫌啰嗦的可以直接滚动到最下方):
首先放出模型:
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)