新手分享边爬文边写的 Django 用 admin 开发的简易进销存系统-2

1.基本设定(basic)模块

1.1.models.py 设定

1.1.1.币别

这个是唯一一个主键值不是1,2,…的模型,主是要用来测试用这样的做法是否会有不同,测试了之后决定还是用默认的方式遇到的问题会比较少。这个模型是用来提供商品原料所使用的报价币别选择。

class Currency(models.Model):
    id = models.CharField(max_length=3, primary_key=True, verbose_name=u'币别代号')
    title = models.CharField(max_length=8, blank=False, verbose_name=u'币别')
    rate = models.DecimalField(max_digits=16, decimal_places=4, blank=False, verbose_name=u'币别')

    def __str__(self):
        return self.id

    class Meta:
        verbose_name = '币别'
        verbose_name_plural = verbose_name

1.1.2.账期

提供客户供应商的帐期选择。

class Period(models.Model):
    title = models.CharField(max_length=32, blank=False, verbose_name=u'帐期名称')
    period = models.PositiveIntegerField(blank=False, verbose_name=u'天数', help_text=u'天数为整数')

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = '帐期'
        verbose_name_plural = verbose_name

1.1.3.供应商

供应商在建立之后需要通过审核。

STATUS_CHOICES = (
    ('W', u'等待审核'),
    ('A', u'已审核'),
    ('S', u'停止使用'),
)


class Supplier(models.Model):
    title = models.CharField(max_length=128, unique=True, blank=False, verbose_name=u'名称')
    contacter = models.CharField(max_length=32, verbose_name=u'联络人', blank=True)
    period = models.ForeignKey(Period, verbose_name=u'帐期', on_delete=models.PROTECT)
    landline = models.CharField(max_length=16, verbose_name=u'联络市话', blank=True)
    mobile = models.CharField(max_length=16, verbose_name=u'联络手机号', help_text='ex:12345678901',blank=True)
    wechat_account = models.CharField(max_length=16, verbose_name=u'联络微信账号', blank=True)
    email = models.EmailField(verbose_name=u'联络email', blank=True)
    address = models.CharField(max_length=256, verbose_name=u'联络地址', blank=True)
    description = models.CharField(max_length=256, verbose_name=u'描述', blank=True)
    status = models.CharField(max_length=1, choices=STATUS_CHOICES, default='W', verbose_name=u'状态')

    def get_absolute_url(self):
        return reverse('basic:supplier_detail', args=[self.id])

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = '供货商'
        verbose_name_plural = verbose_name
        permissions = (
            ('audit_supplier', '可审核供货商'),
            ('stop_supplier', '可终止供货商'),
        )

1.1.4.客户

客户在建立之后需要通过审核。

class Customer(models.Model):
    title = models.CharField(max_length=128, unique=True, blank=False, verbose_name=u'名称')
    contacter = models.CharField(max_length=32, verbose_name=u'联络人', blank=True)
    period = models.ForeignKey(Period, verbose_name=u'帐期', on_delete=models.PROTECT)
    landline = models.CharField(max_length=16, verbose_name=u'联络市话', blank=True)
    mobile = models.CharField(max_length=16, verbose_name=u'联络手机号', help_text='ex:12345678901', blank=True)
    wechat_account = models.CharField(max_length=16, verbose_name=u'联络微信账号', blank=True)
    email = models.EmailField(verbose_name=u'联络email', blank=True)
    address = models.CharField(max_length=256, verbose_name=u'联络地址', blank=True)
    description = models.CharField(max_length=256, verbose_name=u'描述', blank=True)
    status = models.CharField(max_length=1, choices=STATUS_CHOICES, default='W', verbose_name=u'状态')

    def get_absolute_url(self):
        return reverse('basic:customer_detail', kwargs={'pk': self.pk})

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = '客户'
        verbose_name_plural = verbose_name
        permissions = (
            ('audit_customer', '可审核客户'),
            ('stop_customer', '可终止客户'),
        )

1.1.5.原料种类

原料的一个标签,在建立之后需要通过审核。

