2016-07-25 24 views
1

Ich habe ein wiederkehrendes Problem, das ich nicht angemessen lösen kann. Meine Website ähnelt einer Jobseite, auf der Personen Jobs (und Details darin) veröffentlichen können, und andere Personen können sie mit einem Lesezeichen versehen. Jeder Job kann offensichtlich von mehr als einem Betrachter mit einem Lesezeichen versehen werden.Der beste Weg, um Daten aus mehreren Tabellen zu zeigen

Also hier ist die model.py:

class Job(models.Model): 
    user = models.ForeignKey(User, on_delete=models.CASCADE) 
    title = models.CharField(max_length=150) 
    description = models.CharField(max_length=5000) 


class Bookmark(models.Model): 
    user = models.ForeignKey(User, on_delete=models.CASCADE) 
    job = models.ForeignKey(Job, on_delete=models.CASCADE) 

Meine Absicht ist es, alle Arbeitsplätze in der Homepage angezeigt werden, die mehrere Jobs von mehreren Benutzern bedeutet. Andere Benutzer können auf ein kleines Lesezeichensymbol klicken, um ein Lesezeichen zu setzen oder die Markierung aufzuheben. Wie so:

Hier ist der view.py:

def index(request): 
    context = {} 
    populateContext(request, context) 

    jobs = Job.objects.all().order_by('-id') 

    context = {'jobs': jobs} 


    return render(request, 'templates/index.html', context) 

Ganz einfach denke ich, das ist meine Absicht. So sieht die Vorlage aus:

{% for job in jobs %} 
    <div> 
     {{ job.title }}<br> 
     {{ job.description }}<br> 
     by {{ job.user.username }} 
    </div> 
{% endfor %} 

Meine Frage ist, wie kann ich den Lesezeichenstatus für jeden Benutzer anzeigen? Hier ist meine aktuelle Lösung:

{% for job in jobs %} 
    <div> 
     {{ job.title }}<br> 
     {{ job.description }}<br> 
     by {{ job.user.username }}<br> 

     {% for watch in job.bookmark_set.all %} 
      {% if watch.user_id = request.user.id %} 
       You have bookmarked this! <a>Unbookmark!</a> 
      {% endif %} 
     {% endfor %} 

     <a>Bookmark</a> 
    </div> 
{% endfor %} 

Die "Unbuchzeichen!" Der Link wird übrigens über den Link "Lesezeichen" positioniert. Die obige Lösung funktioniert auf diese Weise, da die Textmappentabelle für einen bestimmten Job, jedoch unter mehreren Benutzern, keine oder mehrere Lesezeichen enthält. Ich würde dies in der view.py behandeln, indem ich nur Jobs filtern würde, die der angemeldete Benutzer erstellt hat. Aber ich kann nicht nach welchem ​​Job filtern, weil die index.html alle anzeigt. So zum Beispiel könnte ich spucke this out ...:

bookmarked = Bookmark.objects.all().filter(user_id=request.user.id) 

... und das würde alle Lesezeichen auf verschiedenen Arbeitsplätzen Liste heraus, dass der angemeldete Benutzer gemacht hatte. Ich muss das immer noch in der Vorlage filtern, so dass jedes Projekt mit jedem Lesezeichen übereinstimmt, und ich verstehe, dass dies nicht möglich ist.

Wie auch immer, ich denke, das ist ziemlich ineffizient. Also habe ich mich gefragt, ob es einen einfacheren Weg gibt, damit umzugehen? Vorzugsweise so, dass es so funktioniert:

{% for job in jobs %} 
    <div> 
     {{ job.title }}<br> 
     {{ job.description }}<br> 
     by {{ job.user.username }}<br> 

     {% if job.id = bookmark.job.id %} 
      You have bookmarked this! <a>Unbookmark!</a> 
     {% else %} 
      <a>Bookmark</a> 
     {% endif %} 
    </div> 
{% endfor %} 

Vielen Dank!

Antwort

3

Sie können conditional expressions verwenden, um Ihre jobs mit diesen Informationen zu kommentieren. In der Ansicht:

from django.db.models import Case, IntegerField, Sum, When 

jobs = Job.objects.annotate(
      is_bookmarked=Sum(Case(
       When(bookmark__user=request.user, then=1), 
       default=0, output_field=IntegerField() 
      ))).order_by('-id') 

Jeder job hat jetzt eine is_bookmarked Eigenschaft, die entweder 1 ist (der Benutzer hat den Job vorgemerkt) oder 0. In der Vorlage:

{% for job in jobs %} 
    <div> 
     {% if job.is_bookmarked %} 
      You have bookmarked this! <a>Unbookmark!</a> 
     {% else %} 
      <a>Bookmark</a> 
     {% endif %} 
    </div> 
{% endfor %} 

Nur der Vollständigkeit halber, der andere Ansatz, den Sie im Sinn hatte, würde auch (wenn auch weniger effizient als die oben). In der Ansicht:

jobs = Job.objects.all().order_by('-id') 
# Get a list of all Job IDs bookmarked by this user 
user_bookmarks = Bookmark.objects.filter(user_id=request.user.id)\ 
           .values_list('job__id', flat=True) 

In der Vorlage:

{% for job in jobs %} 
    <div> 
     {% if job.id in user_bookmarks %} 
      You have bookmarked this! <a>Unbookmark!</a> 
     {% else %} 
      <a>Bookmark</a> 
     {% endif %} 
    </div> 
{% endfor %} 

Beide Ansätze sind dabei so ziemlich die gleiche Logik - der Unterschied ist, dass die erste dieser auf Datenbankebene tut in der Regel effizienter ist, .

+0

Elegante Lösung! – gglasses

+0

Vielen Dank für die detaillierte Lösung und Erklärung! Der zweite Ansatz funktioniert perfekt. Die erste jedoch nicht. Wenn der Job mit einem Lesezeichen versehen wurde, wird der Job zweimal angezeigt (einmal als nicht mit einem Lesezeichen versehen und einmal als Lesezeichen). Gibt es auch einen Geschwindigkeitsunterschied zwischen beiden Ansätzen? – Bob

+0

Hmm lass mich versuchen, den ersten Ansatz zu beheben, so dass es funktioniert ... es ist effizienter, da es nur auf DB-Abfrage und keine Listenfilterung erfordert. – solarissmoke

Verwandte Themen