# 店铺表
class MallShop(AbstractUser):
name = models.CharField(max_length=20, blank=True, null=True, verbose_name='店铺名')
openid = models.CharField(max_length=255, verbose_name='openid')
shop_icon = models.ImageField(upload_to='shop/icon/', blank=True, verbose_name='店铺头像')
infocode = models.CharField(max_length=20, unique=True, verbose_name='激活码')
province = models.CharField(max_length=30, blank=True, null=True, verbose_name='省份')
city = models.CharField(max_length=30, blank=True, null=True, verbose_name='城市')
quxian = models.CharField(max_length=30, blank=True, null=True, verbose_name='区县')
address = models.CharField(max_length=300, blank=True, null=True, verbose_name='地址')
wtchat = models.CharField(max_length=30, blank=True, null=True, verbose_name='微信')
addtime = models.DateTimeField(auto_now_add=True, verbose_name='激活时间')
shop_turnover = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name='总营业额')
total_expenditure = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name='总支出')
qrcode = models.CharField(max_length=255, blank=True, verbose_name='二维码', help_text='用户扫码即可成为店铺会员')
def show_photo(self):
text = """
""" % self.shop_icon.url if self.shop_icon else ''
return mark_safe(text)
show_photo.short_description = '店铺头像'
# 用户管理
class MallUser(models.Model):
shop = models.ForeignKey(to='MallShop', on_delete=models.CASCADE, editable=False, verbose_name='所属店铺')
level = models.ForeignKey(to='UserClass', on_delete=models.SET_NULL, blank=True, null=True, verbose_name='用户级别')
openid = models.CharField(max_length=255, verbose_name='openid')
phone = models.CharField(max_length=11, unique=True, verbose_name='手机号')
username = models.CharField(max_length=50, default='匿名用户', verbose_name='用户名')
icon = models.CharField(max_length=255, blank=True, verbose_name='头像')
gender = models.NullBooleanField(default=None, verbose_name='性别', choices=((None, '不详'), (True, '男'), (False, '女')))
province = models.CharField(max_length=30, blank=True, null=True, verbose_name='省份')
city = models.CharField(max_length=30, blank=True, null=True, verbose_name='城市')
quxian = models.CharField(max_length=30, blank=True, null=True, verbose_name='区县')
address = models.CharField(max_length=300, blank=True, null=True, verbose_name='地址')
money = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name='余额')
wechat = models.CharField(max_length=100, blank=True, verbose_name='微信')
birthday = models.DateTimeField(default=None, blank=True, null=True, verbose_name='生日')
age = models.CharField(blank=True, max_length=15, verbose_name='年龄')
addtime = models.DateTimeField(auto_now_add=True, verbose_name='注册时间')
consumption = models.IntegerField(default=0, verbose_name='消费指数', help_text='平均没人每月来的次数,大于5则高于平均指数,小于则低于平均指数')
satisfaction = models.IntegerField(default=0, verbose_name='满意度', help_text='根据用户对服务的评价,5为最高,0为最低')
def over_time_birthday(self):
if self.birthday:
month = now.month - self.birthday.month
day = now.day - self.birthday.day
if not month:
text = "会员还剩{}天生日
".format(day)
else:
text = "会员还剩{}月{}天生日
".format(month, day)
return mark_safe(text)
else:
return mark_safe("")
over_time_birthday.short_description = '会员生日'
class ShopUserCreate:
def save_models(self):
self.new_obj.shop = self.request.user
super().save_models()
class AccessLevel:
def get_model(self):
return self.model_set
def queryset(self):
"""改进权限级查看"""
qs = self.request.user
shopuser = MallShop.objects.get(username=qs)
if shopuser.is_superuser:
return self.model._default_manager.get_queryset()
else:
return self.get_model().objects.filter(shop=qs)
class MallUserAdmin(AccessLevel, AllowDelete, ShopUserCreate):
# 设置显示字段
list_display = ['show_photo', 'shop_username', 'level', 'phone', 'money', 'username', 'gender',
'over_time_birthday', 'province', 'city',
'quxian', 'address', 'wechat', 'age', 'addtime', 'consumption',
'satisfaction', 'ope_balance']
# 设置搜索字段
search_fields = ['id', 'phone', 'username']
# 设置过滤字段
list_filter = ['gender', 'province', 'city', 'quxian', 'birthday', 'age', 'consumption', 'satisfaction']
model_icon = 'fa fa-team'
# list中哪个字段带链接,点击可以进入编辑
list_display_links = ("phone",)
# 显示还原按钮,删除修改的信息可以还原
reversion_enable = True
# 列聚合,可用的值:"count","min","max","avg", "sum"
# aggregate_fields = {"id": "max"}
show_detail_fields = ['phone']
show_all_rel_details = True
# list页面直接编辑
list_editable = (
'province', 'city', 'quxian', 'wtchat', 'birthday', 'gender', 'username'
)
# 自动刷新
refresh_times = (3, 5, 10)
# 添加数据时候,一步一步提供数据
# wizard_form_list = [
# ("基础信息", ("username", "password", "openid", "shop_icon", "infocode")),
# ("其它信息", ("last_login", "is_superuser", "name", "province", "city", "quxian", "wtchat")),
# ]
# 排序
ordering = ['-consumption']
# 不显示字段
exclude = ['shop']
is_addbalance = True
# 自读字段
readonly_fields = ['satisfaction', 'consumption', 'addtime', 'money', 'icon', 'shop']
# 添加过滤(这里是过滤日期)
ate_hierarchy = ['addtime']
model_set = MallUser
# 从‘多选框’的形式改变为‘过滤器’的方式,水平排列过滤器,必须是一个 ManyToManyField类型,且不能用于 ForeignKey字段,默认地,管理工具使用`` 下拉框`` 来展现`` 外键`` 字段
# filter_horizontal = ('authors',)
def shop_username(self, obj):
return '%s' % obj.shop.name if obj.shop.name else obj.shop.username # ☆☆☆☆☆
shop_username.short_description = '店铺'
# 重写formfield_for_dbfield,设计add和edit表单
def formfield_for_dbfield(self, db_field, **kwargs):
if not self.request.user.is_superuser:
# 对case这个表项的下拉框选择进行过滤
if db_field.name == "level":
kwargs["queryset"] = UserClass.objects.filter(shop=self.request.user).order_by('id')
# if db_field.user_service == "user_service":
# kwargs["queryset"] = UserExpend.objects.filter(shop=self.request.user).order_by('id')
#
# if db_field.name == "user_service":
# kwargs["queryset"] = UserExpend.objects.filter(shop=self.request.user).order_by('id')
# 对assigned_recipient这个表项的下拉选择进行过滤
# 并且需要用到外键
# if db_field.name == "assigned_recipient":
# stu_ids = StudentDoctor.objects.filter(doctor=self.request.user).values('student_id')
# ids = []
# # 这里使用循环,为了下方再次查询时在list中使用in
# for id in stu_ids:
# ids.append(id['student_id'])
# # 根据主键在ids列表中查询得到Queryset。注意kwargs["queryset"]一定是queryset
# kwargs["queryset"] = User.objects.filter(pk__in=ids)
return db_field.formfield(**dict(**kwargs))
else:
attrs = self.get_field_attrs(db_field, **kwargs)
return db_field.formfield(**dict(attrs, **kwargs))
class AddBalance(BaseAdminPlugin):
"""给用户增加余额"""
# 默认不加载,只在需要加载的options中设置True来加载
is_addbalance = False
def init_request(self, *arg, **kwargs):
return self.is_addbalance
def get_media(self, media):
# 此处用来加入我们自己的js文件
media = media + self.vendor("xadmin.self.addbalance.js")
return media
xadmin.site.register_plugin(AddBalance, ListAdminView)
@filter_hook
def post_response(self):
"""
Determines the HttpResponse for the add_view stage.
"""
request = self.request
msg = _(
'The %(name)s "%(obj)s" was added successfully.') % {'name': force_text(self.opts.verbose_name),
'obj': "%s" % (self.model_admin_url('change', self.new_obj._get_pk_val()), force_text(self.new_obj))}
if "_continue" in request.POST:
self.message_user(
msg + ' ' + _("You may edit it again below."), 'success')
return self.model_admin_url('change', self.new_obj._get_pk_val())
if "_addanother" in request.POST:
self.message_user(msg + ' ' + (_("You may add another %s below.") % force_text(self.opts.verbose_name)), 'success')
return request.path
else:
# 我们发过了就把 is_msg 改成False,这样系统就不会在调用一次
if self.is_msg:
self.message_user(msg, 'success')
# Figure out where to redirect. If the user has change permission,
# redirect to the change-list page for this object. Otherwise,
# redirect to the admin index.
if "_redirect" in request.POST:
return request.POST["_redirect"]
elif self.has_view_permission():
return self.model_admin_url('changelist')
else:
return self.get_admin_url('index')
关于xadmin的过滤大家应该也知道,我上面也说了,重写formfield_for_dbfield方法就可以,然后需求来了,inlines里面的内容怎么过滤,我看了一下,光重写formfield_for_dbfield是不行的,然后我追踪源码,查到inlines调用了xadmin/views/edit.py 90行的formfield_for_dbfield方法,然后我就在这个方法里 加上了
if db_field.name == "filename":
kwargs["queryset"] = model.objects.filter()
然后在导入model,重启一下ok了,我这个提供三种思路,第一个重写源码,第二个改写调用方法,把方法写道adminx.py里,还有就是把整个类提出来重写,我挑了里面最简单,改动最少的。
写完了,关于xadmin也算是有一定了解了项目也已经开源了,有兴趣的可以拿下来看一下
https://github.com/Anning01/shopsystem