python - Django:分配外键 - 无法获得类的代表

标签 python django repr

我在这里问这个问题是因为,在我的搜索中,这个错误通常与查询有关,而不是外键分配。

我遇到的错误发生在模型的方法中。这是代码:

class Deal(models.Model):

    ...model_fields...

    def _update_existing_deal(self, deal_dict):
        #deal made from deal_dict here, psuedo code below
        deal = Deal(deal_dict)
        HistoricalDeal().create_historical_deal(deal)


        self.price = deal_dict.get('price', self.price)
        if self.comment != deal_dict.get['comment']:
            self.comment = deal_dict.get('comment', '')
        self.set_unit_price()
        logger.debug(
            'Existing deal, (pk: %d), updated.',
            self.pk
        )

class HistoricalDeal(models.Model):
    deal = models.ForeignKey(Deal)
    created_at = models.DateTimeField(auto_now_add=True)
    price = models.DecimalField(max_digits=8, decimal_places=2, blank=True,
                                default=0)
    unit_price = models.DecimalField(decimal_places=2, max_digits=6,
                                     null=True, blank=True)

    def create_historical_deal(self, deal):
        self.deal = deal
        self.price = deal.price
        self.unit_price = deal.unit_price
        self.save()
        logger.debug(
            'HistoricalDeal created for Deal with pk: %d.',
            deal.pk
        )

    def __str__(self):
        return ', '.join([self.deal.name, self.created_at.date()])

事实是,我传递给 HistoricalDeal.create_historical_dealDeal 是合法的。这是 PyCharm 中调试器的图片。 Debugger Message

对于搜索引擎,信息是:

Unable to get repr for <class 'deals.models.HistoricalDeal'>

有什么想法吗?

编辑:下面交易的完整代码:

class Deal(models.Model):
    LUMBER = 'lumber'
    WOODBLANK = 'woodblank'
    DOWEL = 'dowel'
    VENEER = 'veneer'
    PLYWOOD = 'plywood'

    TYPE_CHOICES = (
        (LUMBER, 'Lumber'),
        (WOODBLANK, 'Wood Blank'),
        (DOWEL, 'Dowel'),
        (VENEER, 'Veneer'),
        (PLYWOOD, 'Plywood'),
    )

    # define the correct method and unit for each material type
    # mainly used in `get_unit_price`
    MATERIAL_MAPPING = {
        LUMBER: {
            'method': lambda self: float(self.price) / (float(self.board_feet) or 1),
            'unit': 'BF',
        },
        WOODBLANK: {
            'method': lambda self: self.price,
            'unit': 'Purchase',
        },
        DOWEL: {
            'method': lambda self: float(self.price) / (float(self.linear_feet) or 1),
            'unit': 'LF',
        },
        VENEER: {
            'method': lambda self: float(self.price) / (float(self.square_feet) or 1),
            'unit': 'SF',
        },
        PLYWOOD: {
            'method': lambda self: float(self.price) / (float(self.square_feet) or 1),
            'unit': 'SF',
        }
    }

    name = models.CharField(max_length=200)
    slug = models.SlugField(max_length=100)
    url = models.CharField(max_length=200, blank=True)
    vendor = models.ForeignKey('Vendor')
    category = models.ForeignKey('Category')
    active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    price = models.DecimalField(max_digits=8, decimal_places=2, blank=True,
                                default=0)
    comment = models.TextField(blank=True)
    img = models.ImageField(blank=True)
    unique_lot = models.IntegerField(default=None, blank=True, null=True)

    material_type = models.CharField(max_length=9, choices=TYPE_CHOICES)

    # attributes specific to material types
    board_feet = models.DecimalField(decimal_places=2, max_digits=6,
                                     null=True, blank=True)
    thickness = models.CharField(max_length=15,
                                 null=True, blank=True)
    length = models.CharField(max_length=15,
                              null=True, blank=True)
    width = models.CharField(max_length=15,
                             null=True, blank=True)
    diameter = models.CharField(max_length=15,
                                null=True, blank=True)
    linear_feet = models.DecimalField(decimal_places=2, max_digits=6,
                                      null=True, blank=True)
    square_feet = models.DecimalField(decimal_places=2, max_digits=6,
                                      null=True, blank=True)
    adhesive_backing = models.NullBooleanField(default=False,
                                               null=True, blank=True)

    image = models.ForeignKey('Image', null=True, blank=True)

    unit_price = models.DecimalField(decimal_places=2, max_digits=6,
                                     null=True, blank=True)

    def set_unit_price(self):
        method = self.MATERIAL_MAPPING[self.material_type]['method']
        self.unit_price = method(self)
        self.save()

    @property
    def get_unit_price(self):
        method = self.MATERIAL_MAPPING[self.material_type]['method']
        unit = self.MATERIAL_MAPPING[self.material_type]['unit']
        return {
            'value': method(self),
            'units': unit
        }

    @classmethod
    def _find_matching_deal(cls, deal_dict):
        """ Check for an existing deal that matches `deal_dict` """
        # TODO: use get_or_create?
        match = cls.objects.filter(
            material_type=deal_dict.get('deal_type', None),
            board_feet=deal_dict.get('boardfeet', None),
            thickness=deal_dict.get('thickness', None),
            length=deal_dict.get('length', None),
            width=deal_dict.get('width', None),
            diameter=deal_dict.get('diameter', None),
            linear_feet=deal_dict.get('linear_feet', None),
            square_feet=deal_dict.get('square_feet', None),
            adhesive_backing=deal_dict.get('adhesive_backing', None),
            unique_lot=deal_dict.get('unique_lot', None),
            category=deal_dict['category'],
            url=deal_dict['url']
        )
        if not match:
            return None
        # Because of the unique constraint, there should only be one match
        assert len(match) == 1
        return match[0]

    @staticmethod
    def _guess_category(name, url):
        """ Find the category that best matches the deal name/url """
        name = name.lower()
        url = url.lower()
        # create a string of unique possible name variants
        search_string = '|'.join({
            name,
            name.replace(' ', ''),
            name.replace('_', ' '),
            name.replace('-', ' '),
            name.replace('_', ''),
            name.replace('-', ''),
            url.replace(' ', ''),
            url.replace('-', ' '),
            url.replace('_', ' '),
            url.replace('-', ''),
            url.replace('_', ''),
        })
        # TODO: cache categories, don't query each time
        all_categories = Category.objects.all()

        # get a list of categories that might match
        matching_categories = [
            category for category in all_categories
            if category.name.lower() in search_string
            ]
        logger.debug('Found these category matches for %s: %s', name,
                     matching_categories)
        if len(matching_categories) == 0:
            matching_categories = [
                category for category in all_categories
                if category.name.replace(' ', '').lower() in search_string
                ]
        if len(matching_categories) == 0:
            # add it to the Misc category
            return Category.objects.get_or_create(
                name="Miscellaneous",
                defaults={'slug': 'misc'}
            )[0]
        # return the first match
        return matching_categories[0]

    @staticmethod
    def _get_vendor(vendor_name):
        return Vendor.objects.get_or_create(
            name=vendor_name,
            defaults={'shipping': False}
        )[0]

    @staticmethod
    def _capitalize_name(name):
        return name.replace('-', ' ').replace('_', ' ').title()

    def _update_existing_deal(self, deal_dict):
        self.price = deal_dict.get('price', self.price)
        if self.comment != deal_dict.get['comment']:
            self.comment = deal_dict.get('comment', '')
        self.set_unit_price()
        logger.debug(
            'Existing deal, (pk: %d), updated.',
            self.pk
        )

    @classmethod
    def save_from_dict(cls, deal_dict):
        logger.debug('saving deal from dict: %s', deal_dict)
        deal_dict['category'] = cls._guess_category(deal_dict['name'], deal_dict['url'])
        deal_dict['name'] = cls._capitalize_name(deal_dict['name'])
        existing_deal = cls._find_matching_deal(deal_dict)
        if not existing_deal:
            logger.debug('This is a new deal, saving it')
            current_deal = cls.objects.create(
                name=deal_dict.get('name'),
                slug=deal_dict.get('slug', ''),
                url=deal_dict.get('url'),
                image=Image.from_url(deal_dict.get('image_url', None)),
                price=deal_dict.get('price'),
                comment=''.join(deal_dict.get('comment', [])),
                material_type=deal_dict.get('deal_type', None),
                board_feet=deal_dict.get('boardfeet', None),
                thickness=deal_dict.get('thickness', None),
                length=deal_dict.get('length', None),
                width=deal_dict.get('width', None),
                diameter=deal_dict.get('diameter', None),
                linear_feet=deal_dict.get('linear_feet', None),
                square_feet=deal_dict.get('square_feet', None),
                adhesive_backing=deal_dict.get('adhesive_backing', None),
                unique_lot=deal_dict.get('unique_lot', None),
                category=deal_dict['category'],
                vendor=cls._get_vendor(deal_dict['vendor_name']),
            )
            current_deal.set_unit_price()
        else:
            logger.debug(
                'Existing deal, updating it (pk: %d)',
                existing_deal.pk
            )
            HistoricalDeal().create_historical_deal(existing_deal)
            existing_deal._update_existing_deal(deal_dict)

    def __str__(self):
        return '<Deal: %d, %s>' % (self.pk, self.name)

    class Meta(object):
        unique_together = ((
                               'material_type',
                               'board_feet',
                               'thickness',
                               'length',
                               'width',
                               'diameter',
                               'linear_feet',
                               'square_feet',
                               'adhesive_backing',
                               'unique_lot',
                               'category',
                               'url'
                           ),)

最佳答案

James Bennet 对 Sandwich Heat 的回答的评论指出了解决方案:

HistoricalDeal 模型的 __str__ 方法中,我将一个日期对象传递给 ''.join([...])(这不是字符串)。只需使用 str() 将该值强制转换为字符串即可解决问题。

关于python - Django:分配外键 - 无法获得类的代表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31574990/

相关文章:

Python Facebook SDK : 'module' object has no attribute 'GraphAPI'

Python __repr__ 用于所有成员变量

python - 当参数默认为 None 时使用 __repr__,但可能是一个 str

Python:如何一次浏览文件中的多行?

python - Django/Nginx/Python 设置中的 MySQL 主机 - 恢复为 localhost

python - 无限递归,同时扩展管理员的应用程序 change_form 模板

python - Django:检查列表中是否存在行

django - 重命名 Django 模型字段

python - 为什么 `print hashlib.sha224(some_string).digest()` 与其 `repr()` 不同?

python - 如何在底部设置pygtk scrolledwindow vscrollbar