class Category(models.Model):
    title = models.CharField(max_length=64, unique=True, blank=False, verbose_name=u'Part Number')
    description = models.CharField(max_length=256, verbose_name=u'描述', blank=True)
    status = models.CharField(max_length=1, choices=STATUS_CHOICES, default='W', verbose_name=u'状态')

    def get_absolute_url(self):
        return reverse('basic:category_detail', kwargs={'pk': self.pk})

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = '原料种类'
        verbose_name_plural = verbose_name
        permissions = (
            ('audit_category', '可审核原料种类'),
            ('stop_category', '可终止原料种类'),
        )

1.1.6.商品Part

商品的一个标签,在建立之后需要通过审核。

class Part(models.Model):
    title = models.CharField(max_length=64, unique=True, blank=False, verbose_name=u'Part Number')
    description = models.CharField(max_length=256, verbose_name=u'描述', blank=True)
    status = models.CharField(max_length=1, choices=STATUS_CHOICES, default='W', verbose_name=u'状态')

    def get_absolute_url(self):
        return reverse('basic:part_detail', kwargs={'pk': self.pk})

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = '商品Part'
        verbose_name_plural = verbose_name
        permissions = (
            ('audit_part', '可审核商品Part'),
            ('stop_part', '可终止商品Part'),
        )

1.1.7.商品Size

商品的一个标签,在建立之后需要通过审核。

class Size(models.Model):
    title = models.CharField(max_length=64, unique=True, blank=False, verbose_name=u'size')
    description = models.CharField(max_length=256, verbose_name=u'描述', blank=True)
    status = models.CharField(max_length=1, choices=STATUS_CHOICES, default='W', verbose_name=u'状态')

    def get_absolute_url(self):
        return reverse('basic:size_detail', kwargs={'pk': self.pk})

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = '商品Size'
        verbose_name_plural = verbose_name
        permissions = (
            ('audit_size', '可审核商品Size'),
            ('stop_size', '可终止商品Size'),
        )

1.1.8.原料

在建立之后需要通过审核。

class Material(models.Model):
    title = models.CharField(max_length=64, unique=True, blank=False, verbose_name=u'料号')
    image_sub = models.CharField(max_length=64, verbose_name=u'图文件在google共享文件夹的位置', blank=False, null=False)
    supplier = models.ForeignKey(Supplier, verbose_name=u'供货商', on_delete=models.PROTECT)
    category = models.ForeignKey(Category, verbose_name=u'种类', on_delete=models.PROTECT, limit_choices_to={'status': 'A'},)
    price = models.DecimalField(max_digits=16, decimal_places=4, verbose_name=u'未税价', null=False, blank=False)
    tax = models.DecimalField(max_digits=16, decimal_places=4, verbose_name=u'税金', null=False, blank=False)
    tax_price = models.DecimalField(max_digits=16, decimal_places=4, verbose_name=u'含税价', null=False, blank=False)
    currency = models.ForeignKey(Currency, verbose_name=u'报价币别', blank=False, null=False, on_delete=models.PROTECT)
    description = models.CharField(max_length=256, verbose_name=u'描述', blank=True)
    status = models.CharField(max_length=1, choices=STATUS_CHOICES, default='W', verbose_name=u'状态')
    stock = models.PositiveIntegerField(default=0, verbose_name=u'库存数量')

    def get_absolute_url(self):
        return reverse('basic:material_detail', kwargs={'pk': self.pk})

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = '原料'
        verbose_name_plural = verbose_name
        permissions = (
            ('audit_material', '可审核原料'),
            ('stop_material', '可终止原料'),
        )

1.1.9.商品

在建立之后需要通过审核。

class Product(models.Model):
    title = models.CharField(max_length=64, unique=True, blank=False, verbose_name='Model Name')
    part = models.ForeignKey(Part, verbose_name='Part Number', null=True, blank=True,
                             on_delete=models.PROTECT, limit_choices_to={'status': 'A'},)
    size = models.ForeignKey(Size, verbose_name='size', on_delete=models.PROTECT, limit_choices_to={'status': 'A'},)
    image_sub = models.CharField(max_length=64, verbose_name=u'图文件在google共享文件夹的位置', blank=False, null=False)
    price = models.DecimalField(max_digits=16, decimal_places=4, verbose_name=u'未税价', null=False, blank=False)
    tax = models.DecimalField(max_digits=16, decimal_places=4, verbose_name=u'税金', null=False, blank=False)
    tax_price = models.DecimalField(max_digits=16, decimal_places=4, verbose_name=u'含税价', null=False, blank=False)
    currency = models.ForeignKey(Currency, verbose_name=u'报价币别', blank=False, null=False, on_delete=models.PROTECT)
    description = models.CharField(max_length=256, verbose_name=u'描述', blank=True)
    combines = models.ManyToManyField(Material, through='Bom')
    status = models.CharField(max_length=1, choices=STATUS_CHOICES, default='W', verbose_name=u'状态')
    stock = models.PositiveIntegerField(default=0, verbose_name=u'库存数量')

    def get_absolute_url(self):
        return reverse('basic:product_detail', kwargs={'pk': self.pk})

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = u'商品'
        verbose_name_plural = verbose_name
        permissions = (
            ('audit_product', '可审核商品'),
            ('stop_product', '可终止商品'),
        )

