0

我创建了一系列自定义 ModelFields,它们只是受限制的 ForeignKeys。您会在下面找到 CompanyField。实例化时,您可以提供一个类型(例如,客户、供应商)。提供类型后,该字段可确保仅允许具有适当类型的值。

定义自定义字段的 crm 应用程序可以正常编译和运行。最终,我使用“从 crm 导入字段”将字段引用添加到不同的应用程序(事件)。现在我看到一大堆这样的错误:

events.incident:“组”与模型公司有关系,该模型尚未安装或抽象。

这是所有血腥的细节。请让我知道我是否可以提供更多信息,这可能会有所帮助。

## crm/fields.py

import models as crmmods

class CompanyField(models.ForeignKey):
    def __init__(self, *args, **kwargs):
        # This is a hack to get South working. In either case, we just need to
        # make sure the FK refers to Company.
        try:
            # kwargs['to'] == crmmods.company doesn't work for some reason I
            # still haven't figured out
            if str(kwargs['to']) != str(crmmods.Company):
                raise AttributeError("Only crm.models.Company is accepted " + \
                    "for keyword argument 'to'")
        except:
            kwargs['to'] = 'Company'

        # See if a CompanyType was provided and, if so, store it as self.type
        if len(args) > 0:
            company_type = args[0]
            # Type is expected to be a string or CompanyType
            if isinstance(company_type, str):
                company_type = company_type.upper()
                if hasattr(crmmods.CompanyType, company_type):
                    company_type = getattr(crmmods.CompanyType, company_type)
                else:
                    raise AttributeError(
                        "%s is not a valid CompanyType." % company_type)
            elif not isinstance(company_type, crmmods.CompanyType):
                raise AttributeError(
                    "Expected str or CompanyType for first argument.")

            self.type = company_type
        else:
            self.type = None

        super(CompanyField, self).__init__(**kwargs)

    def formfield(self, **kwargs):
        # Restrict the formfield so it only displays Companies with the correct
        # type.
        if self.type:
            kwargs['queryset'] = \
                crmmods.Company.objects.filter(companytype__role=self.type)
        return super(CompanyField, self).formfield(**kwargs)

    def validate(self, value, model_instance):
        super(CompanyField, self).validate(value, model_instance)

        # No type set, nothing to check.
        if not value or not self.type:
            return

        # Ensure that value is correct type.
        if not \
        value.companytype_set.filter(role=self.type).exists():
            raise ValidationError("Company does not have the " + \
                "required roles.")

## crm/models.py

import fields

class CompanyType(models.Model):
    name = models.CharField(max_length=25)

class Company(models.Model):
    type = models.ForeignKey(CompanyType)

class Person(models.Model):
    name = models.CharField(max_length=50)
    company = fields.CompanyField("Client")

## incidents/models.py

from crm import fields as crmfields

class Incident(models.Model):
    company = crmfields.CompanyField("Client")
4

2 回答 2

1

你有一个循环包依赖。fields进口models哪个进口fields哪个进口models哪个进口fields。. .

循环包依赖是一个坏主意(tm)。尽管它在某些情况下可能有效,但它不适用于您的情况,原因是涉及元类的复杂原因,我将不遗余力。

编辑

原因是 Django ORM 模块使用元类将其类变量(模型的字段)转换为对象上的属性描述符。这是由元类在类定义时完成的。加载模块时定义一个类。由于这个原因,它的属性也必须在类加载时定义。这与方法的代码不同,方法的代码在执行类的那一刻就解析了对名称的引用。

field现在,由于您在类定义中来回引用一个对象models,因此这将不起作用。

如果您将所有三个放在同一个包中,您的问题将得到解决。

于 2012-09-20T20:52:55.163 回答
0

经过大量的努力,它被修复了,只是通过改变

kwargs['to'] = 'Company'

kwargs['to'] = 'crm.Company'

似乎当在 crm 应用程序之外评估“to”参数时,它是在事件应用程序的上下文中评估它。也就是说,它正在寻找“incidents.Company”,正如错误消息所暗示的那样,它不存在。

于 2012-09-24T22:36:59.950 回答