2016-03-07 3 views
3

J'ai cherché partout, mais je n'ai pas pu trouver un bon exemple.Django QuerySet avec ManyToMany étant passé au sérialiseur personnalisé

J'ai deux modèles, dont un a un ManyToManyField. J'essaie de passer un QuerySet qui a besoin d'informations à travers le ManyToManyField dans un sérialiseur personnalisé et renvoie une réponse 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) 

Je ne peux pas changer le sérialiseur, parce que j'ai d'autres méthodes qui en dépendent. Lorsque j'exécute ce code, j'obtiens:

TypeError: unhashable type: 'list'

Tout renseignement sur la façon de résoudre ce problème est grandement apprécié! Juste au cas, c'est le retraçage.

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' 

Répondre

0

Depuis company est un champ de m2m, il semble obj['company'] dans la déclaration suivante sera une liste:

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

et, vous essayez d'obtenir une valeur de company_map dict en passant une liste comme la clé ce qui conduit à cette erreur.

Vous pouvez utiliser la compréhension de la liste pour obtenir les noms de société des ids:

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

Vous pouvez également suivre this post pour des explications détaillées, et si vous voulez, vous pouvez essayer vous-même dans une coquille:

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

J'ai bien compris cette partie, mais je suis un peu perplexe sur la façon de le résoudre. Des idées? La seule chose que je ne peux pas changer est le sérialiseur, mais tout le reste dans views.py et model.py sont modifiables. – sabellachan

+0

Veuillez jeter un oeil à la réponse mise à jour. – AKS

0

Peu importe, j'ai peut-être posé une mauvaise question. Il s'avère que ce que je voulais faire était en fait utiliser un ForeignKey, pas ManyToManyField. Merci pour l'aide de toute façon!