Django: Assigning ForeignKey - Unable to get repr for class

匿名 (未验证) 提交于 2019-12-03 00:56:02

问题:

I ask this question here because, in my searches, this error has been generally related to queries rather than ForeignKey assignment.

The error I am getting occurs in a method of a model. Here is the code:

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()]) 

The thing is, the Deal I am passing to HistoricalDeal.create_historical_deal is legit. Here's a picture of the debugger in PyCharm.

For search engines, the message there is:

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

Any ideas?

Edit: Full code for Deal below:

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'                            ),) 

回答1:

The solution was pointed out by James Bennet's comment on the answer from Sandwich Heat:

In the HistoricalDeal model's __str__ method, I passed a date object to ''.join([...]) (which is not a string). Simply coercing that value into a string with str() eliminated the problem.



回答2:

I'm going to venture a guess that the __str__ method should be replaced with __unicode__. This may not entirely fix the problem, but based on the documentation from the Django tutorial, I see this:

from django.db import models  class Question(models.Model):     # ...     def __str__(self):              # __unicode__ on Python 2         return self.question_text  class Choice(models.Model):     # ...     def __str__(self):              # __unicode__ on Python 2         return self.choice_text 

However, you're using the str method for this model:

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


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!