1.1.10.BOM表

商品原料之间的关系,简单来说就是商品A需要原料1几个+原料2几个。

class Bom(models.Model):
    num = models.CharField(max_length=2, default='', verbose_name=u'单身项次')
    product = models.ForeignKey(Product, verbose_name='商品', on_delete=models.CASCADE)
    material = models.ForeignKey(Material, verbose_name='原料', on_delete=models.PROTECT, limit_choices_to={'status': 'A'},)
    quantity = models.PositiveIntegerField(default=1, verbose_name=u'组成数量')

    def save(self, *args, **kwargs):
        if self.num == '':
            #项次的格式是01,02...
            boms = Bom.objects.filter(product=self.product)
            num = "{0:02d}".format(boms.count() + 1)
            self.num = "{0:02d}".format(int(num))
        super().save(*args, **kwargs)

    def __str__(self):
        return '{}'.format(self.num)

    class Meta:
        verbose_name = 'BOM表'
        verbose_name_plural = verbose_name

1.2.admin.py 设定

1.2.1.其他model

由于admin的显示方式除了商品-BOM表之外没比较特别的,所以我其他的就带过,下面再来解释商品-BOM表的显示方式。

from django.contrib import admin
from django.contrib.auth import get_permission_codename
from django.db import models
from .models import Bom, Currency, Period, Supplier, Customer, Category, Part, Size, Material, Product

admin.site.site_header = '进销存系统'


@admin.register(Period)
class PeriodAdmin(admin.ModelAdmin):
    list_display = ['id', 'title', 'period']
    view_on_site = False

@admin.register(Currency)
class CurencyAdmin(admin.ModelAdmin):
    list_display = ['id', 'title', 'rate']
    view_on_site = False


class SupplierAdmin(admin.ModelAdmin):
    list_display = ['id', 'title', 'contacter', 'period', 'status']
    fields = ['title', 'contacter', 'period', 'landline', 'mobile', 'wechat_account', 'email', 'address',
              'description']
    actions = ['make_audited', 'make_stopped']
    view_on_site = False
    list_filter = ['status']
    list_per_page = 10
    list_max_show_all = 100

    def make_audited(self, request, queryset):
        rows = queryset.update(status='A')
        if rows > 0:
            self.message_user(request, u'已完成审核动作')
    make_audited.allowed_permissions = ('audit',)
    make_audited.short_description = u'通过审核'

    def has_audit_permission(self, request):
        opts = self.opts
        codename = get_permission_codename('audit', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))

    def make_stopped(self, request, queryset):
        rows = queryset.update(status='S')
        if rows > 0:
            self.message_user(request, u'已完成终止动作')
    make_stopped.allowed_permissions = ('stop',)
    make_stopped.short_description = u'终止使用'

    def has_stop_permission(self, request):
        opts = self.opts
        codename = get_permission_codename('stop', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))


admin.site.register(Supplier, SupplierAdmin)


class CustomerAdmin(admin.ModelAdmin):
    list_display = ['id', 'title', 'contacter', 'period', 'status']
    fields = ['title', 'contacter', 'period', 'landline', 'mobile', 'wechat_account', 'email', 'address',
              'description']
    actions = ['make_audited']
    view_on_site = False
    list_filter = ['status']
    list_per_page = 10
    list_max_show_all = 100

    def make_audited(self, request, queryset):
        rows = queryset.update(status='A')
        if rows > 0:
            self.message_user(request, u'已完成审核动作')
    make_audited.allowed_permissions = ('audit',)
    make_audited.short_description = u'通过审核'

    def has_audit_permission(self, request):
        opts = self.opts
        codename = get_permission_codename('audit', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))

    def make_stopped(self, request, queryset):
        rows = queryset.update(status='S')
        if rows > 0:
            self.message_user(request, u'已完成终止动作')
    make_stopped.allowed_permissions = ('stop',)
    make_stopped.short_description = u'终止使用'

    def has_stop_permission(self, request):
        opts = self.opts
        codename = get_permission_codename('stop', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))


