Django模型方面报错

Django模型方面报错

AttributeError: Manager isn’t accessible via air_compressor_station(模型名) instances

原因:不能用实例直接访问关联的数据集

错误代码示范:

……
	@property
    def get_total_running_time(self):
        #当前空压站对应的所有运行时长求和
        self.total_running_time = self.objects\
        .air_compressor_station_switch_record_set\
        .aggregate(models.Sum("this_run_time"))
       return return self.total_running_time

django.db.utils.OperationalError:(1054,“Unknown column ‘machine_air_compressor_station_switch_record.stop_time’ in ‘field list’”)

解释:没找到对应的字段

原因:

  • 字段名拼写错误
  • 该字段是模型新增的字段,没有做数据迁移

Refused to display ‘http://127.0.0.1:8000/’ in a frame because it set ‘X-Frame-Option’

解释:页面有类似内嵌的情况,但是我请求的链接被服务器拒绝了

原因:X-Frame-Options设置出了问题

解决:settings.py文件中修改配置

# settings.py文件中代码
……

# 中间件变量中添加XFrameOptionsMiddleware
MIDDLEWARE = [
    ……
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ……
]
# 总体设置项目的X-Frame-Options
X_FRAME_OPTIONS = "SAMEORIGIN"

这个报错的解决我也是以前在网上搜到的,附当时解决我问题的文章链接:

https://www.cnblogs.com/lph970417/p/12896689.html

django.db.utils.DataError: (1366, “Incorrect string value: ‘\xE3\x80\x81\xE9\xA2\x84…’ for column xxxx.xxxx.xxx at row 1”)

解释:数据库表字符集不对

原因:django默认使用utf8格式数据库,如果创建数据库时没有指定字符集,只是使用数据库服务本身所默认的字符集将抛出此报错。这个错误虽然报的是某个表字符集不对,但通常是整数据库字符集不对然后一个一个报出数据库表字符集问题

解决:修改数据库字符集为utf8

django.db.utils.DataError: (1406, “Data too long for column ‘xxx’ at row x”)

解释:数据库表某个字符类型的长度太小

原因:数据库表的字符字段长度改小了,而这个表里已有的记录字段值又大于这个长度。例如一个表中有一个名为sex的字符字段,长度是10,有一条记录的sex字段值是"男的",现在我们把这个sex字段的长度改为1,那么就会报上述的错误。
同理,如果字段中添加了choices参数,而choices参数值中的元素长度大于字段长度也会报类似的错误:
xxx.xxx.xxx(某个字符类型字段名): (fields.E009) ‘max_length’ is too small to fit the longest value in ‘choices’ (x characters).

解决:删除新生成的migrations文件,然后调整字段长度或者修改字段值。再重新做数据迁移

django.db.utils.ProgrammingError: (1146, “Table ‘xxx.xxx’ doesn’t exist”)

解释:数据库表不存在

原因同字段不存在报错

此报错的特殊情况:项目首次发布创建数据表时一直报错表不存在
这是我最近几个月踩的最大的坑,说起来都是泪。起因是这样的,我在注册模型的时候添加了自定义表单,这样就可以在admin管理页中直接使用自定义的表单。本来也没啥大问题,但是老板觉得表单的输入框用起来太麻烦非要使用下拉列表框,那么我就得再写个函数从查询其他模型数据生成下拉框的选项值,然后一更新发布就凉凉了,一直报上面的错。原因说起来有些长,先看代码示例:

# models.py文件

# 定义不同的设备
class MachineA(models.Model):
    class Meta:
        verbose_name = "A设备"
        verbose_name_plural = "A设备"

    name = models.CharField("设备名称",max_length=90)

    def __str__(self):
        return self.name


class MachineB(models.Model):
    class Meta:
        verbose_name = "B设备"
        verbose_name_plural = "B设备"

    name = models.CharField("设备名称",max_length=90)

    def __str__(self):
        return self.name


# 定义设备任务
class MachineOrder(models.Model):
    class Meta:
        verbose_name = "设备工作任务"
        verbose_name_plural = "设备工作任务"

    machine_type = models.CharField("设备类型",max_length=1,choices=(("A","A设备"),("B","B设备")))
    machine_ID = models.IntegerField("设备ID")
    order_name = models.CharField("任务名称",max_length=90)
    start_time = models.DateTimeField("任务开始时间")

    # 属性化方法
    @property
    def get_machine(self):
        if self.machine_type == "A":
            this_machine = MachineA.objects.get(id=self.machine_ID)
        else:
            this_machine = MachineB.objects.get(id=self.machine_ID)
        return str(this_machine)
