You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django创建Command时自动生成CommandPositions报UnboundLocalError问题

问题

在Django项目中定义了如下模型:

from django.db import models
from django.contrib.auth.models import User
from django.templatetags.static import static
from simple_history.models import HistoricalRecords
from treebeard.mp_tree import MP_Node
from . import constants

from datetime import datetime


class Profile(models.Model):
    # Managed fields
    user     = models.OneToOneField(User, related_name="profile", on_delete=models.CASCADE)
    memberId = models.CharField(unique=True, max_length=15, null=False, blank=False, default=GenerateFA)
    avatar   = models.ImageField(upload_to="static/MCARS/img/members", null=True, blank=True)
    birthday = models.DateField(null=True, blank=True)
    gender   = models.CharField(max_length=10, choices=constants.GENDER_CHOICES, null=True, blank=True)
    invited  = models.BooleanField(default=False)
    registered = models.BooleanField(default=False)
    height   = models.PositiveSmallIntegerField(null=True, blank=True)
    phone    = models.CharField(max_length=32, null=True, blank=True)
    address  = models.CharField(max_length=255, null=True, blank=True)
    number   = models.CharField(max_length=32, null=True, blank=True)
    city     = models.CharField(max_length=50, null=True, blank=True)
    zip      = models.CharField(max_length=30, null=True, blank=True)

    @property
    def get_avatar(self):
        return self.avatar.url if self.avatar else static('static/MCARS/img/avatars/default.jpg')

    def save(self, **kwargs):
        if not self.pk:
            super(Profile, self).save(**kwargs)
            rank = Rank.objects.create(user=self, longrank='o1', shortrank='o1', branch='r')
            rank.save()
        else:
            super(Profile, self).save(**kwargs)

    def __str__(self):
        rank = Rank.objects.get(user=self.user.profile).get_longrank_display()
        return  rank + " " + self.user.first_name + " " + self.user.last_name + "(" + self.memberId + ")"


class Rank(models.Model):
    user = models.ForeignKey(Profile, related_name="Rank", on_delete=models.CASCADE)
    longrank = models.CharField(max_length=5, null=True, blank=True, choices=constants.long_rank)
    shortrank = models.CharField(max_length=5, null=True, blank=True, choices=constants.short_rank)
    branch = models.CharField(max_length=5, null=True, blank=True, choices=constants.branch)
    image = models.ImageField(upload_to="static/MCARS/img/ranks", null=True, blank=True)
    history = HistoricalRecords()

    def save(self, **kwargs):
        self.shortrank = self.longrank
        self.image = 'static/MCARS/img/ranks/' + self.branch[0] + '-' + self.longrank + '.png'
        super(Rank, self).save(**kwargs)

    def __str__(self):
        return self.get_longrank_display() + ' (' + self.get_shortrank_display() + ') ' + self.user.user.first_name + ' ' + self.user.user.last_name


class Command(MP_Node):
    CO = models.ForeignKey(User, related_name="user", on_delete=models.CASCADE)
    ship = models.ImageField(upload_to="static/MCARS/img/ships", null=True, blank=True)
    seal = models.ImageField(upload_to="static/MCARS/img/flag", null=True, blank=True)
    Type = models.CharField(max_length=10, choices=constants.CMD_TYPE)
    name = models.CharField(max_length=255, null=True, blank=True)
    address  = models.CharField(max_length=255, null=True, blank=True)
    number   = models.CharField(max_length=32, null=True, blank=True)
    city     = models.CharField(max_length=50, null=True, blank=True)
    zip      = models.CharField(max_length=30, null=True, blank=True)
    hull = models.CharField(max_length=255, null=True, blank=True)
    Commissioned = models.BooleanField(default=True)

    node_order_by = ['name']

    def save(self, **kwargs):
        if not self.pk:
            super(Command, self).save(**kwargs)
            CommandPositions = CommandPositions.objects.create(command=self, name="CO", responsibility='Commanding Officer')
            CommandPositions.save()
        else:
            super(Command, self).save(**kwargs)

    def isCO(self, user):
        return self.CO == user

    def __str__(self):
        rank = Rank.objects.get(user=self.CO.profile).get_longrank_display()
        return self.name + ' (' + self.hull + ') ' + rank + " " + self.CO.first_name + " " + self.CO.last_name + " Commanding"

class CommandPositions(models.Model):
    Command = models.ForeignKey(Command, related_name="Positions", on_delete=models.CASCADE)
    name = models.CharField(max_length=255, null=True, blank=True)
    responsibility = models.TextField(null=True, blank=True)

class Assignment(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    Position = models.ForeignKey(Command, on_delete=models.CASCADE)
    assigned_dt = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name_plural = "Assignments"

创建Profile记录时能自动生成对应的Rank记录,但创建Command记录时,自动生成CommandPositions记录抛出如下错误:

File "/Users/evancutler/PycharmProjects/MCARS/MCARS/models.py", line 98, in save
    CommandPositions = CommandPositions.objects.create(command=self, name="CO", responsibility='Commanding Officer')
                       ^^^^^^^^^^^^^^^^

Exception Type: UnboundLocalError at /admin/MCARS/command/add/
Exception Value: cannot access local variable 'CommandPositions' where it is not associated with a value

原因分析

问题出在Command模型的save方法里:你把局部变量名定义成了CommandPositions,和模型类名完全相同。Python解释器会优先把这个名字当作局部变量处理,当你执行CommandPositions.objects.create()时,局部变量CommandPositions还没有被赋值,就会触发UnboundLocalError。

而Profile模型的save方法里用的是rank作为变量名,和Rank模型类名不同,所以不会覆盖全局的模型类引用,因此可以正常调用Rank.objects.create()。

另外补充:objects.create()方法本身已经会自动保存新创建的对象,不需要再调用.save(),这部分是冗余代码。

解决方案

修改Command模型的save方法,把局部变量名改成和模型类不同的名字,同时去掉多余的.save()调用:

def save(self, **kwargs):
    if not self.pk:
        super(Command, self).save(**kwargs)
        # 变量名改为command_position,避免和模型类名冲突
        command_position = CommandPositions.objects.create(
            command=self, 
            name="CO", 
            responsibility='Commanding Officer'
        )
    else:
        super(Command, self).save(**kwargs)

或者更简洁的写法,直接调用create不赋值:

def save(self, **kwargs):
    if not self.pk:
        super(Command, self).save(**kwargs)
        CommandPositions.objects.create(
            command=self, 
            name="CO", 
            responsibility='Commanding Officer'
        )
    else:
        super(Command, self).save(**kwargs)

这样就能解决变量名冲突导致的错误,同时简化代码。

内容的提问来源于stack exchange,提问作者arcee123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 14:53:09