admin.site.register(Customer, CustomerAdmin)


class CategoryAdmin(admin.ModelAdmin):
    list_display = ['id', 'title', 'description', 'status']
    fields = ['title', 'description']
    actions = ['make_audited', 'make_stopped']
    view_on_site = False
    list_filter = ['status']
    list_per_page = 10
    list_max_show_all = 100

    def make_audited(self, request, queryset):
        rows = queryset.update(status='A')
        if rows > 0:
            self.message_user(request, u'已完成审核动作')
    make_audited.allowed_permissions = ('audit',)
    make_audited.short_description = u'通过审核'

    def has_audit_permission(self, request):
        opts = self.opts
        codename = get_permission_codename('audit', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))

    def make_stopped(self, request, queryset):
        rows = queryset.update(status='S')
        if rows > 0:
            self.message_user(request, u'已完成终止动作')
    make_stopped.allowed_permissions = ('stop',)
    make_stopped.short_description = u'终止使用'

    def has_stop_permission(self, request):
        opts = self.opts
        codename = get_permission_codename('stop', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))


admin.site.register(Category, CategoryAdmin)


class PartAdmin(admin.ModelAdmin):
    list_display = ['id', 'title', 'description', 'status']
    fields = ['title', 'description']
    actions = ['make_audited', 'make_stopped']
    view_on_site = False
    list_filter = ['status']
    list_per_page = 10
    list_max_show_all = 100

    def make_audited(self, request, queryset):
        rows = queryset.update(status='A')
        if rows > 0:
            self.message_user(request, u'已完成审核动作')
    make_audited.allowed_permissions = ('audit',)
    make_audited.short_description = u'通过审核'

    def has_audit_permission(self, request):
        opts = self.opts
        codename = get_permission_codename('audit', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))

    def make_stopped(self, request, queryset):
        rows = queryset.update(status='S')
        if rows > 0:
            self.message_user(request, u'已完成终止动作')
    make_stopped.allowed_permissions = ('stop',)
    make_stopped.short_description = u'终止使用'

    def has_stop_permission(self, request):
        opts = self.opts
        codename = get_permission_codename('stop', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))


admin.site.register(Part, PartAdmin)


class SizeAdmin(admin.ModelAdmin):
    list_display = ['id', 'title', 'description', 'status']
    fields = ['title', 'description']
    actions = ['make_audited', 'make_stopped']
    view_on_site = False
    list_filter = ['status']
    list_per_page = 10
    list_max_show_all = 100

    def make_audited(self, request, queryset):
        rows = queryset.update(status='A')
        if rows > 0:
            self.message_user(request, u'已完成审核动作')
    make_audited.allowed_permissions = ('audit',)
    make_audited.short_description = u'通过审核'

    def has_audit_permission(self, request):
        opts = self.opts
        codename = get_permission_codename('audit', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))

    def make_stopped(self, request, queryset):
        rows = queryset.update(status='S')
        if rows > 0:
            self.message_user(request, u'已完成终止动作')
    make_stopped.allowed_permissions = ('stop',)
    make_stopped.short_description = u'终止使用'

    def has_stop_permission(self, request):
        opts = self.opts
        codename = get_permission_codename('stop', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))


admin.site.register(Size, SizeAdmin)


class MaterialAdmin(admin.ModelAdmin):
    list_display = ['id', 'title', 'image_sub', 'supplier', 'category', 'tax_price', 'currency', 'stock', 'status']
    fields = ['title', 'image_sub', 'supplier', 'category', 'price', 'tax', 'tax_price',
              'description', 'currency']
    actions = ['make_audited', 'make_stopped']
    view_on_site = False
    list_filter = ['status']
    list_per_page = 10
    list_max_show_all = 100

    def make_audited(self, request, queryset):
        rows = queryset.update(status='A')
        if rows > 0:
            self.message_user(request, u'已完成审核动作')
    make_audited.allowed_permissions = ('audit',)
    make_audited.short_description = u'通过审核'

    def has_audit_permission(self, request):
        opts = self.opts
        codename = get_permission_codename('audit', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))

    def make_stopped(self, request, queryset):
        rows = queryset.update(status='S')
        if rows > 0:
            self.message_user(request, u'已完成终止动作')
    make_stopped.allowed_permissions = ('stop',)
    make_stopped.short_description = u'终止使用'

    def has_stop_permission(self, request):
        opts = self.opts
        codename = get_permission_codename('stop', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))


