2016-03-07 95 views
3

我已經遍尋搜索,但找不到一個好例子。將Django QuerySet與ManyToMany傳遞給自定義序列化程序

我有兩個模型,其中之一有一個ManyToManyField。我試圖通過ManyToManyField將需要信息的QuerySet傳遞到自定義序列化器並返回JSON響應。

model.py

class Company(models.Model): 
    """Company in database.""" 

    founded = models.DateField(null=True) 
    name = models.CharField(max_length=60) 
    series = models.CharField(max_length=10, null=True) 
    valuation = models.DecimalField(max_digits=20, decimal_places=5, null=True) 
    description = models.TextField(null=True) 

    def __unicode__(self): 
     """Return human-readable representation of company for debugging.""" 

     return '<{}>'.format(self.name) 


class Metric(models.Model): 
    """Metrics for companies.""" 

    name = models.CharField(max_length=30) 
    end_date = models.DateField() 
    start_date = models.DateField() 
    company = models.ManyToManyField(Company) 
    value = models.IntegerField() 

    def __unicode__(self): 
     """Return human-readable representation of metric for debugging.""" 

     return '<{}, {}>'.format(self.name, self.company) 

views.py

class ClientAPI: 

@classmethod 
def _serialize(cls, objects): 
    def create_company_map(): 
     return {c.id: c.name for c in Company.objects.all()} 

    # Replace company ids with company names 
    def map_company(obj, company_map): 
     if 'company' in obj: 
      obj['company'] = company_map[obj['company']] 
     return obj 

    company_map = create_company_map() 
    raw = serializers.serialize('python', objects) 
    res = [dict(map_company(obj['fields'], company_map)) for obj in raw] 
    return res 

@classmethod 
def get_metrics(cls, request): 
    all_metrics = Metric.objects.all().order_by('end_date') 
    serialized_metrics = ClientAPI._serialize(all_metrics) 

    return JsonResponse(serialized_metrics, safe=False, json_dumps_params=None) 

@classmethod 
def get_metrics_by_company(cls, request, company_name): 
    metrics_by_company = Metric.objects.filter(company__name=company_name).order_by('end_date') 
    serialized_metrics_by_company = ClientAPI._serialize(metrics_by_company) 

    return JsonResponse(serialized_metrics_by_company, safe=False, json_dumps_params=None) 

我不能改變串行,因爲我有一個依賴於它的其他方法。當我運行這個代碼時,我得到:

TypeError: unhashable type: 'list'

任何深入瞭解我如何解決這一問題,都非常感謝!以防萬一,這是追溯。

Traceback (most recent call last): 
    File "/Users/jackiehuynh/anaconda/lib/python2.7/site-packages/django/core/handlers/base.py", line 149, in get_response 
    response = self.process_exception_by_middleware(e, request) 
    File "/Users/jackiehuynh/anaconda/lib/python2.7/site-packages/django/core/handlers/base.py", line 147, in get_response 
    response = wrapped_callback(request, *callback_args, **callback_kwargs) 
    File "/Users/jackiehuynh/Lytmus/question_1/client/views.py", line 167, in get_metrics 
    serialized_metrics = ClientAPI._serialize(all_metrics) 
    File "/Users/jackiehuynh/Lytmus/question_1/client/views.py", line 65, in _serialize 
    res = [dict(map_company(obj['fields'], company_map)) for obj in raw] 
    File "/Users/jackiehuynh/Lytmus/question_1/client/views.py", line 60, in map_company 
    obj['company'] = company_map[obj['company']] 
TypeError: unhashable type: 'list' 

回答

0

由於company是M2M領域,似乎obj['company']在下面的語句將是一個列表:

obj['company'] = company_map[obj['company']] 

而且,你正試圖通過傳遞一個清單爲重點,從company_map字典得到一些價值這導致了這個錯誤。

您可以使用列表中理解從IDS得到公司名稱:

obj['company'] = [company_map.get(idx, None) for idx in obj['company']] 

您也可以按照this post的詳細解釋,如果你願意,你可以試試這個自己在外殼:

In [1]: x = {'a': 1} 

In [2]: x[[1, 2]] 
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-7-1032576b46f9> in <module>() 
----> 1 x[[1, 2]] 

TypeError: unhashable type: 'list' 
+0

我已經確定了這一部分,但我對如何解決它有點難以理解。有任何想法嗎?我唯一不能改變的就是序列化器,但view.py和model.py中的其他內容都是可以改變的。 – sabellachan

+0

請查看更新後的答案。 – AKS

0

沒關係,我可能會問一個不好的問題。結果我想要做的是實際使用一個ForeignKey,而不是ManyToManyField。無論如何感謝您的幫助!