0

I am trying to populate a navbar "dropdown-menu" with individual "dropdown-item"'s populated from data in the sqlite3 DB.

I have something similar working on other pages but I cant get it to work in my navbar.

I am creating a record label, and want the list of artists populated from entries in the DB. I have found one tutorial on doing something similar in php, but doesn't translate, and there doesn't seem to be anything either on youtube or here other than populating form data.

Any help is greatly appreciated, as I have been trying to get it working for about a week now. I know it should be simple, but im missing something.

the app is called "music"

models.py

class Artist(models.Model):
    artist_name = models.CharField(max_length=250, default='')
    artist_logo = models.FileField()
    artist_url = models.URLField(blank=True)

    def __str__(self):
        return self.artist_name

class Release(models.Model):
    artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
    release_title = models.CharField(max_length=500)
    release_cover = models.FileField()
    release_duration = models.IntegerField()

    def __str__(self):
        return self.release_title

class Track(models.Model):
    release = models.ForeignKey(Release, default='', on_delete=models.CASCADE)
    artist = models.ForeignKey(Artist, default='', on_delete=models.CASCADE)
    track_title = models.CharField(max_length=200)
    track_version = models.CharField(max_length=200)
    track_genre = models.CharField(max_length=100)
    track_duration = models.IntegerField()
    track_number = models.SmallIntegerField()

    class Meta:
        ordering = ["track_number"]

    def __str__(self):
        return self.track_title

views.py

from django.contrib.auth import authenticate, login
from django.views import generic
from django.views.generic import ListView, View
from .models import Artist, Track, Release
from .forms import UserForm

# class IndexView(ListView):
#     template_name = 'music/index.html'

class ReleaseView(generic.ListView):
    template_name = 'music/releaselist.html'
    context_object_name = 'all_releases'

    def get_queryset(self):
        return Release.objects.all()

class ArtistView(generic.ListView):
    model = Artist
    template_name = 'music/artistlist.html'
    context_object_name = 'all_artists'

    def get_queryset(self):
        return Artist.objects.all()

class DetailView(generic.DetailView):
    model = Release
    template_name = 'music/detail.html'

urls.py (Main)

from django.contrib import admin
from django.urls import path, include, re_path
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
# include urls from the music app
    path('music/', include('music.urls'))

urls.py ("music" aka the app urls)

from django.contrib import admin
from django.urls import path, include, re_path
from . import views

# defined the app name in case the same fields are used in other apps
app_name = 'music'

