Python Django近期总结 - 2021-06-06

2021/06/06 20:16 下午 posted in  技术 comments

周五公司给买的键盘到货了,毕竟我自己不太会买这么贵的键盘……不过这个键盘的布局由于键数缩小到60,键位改变了不少。为了熟悉一下键盘,整理一下近期的一些经验,以飨读者。

使用Django REST Framework 提示Could not resolve URL for hyperlinked relationship using view name "user-detail"

经过查询,由于我在app里的urls.py里设定了namespace名称,因此在Django设置序列化的文件serializers.py中,需要在serializers.HyperlinkedIdentityField中指定view_name的名称,例如:

class UserSerializer(serializers.HyperlinkedModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name="myapp:user-detail")

    class Meta:
    model = User
    fields = ('url', 'username')

至此,该问题解决。

Django Models 处理Select形式字段经验总结

其实还是挺简单的,由于我的需求只需要在Django后台页面显示,所以只需要在Models那里处理一下就好了。由于我需要的字段比较多,因此在app目录下新建了一个文件cons.py专门存储字段。

以下是模型文件models.py

# -*- coding: UTF-8 -*-
from django.db import models
from .cons import SALCATEGORIES
from .cons import YEAR
from .cons import MONTH
from .cons import ORG

# Create your models here.
class Salary(models.Model):
    month = models.CharField('月',max_length=50, choices=MONTH)
    year = models.CharField('年',max_length=10, choices=YEAR)
    org = models.CharField('组织名',max_length=100, choices=ORG)
    create_timestamp = models.DateTimeField('创建时间',auto_now_add=True)
    change_timestamp = models.DateTimeField('修改时间',auto_now=True)
    def __str__(self):
        return dict(YEAR)[self.year]+dict(MONTH)[self.month]+'_'+dict(ORG)[self.org]

    class Meta:
        db_table = 'salary'

cons.py文件引入的内容如下:

# -*- coding: UTF-8 -*-
SALCATEGORIES = (
    ('shubas','应发 - 基本工资'),
    ('shupos','应发 - 岗位工资'),
    ('shupls','应发 - 绩效工资'),
    ('shuotr','应发 - 其他'),
    ('wihuem','扣缴 - 失业保险'),
    ('wihmed','扣缴 - 医疗保险'),
    ('wihold','扣缴 - 养老保险'),
    ('wihgjj','扣缴 - 公积金'),
    ('wihbgj','扣缴 - 补充住房公积金'),
    ('wihotr','扣缴 - 其他'),
    ('relsal','实发 - 实发工资'),
    ('relotr','实发 - 其他'),
)

YEAR = (
    ('2020','2020年'),
    ('2021','2021年'),
    ('2022','2022年'),
    ('2023','2023年'),
    ('2024','2024年'),
    ('2025','2025年'),
    ('2026','2026年'),
    ('2027','2027年'),
    ('2028','2028年'),
)

MONTH = (
    ('01','01月'),
    ('02','02月'),
    ('03','03月'),
    ('04','04月'),
    ('05','05月'),
    ('06','06月'),
    ('07','07月'),
    ('08','08月'),
    ('09','09月'),
    ('10','10月'),
    ('11','11月'),
    ('12','12月'),
)

ORG = (
    ('abc','中国abc公司'),
    ('cde','上海cde公司'),
)

这个键值对,存储的是前面的键,显示的是后面的值

上面的这个形式,对于该变量的类型也是一个挺有趣的东西。众所周知( )是个元组的初始化标志,正常来说元组是不能直接转换为字典的,但是上面这样的变量是可以正常转换的,请见如下测试代码和输出:

print(type(ORG))
for i in ORG:
    print(i[0]+"_"+i[1])
    print(type(i))

print(type(dict(ORG)))
print(dict(ORG))
for i in dict(ORG):
    print(i)
    print(type(i))

输出:

<class 'tuple'>
abc_中国abc公司
<class 'tuple'>
cde_上海cde公司
<class 'tuple'>
<class 'dict'>
{'abc': '中国abc公司', 'cde': '上海cde公司'}
abc
<class 'str'>
cde
<class 'str'>

回到实现上来。最终我需要的后台显示情况如下:

数据库表存储情况如下:

Pasted Screenshot 2021-06-06 20-54-18

这里我们介绍一下Django里模型Fieldchoices字段:

一个 sequence 本身由正好两个项目的迭代项组成(例如 [(A,B),(A,B)...] ),作为该字段的选择。如果给定了选择,它们会被 模型验证 强制执行,默认的表单部件将是一个带有这些选择的选择框,而不是标准的文本字段。

每个元组中的第一个元素是要在模型上设置的实际值,第二个元素是人可读的名称。例如:

YEAR_IN_SCHOOL_CHOICES = [
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate'),
]


> 一般来说,最好在模型类内部定义选择,并为每个值定义一个合适的名称的常量:

> ```python
> from django.db import models
> 
> class Student(models.Model):
    FRESHMAN = 'FR'
    SOPHOMORE = 'SO'
    JUNIOR = 'JR'
    SENIOR = 'SR'
    GRADUATE = 'GR'
    YEAR_IN_SCHOOL_CHOICES = [
        (FRESHMAN, 'Freshman'),
        (SOPHOMORE, 'Sophomore'),
        (JUNIOR, 'Junior'),
        (SENIOR, 'Senior'),
        (GRADUATE, 'Graduate'),
    ]
    year_in_school = models.CharField(
        max_length=2,
        choices=YEAR_IN_SCHOOL_CHOICES,
        default=FRESHMAN,
    )
> 
    def is_upperclass(self):
        return self.year_in_school in {self.JUNIOR, self.SENIOR}
> ```

> 虽然你可以在模型类之外定义一个选择列表,然后引用它,但在模型类内定义选择和每个选择的名称,可以将所有这些信息保留在使用它的类中,并帮助引用这些选择(例如,`Student.SOPHOMORE` 将在导入 `Student` 模型的任何地方工作)。

> 你还可以将你的可用选择收集到可用于组织目的的命名组中:

> ```
MEDIA_CHOICES = [
    ('Audio', (
            ('vinyl', 'Vinyl'),
            ('cd', 'CD'),
        )
    ),
    ('Video', (
            ('vhs', 'VHS Tape'),
            ('dvd', 'DVD'),
        )
    ),
    ('unknown', 'Unknown'),
]

每个元组中的第一个元素是应用于该组的名称。第二个元素是一个二元元组的迭代,每个二元元组包含一个值和一个可读的选项名称。分组后的选项可与未分组的选项结合在一个单一的列表中(如本例中的 'unknown' 选项)。

对于每一个设置了 choice 的模型字段,Django 会添加一个方法来检索字段当前值的可读名称。参见数据库 API 文档中的 get_FOO_display()

请注意,选择可以是任何序列对象——不一定是列表或元组。这让你可以动态地构造选择。但是如果你发现自己把 chips 魔改成动态的,你可能最好使用一个合适的的带有 ForeignKey 的数据库表。 chips 是用于静态数据的,如果有的话,不应该有太大的变化。

每当 choices 的顺序变动时将会创建新的迁移。

除非 blank=Falsedefault 一起设置在字段上,否则包含 "---------" 的标签将与选择框一起呈现。要覆盖这种行为,可以在 choices 中添加一个包含 None 的元组,例如 (None, 'Your String For Display') 。另外,你也可以在有意义的地方使用一个空字符串来代替 None ——比如在 CharField

最后,新设备镇楼压轴。这可是近几年手头设备最贵的一年了。

IMG_8731