admin.site.register(Material, MaterialAdmin)

1.2.2.商品model

由于我希望如下在编辑商品时也一起编辑BOM表,所以我用inline的方式将BOM表放入商品信息编辑中;并且我希望在商品通过审核之后,除了授权的使用者之外,不可以再编辑BOM表了;也就是说当使用者有权限新增商品(add_product)且也有权限新增BOM表(add_bom)时可以在新增商品画面中新增BOM表信息,没有权限修改BOM表(change_bom)的话在修改商品则不能新增与修改商品,我使用的是复写商品change_form.html(后面将再说明)的方式。
商品编辑画面
商品与BOM表的写法如下:

class BomInline(admin.TabularInline):
    model = Bom
    fields = ['material', 'quantity']
    raw_id_fields = ['material']
    extra = 0


class ProductAdmin(admin.ModelAdmin):
    list_display = ['id', 'title', 'part', 'size', 'image_sub', 'tax_price', 'currency', 'stock', 'status']
    fields = ['title', 'part', 'size', 'image_sub', 'price', 'tax', 'tax_price',
              'currency', 'description']
    actions = ['make_audited', 'make_stopped']
    inlines = [BomInline]
    view_on_site = False
    list_filter = ['status']
    list_per_page = 10
    list_max_show_all = 100

    def make_audited(self, request, queryset):
        rows = queryset.update(status='A')
        if rows > 0:
            self.message_user(request, u'已完成审核动作')
    make_audited.allowed_permissions = ('audit',)
    make_audited.short_description = u'通过审核'

    def has_audit_permission(self, request):
        opts = self.opts
        codename = get_permission_codename('audit', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))

    def make_stopped(self, request, queryset):
        rows = queryset.update(status='S')
        if rows > 0:
            self.message_user(request, u'已完成终止动作')
    make_stopped.allowed_permissions = ('stop',)
    make_stopped.short_description = u'终止使用'

    def has_stop_permission(self, request):
        opts = self.opts
        codename = get_permission_codename('stop', opts)
        return request.user.has_perm('%s.%s' % (opts.app_label, codename))


admin.site.register(Product, ProductAdmin)

1.3.templates 设定

change_form.html 放置的位置如下:
change_form.html位置
我复制的来源位置是 C:\django\CSDN\Lib\site-packages\django\contrib\admin\templates\admin,因只复写商品(product)的画面,所以视你实际路径取得该 html 档后放到自己建立的 basic\templates\admin\basic\product 目录下,然后在该档案中新增如下 jquery 语法:
在 change_form.html 档中新增 jquery 语法

{% if not perms.basic.change_bom %} #特别注意
<script>
(function($) {
    $(document).ready(function(){
        var href = location.href;
        href_list = href.split('/');
        <!-- 表示为change -->
        if (href_list[href_list.length - 2] == 'change'){
            $('tr.add-row').hide(); #特别注意
            $('div.submit-row').html('<a href="/admin/sale/order/" class="closelink">Close</a>'); #特别注意
        }
    });
})(django.jQuery);
</script>
{% endif %}

有了上方代码中**#特别注意**的三行,如果使用者没有修改BOM表权限(change_bom)的话,代码就直接不让使用者新增bom表[ ( ′ t r . a d d − r o w ′ ) . h i d e ( ) ; ] , 且 直 接 将 新 增 的 按 钮 改 成 关 闭 [ (&#x27;tr.add-row&#x27;).hide();],且直接将新增的按钮改成关闭[ (tr.addrow).hide();][(‘div.submit-row’).html(‘Close’);]

1.4.urls.py 设定

虽然basic模块没有用到 urls.py,但是我还是在这个档内新增了一个 app_name 的设定。

from django.urls import path
from django.contrib.auth.decorators import login_required
from . import views

app_name = 'basic'


urlpatterns = [
]
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值