urlpatterns = [
    # no info past music return index EG /music/
    # path('', views.IndexView.as_view(), name='index'),
    # albums/releases
    re_path(r'^release/$', views.ReleaseView.as_view(), name='release'),
    # looking for music page with album id afterwards /music/1
    re_path(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name="detail"),
    re_path(r'^(?P<pk>[0-9]+)/$', views.ArtistView.as_view(), name="artist"),

base.html

      <li class="nav-item dropdown">
        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
          Artists
        </a>
        <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
            {% for artist in all_artists %}
                <li><a class="dropdown-item" href="#">{{ artist.artist_id }}</a></li>
            {% endfor %}
        </div>

      </li>

Update: Here is my releases.html which works using similar code, and at the bottom has a test which looks like the for loop is incorrect

{% extends 'music/base.html' %}
{% block title %}KOLD FUZEON: Releases{% endblock %}

{% block body %}

        {% if all_releases %}
            <ul>
                {% for release in all_releases %}
                    <div class="releaseitem">
                        <li><a href="{% url 'music:detail' release.id %}">{{ release.artist }} - {{ release.release_title }}</a></li>
                        <li><a href="{% url 'music:detail' release.id %}"</a><img src="{{ release.release_cover.url }}" style="width: 300px"></li>
                    </div>
                {% endfor %}
            </ul>
        {% else %}
            <h3>We currently dont have any releases yet.</h3>
        {% endif %}


{#basic test for the artist list to be printed to screen#}
            <ul>
                <li>test1</li>
                {% for artist in all_artists %}
                    <li>test2</li>
                {% endfor %}
            </ul>



{% endblock %}
Des Cahill
  • 163
  • 2
  • 3
  • 15
  • In your Template `base.html`, try **`{{artist.artist_name}}`** instead of `{{ artist.artist_id }}`. – ans2human Jul 11 '18 at 08:11
  • Thanks for the response. I have tried that and its still the same. I tried putting a test list item in with plain text and it doesn't work inside the for loop but does outside the for loop. – Des Cahill Jul 11 '18 at 09:39
  • brother, let me work on your code. Give me Some time. – ans2human Jul 11 '18 at 10:31

2 Answers2

2

In your View.py you have ArtistView where template is artistlist.html and your context is all_artist & you get all objects from db.

Code:

class ArtistView(generic.ListView):
model = Artist
template_name = 'music/artistlist.html'
context_object_name = 'all_artists'

def get_queryset(self):
    return Artist.objects.all()

Now i believe you have a template named artistlist.html. If not create it in templates in which you will use for Loop to render artist list so the code should be this for artistlist.html:

{% extends 'music/base.html' %}
{% block body %}

   <h1>Artists!</h1>

<ul>
{% for artist in all_artists %}
  <li class="artist">
     <h1>
         <a href='/music/{{ artist.id }}'>{{artist.artist_name }}</a>  
     </h1>
  </li>
{% endfor %}
</ul>

</div>

{% endblock %}

You can Render Artist list in Base.html. Using: Context Processor

First Create a file named context_processors.py in your App.Then add this code in that file.

from .models import Artist

def basetest(request):

    hello = Artist.objects.values_list("artist_name", flat=True)
    return {
        'testname': hello
    }

After that, open Settings.py and find context_processors and add the following settings 'yourapp.context_processors.add_variable_to_context'.

Settings.py

TEMPLATES = [
{
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [],
    'APP_DIRS': True,
    'OPTIONS': {
        'context_processors': [
            'django.template.context_processors.debug',
            'django.template.context_processors.request',
            'django.contrib.auth.context_processors.auth',

            #This one is from my code so set it according to you
            #appname.context_processors.function_name_context_processor.py',

            'blog.context_processors.basetest',

        ],
    },
},
]

After this just place {{ testname }} in your base.html according to your need. it will work. No need for looping just the interpolation will render you a list. Format it according to your need by following this doc

ans2human
  • 2,300
  • 1
  • 14
  • 29
  • Apologies, i forgot to mention that my end goal is to have it in a separate file. I was trying to just get it working in my base.html first as I can create a block item for it later in a separate file. I have changed it to the above now but still get no result. I have opened the python console and get results when searching for Artist.objects.all()
    In [10]: Artist.objects.all()
    Out[10]: , ]>
    – Des Cahill Jul 11 '18 at 21:58
  • 1
    @DesCahill, i have updated the code to render model data in your `base.html`. – ans2human Jul 12 '18 at 05:41
  • Hi Ans2Human I wanted to take some time to have a good go at what you mentioned above in your latest update using the context processors. I have tried what you are saying and I get a response with: , ]> but it shows up as plain text which is interesting but i don't know how to work with that to create a separate
  • item with hyperlink for each item.
  • – Des Cahill Jul 12 '18 at 16:25
  • 1
    @DesCahill Link provided at the end of question is for you to understand how can you format the data and to create links i have updated my ans for that. The answer solves your main query of rendering data on `base.html`. – ans2human Jul 13 '18 at 04:30
  • Sure thing, I saw that, so thanks for the help, but I dont know how to work with that and dont understand the reference on the other page, so I am going to try and get the for loop working, as that is more along the line of what i understand. – Des Cahill Jul 13 '18 at 09:07
  • 1
    @DesCahill, help me by accepting the answer as it solved your primary problem. – ans2human Jul 13 '18 at 09:23
  • I appreciate the help that you have provided but it is not a solution, and I still am no further towards a solution, and want to see if others can assist with helping me get the for loop working as that should work. The context processors method is interesting but I have not been able to get anything to work with that other than printing to the screen the results of the db query. I really do appreciate you trying to help though. – Des Cahill Jul 13 '18 at 14:50
  • 1
    Thanx for your appreciation. – ans2human Jul 13 '18 at 16:59
  • 1
    Worked like a charm. Tip for everyone. The above solution is for those, who want to have some data always available somewhere all throughout the website. E.g: Navbar dropdown list. Or else, you will have to pass the query results always from all views. Thanks Anshuman. Super solution. – Arindam Roychowdhury Jan 31 '21 at 22:19
  • Happy to help @Arindam – ans2human Feb 01 '21 at 05:06