# 在models.py的同级目录下创建modelform.py文件,用于存放自定义表单
from .models import *
from django import forms

# 获取不同类型的所有设备
def get_all_machine_selector():
    selector = [(0,"------")]
    all_machine_a = MachineA.objects.all()
    selector += [(obj.id,str(obj)) for obj in all_macine_a]
    all_machine_b = MachineB.objects.all()
    selector += [(obj.id,str(obj)) for obj in all_macine_b]
    return tuple(selector)


# 自定义设备任务表单
class MaMachineOrderForm(forms.ModelForm):
    class Meta:
        model = MachineOrder
        fields = "__all__"

    machine_ID = forms.ChoiceField(
        label="设备",
        choices=get_all_machine_selector(),
        widget=forms.forms.widgets.Select()
    )
# admin.py文件
from .modelform import *

# 模型注册
@admin.register(MachineOrder)
class MachineOrderAdmin(admin.ModelAdmin):
    # 使用当前管理类中的方法作为列
    list_display = ["machine_type","get_machine_func","order_name","start_time"]
    form = MaMachineOrderForm

    # 自定义一个方法,新的列的值就是这个方法的返回值
    def get_machine_func(self,instance):
        """
        参数:
        instance        模型的实例对象
        """
        this_type = instance.machine_type
        this_machine_id = instance.machine_ID

        if this_type == "A":
            this_machine = MachineA.objects.get(id=this_machine_id)
        else:
            this_machine = MachineB.objects.get(id=this_machine_id)

        return str(this_machine)

    # 自定义列名
    get_machine_func.short_description = "设备"

我有不同类型的设备,这些设备都可以执行一些相同的任务,所以我又写了一个任务模型。任务模型的字段就包括设备类型、设备ID、具体任务等。为了方便前端使用,我把设备id地段输入框改成了下拉选项框方便选择。逻辑没毛病,但是在发布创建数据库的时候就会报MachinA、MachineB这两个表不存在的错误。

原因如下:

  1. 我们的项目在执行创建数据迁移文件命令(python manage.py makemigrations app名)时,python解释器会先将我们的项目代码构建起来
  2. 类似于C++的内存四大分区,python也会有事先为我们编写的全部代码本身、全局变量等分配内存,我们定义的函数、定义的类都会在这个时候被存放到指定的内存区域
  3. 从上述的代码中我们可以看到,我的MachineOrderAdmin类中添加了表单MachineOrderForm、MachineOrderForm表单中又重写了machine_ID字段。也就是说,MachineOrderForm表单是MachineOrderAdmin的类属性、machine_ID字段是MachineOrderForm表单的类属性
  4. 类属性不同于实例属性,它们不独属于任何一个实例,而是同一个类的所有实例共有,这样的属性也是会被分配到2所说的内存区,那么get_all_machine_selector函数自然就会在此时执行起来。而执行这个函数的时候,它所查询的MachineA和MachineB还在函数还不一定就被创建了,甚至就算被创建了但是还没又被解释器编译模型的代码。所以在这里就报了表不存在的错误

知道了原因,要改起来其实就简单了,由于django数据查询所返回的Qeryset是惰性的,所以我们只需要修改一下machine_ID字段中所使用的函数就可以了:

# modelform.py文件

# 获取不同类型的所有设备
def get_all_machine_selector():
    selector = [(0,"------")]
    # 获取所有的设备选项,表还不存在查不到就直接跳过
    try:
        all_machine_a = MachineA.objects.all()
        selector += [(obj.id,str(obj)) for obj in all_macine_a]
    except:
        pass

    try:
        all_machine_b = MachineB.objects.all()
        selector += [(obj.id,str(obj)) for obj in all_macine_b]
    except:
        pass

    return tuple(selector)


# 自定义设备任务表单
class MaMachineOrderForm(forms.ModelForm):
    class Meta:
        model = MachineOrder
        fields = "__all__"

    machine_ID = forms.ChoiceField(
        label="设备",
        # 此时获取到的就是下拉选项是没有项目首次运行时查到的数据,有可能不完整
        choices=get_all_machine_selector(),
        widget=forms.forms.widgets.Select()
    )

    """
    在表单使用时,重新获取一次下拉选项
    那么每次打开一个新的表单,下拉选项都将是最新查询到的
    """
    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
        self.fields["machine_ID"].choices = get_all_machine_selector()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值