0

Cela semble assez simple mais je ne suis pas en mesure de trouver une bonne solution de SO ou docs Django (en utilisant Django 1.10)modèle Django - vérifier si le champ a une valeur en elle ou vide si ManyToManyField

Je récupère une objet modèle dans le modèle et affichant uniquement les champs qui ont des valeurs (c.-à-d. non vides ou nuls) ou non vides si ManyToManyField.

Je ne suis pas en mesure de trouver un bon moyen de le faire en dehors de l'utilisation de nombreux if et else pour vérifier le type de champ, puis exécutez la condition correspondante if.

{% if model_name.field_name %} retourne toujours true pour ManytoManyField s (depuis son un ManyRelatedManager)

{% if model_name.field_name|length > 0 %} retourne toujours false pour ManytoManyField s

{% if model_name.field_name.all %} peut fonctionner correctement pour ManyToManyFields mais pas pour d'autres (comme CharField)

Existe-t-il une seule façon de vérifier si un champ a une certaine valeur utilisable à l'intérieur (que ce soit ManytoManyField ou un simple CharField)? Je peux utiliser if-else pour vérifier le type de champ en premier, puis exécuter la vérification correspondante, mais cela semble contre-intuitif car cela ressemble à un cas d'utilisation courant pour justifier une balise de gabarit.

+0

Si vous avez besoin d'une telle logique, il serait peut-être préférable de le mettre dans votre 'views.py'. Les objets associés d'un objet ManyToManyField ou d'un objet ForeignKeyField doivent être appelés avec une méthode du gestionnaire de liens: 'all', ou peut-être' filter'. – cezar

+0

@cezar - merci, j'ai déplacé la logique à views.py.Posté mon code final en tant que réponse. – Anupam

Répondre

0

C'est ce que je fini par faire:

@ conseils de Cezar avait un sens si je me suis déplacé la logique à views.py (après tout, la logique de se montrer une valeur ou non, tombera dans le what- Pour afficher le compartiment et donc aller à la vue au lieu de comment afficher dans le modèle)

De même, au lieu de renvoyer un objet modèle au modèle, renvoyer maintenant un dict avec uniquement les valeurs pertinentes. ManyToManyFields (si elles ne sont pas vides) apparaissent sous forme de listes dans le dict.

for field in school._meta.get_fields(): # where school is the model object 

    #checking if field type is m2m 
    if (field.get_internal_type() == 'ManyToManyField'): 
     if getattr(school,field.name).exists(): 
      school_display[field.name] = [k.name for k in getattr(school, field.name).all()] 

    #checking if field has choices (so we could send the display name) 
    elif field.choices: 
     func_name_to_display = 'get_' + field.name + '_display' 
     #note the '()' at the end, below. getattr(a,b) is equivalent to a.b so we need to add a '()' at the end since its a function 
     school_display[field.name] = getattr(school,func_name_to_display)() 

    #just returning the value (if not empty) in other cases 
    else: 
     field_value = getattr(school,field.name) 
     if (field_value and field_value!='None'): 
      school_display[field.name] = field_value 

return render(request, 'detail.html', {'school_display' : school_display}) 

Je suis content d'avoir fait cela parce que j'ai découvert, au cours du processus, appelle à deux autres méthodes sur l'objet de modèle qui appartiendrait idéalement views.py, et les déplacés.

Heureux d'apprendre si l'approche ci-dessus pourrait être améliorée.

2

Vous pouvez le rendre plus propre à l'aide get_fields: https://docs.djangoproject.com/en/1.11/ref/models/meta/#retrieving-all-field-instances-of-a-model

Donc, dans votre cas, il ressemblerait à quelque chose comme ça (ce code est pseudo):

{% for field in Model._meta.get_fields() %} 
    {% if field.get_internal_type() == "ManyToManyField" %} 
     ... # render m2m, here you could use gettatr 
    {% else %} 
     ... # render regular field, here you could use gettatr 
    {% endif %} 
{% endfor %} 

Mais je suis également d'accord avec le commentaire de @ Cezar que vous devriez déplacer quelque chose comme ceci dans

+0

Merci @Sardorbek - vouliez-vous dire utiliser la logique correspondante pour get_fields(), getattr(), get_internal_type() etc. dans le template en quelque sorte? J'ai posté mon code - maintenant déplacé la logique à views.py et intéressant le code final ressemble à votre pseudo code pour le modèle, donc upvoting – Anupam

+0

@Anupam oui, il pourrait être utilisé dans les modèles, mais je suggère fortement de le faire dans views.py, comme vous l'avez fait. –

0

Si vous utilisez un filtre de gabarit, il sera silencieux évident à quoi cela devrait ressembler:

from django import template 
register = template.Library() 

@register.filter 
def is_not_empty(field): 
    try: 
     return field.count() 
    except (AttributeError, TypeError): 
     return field