Search code examples
pythondjangouser-input

Problem with Displaying the Output of models.ManyToManyField(User)


I am learning Django by building an application, called TravelBuddies. It will allow travelers to plan their trip and keep associated travel items (such as bookings, tickets, copy of passport, insurance information, etc), as well as create alerts for daily activities. The application will also able to update local information such as weather or daily news to the traveler. Travelers can also share the travel information with someone or have someone to collaborate with them to plan for the trip.

I am facing a problem. I have added two activities for Kuala Lumpur through Django admin. They are "Going to Botanical Garden" and "Going to Aquaria."

When I go to http://127.0.0.1:8000/triplist/, I see this page: enter image description here

As you can see, in the Co-planner field, the name of the user is being displayed as <QuerySet [<User: williams>]>.But it is supposed to be displayed as Co-planner: williams.

Same problem occurs when I click on Trip Name: Kuala Lumpur and taken to http://127.0.0.1:8000/triplist/kuala-lumpur/: enter image description here

Here are my codes in models.py:

from django.contrib.auth.models import User
from django.db import models

# Create your models here.
from django.template.defaultfilters import slugify

class Trip(models.Model):
    trip_name = models.CharField(max_length=100)
    date = models.DateField()
    planner_name = models.CharField(max_length=100)
    add_coplanner = models.ManyToManyField(User)
    slug = models.SlugField(max_length=150, default='null')

    def __str__(self):
        return self.trip_name

    def save(self, *args, **kwargs):
        self.slug = slugify(self.trip_name)
        super().save(*args, **kwargs)

class Activity(models.Model):
    trip = models.ForeignKey(Trip, on_delete=models.CASCADE)
    activity_name = models.CharField(max_length=100)
    date = models.DateField(auto_now=True)
    time = models.TimeField(auto_now= True)
    location = models.CharField(max_length=100)
    item_type = models.CharField(max_length=100)
    item_number = models.CharField(max_length=100)
    add_cotraveller = models.ManyToManyField(User)
    slug = models.SlugField(max_length=150, default='null')

    def __str__(self):
        return self.activity_name

    def save(self):
        super(Activity, self).save()
        self.slug = '%i-%s' % (
            self.id, slugify(self.trip.trip_name)
        )
        super(Activity, self).save()

Here are my codes in views.py:

from django.views import generic
from .models import Trip, Activity


class TripListView(generic.ListView):
    template_name = 'trips/triplist.html'
    context_object_name = 'all_trips'

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


class ActivityView(generic.DetailView):
    model = Trip
    template_name = 'trips/activity.html'

Here are my codes in urls.py:

from . import views
from django.urls import path

app_name = 'trips'

urlpatterns = [
    path('triplist/', views.TripListView.as_view(), name='triplist'),
    path('triplist/<slug:slug>/', views.ActivityView.as_view(), name='activity'),
]

Here are my codes in apps.py:

from django.apps import AppConfig


class TripsConfig(AppConfig):
    name = 'trips'

Here are my codes in triplist.html:

<!DOCTYPE html>
{% extends 'trips/base.html' %}
{% load static %}
<html lang="en">
<link rel="stylesheet" type="text/css" href="{% static "css/style.css" %}">

<head>
    <meta charset="UTF-8">
    {% block title%}Trip list{% endblock %}
    <title>Trip list</title>
</head>


<body>
    {% block content %}
    <!--Page content-->
    <h1>This is Trip List Page</h1>


    <ol>
        {% for trip in all_trips %}
        <ol>
            <li><a href="{% url 'trips:activity' trip.slug %}">Trip name: {{ trip.trip_name }}</a></li>
            Date: {{ trip.date }}<br>
            Planner: {{ trip.planner_name }}<br>
            Co-planner: {{ trip.add_coplanner.all }}<br>
        </ol>
        {% endfor %}


    </ol>

    <img src="{% static "images/botanical-garden.jpg" %}" alt="Botanical Garden" />
    <!-- New line -->
    {% endblock %}
</body>
</html>

</html>

Here are my codes in activity.html:

{% extends 'trips/base.html' %}
{% block title%}
Detail
{% endblock %}


{% block content %}

<h3>Activities for {{trip.trip_name}} </h3>

{% for trip_item in trip.activity_set.all %}
<!--<p>Activity name: {{ trip_item.activity_name }}</p>-->
<ol>
    <li>Activity name: {{ trip_item.activity_name }}</li>
    Date: {{ trip_item.date }}<br>
    Time: {{ trip_item.time }}<br>
    Location: {{ trip_item.location }}<br>
    Item Type: {{ trip_item.item_type }}<br>
    Item No: {{ trip_item.item_number }}<br>
    Co-traveller: {{ trip_item.add_cotraveller.all }}
</ol>
{% endfor %}

{% endblock %}

Is there anything wrong with triplist.html and activity.html?

Update 1: By the way, I got the idea of this code add_coplanner = models.ManyToManyField(User) from this link: Auth.User.None when rendering a ManyToManyField.

The person who asked the question also faced the same issue like me. He was getting something like <User: gg>]>. He was advised to override str() method. But I don't understand how to do it.


Solution

  • You need to iterate here since it is the queryset

    triplist.html

      Coplanners: 
        {% for user in trip.add_coplanner.all %}
            {{user.name}} 
            #{{user.username}} do this if your User model don't have name field
         #If you want to separate the users with comma
           {% if not forloop.last %} , {% endif %}
        {% endfor %}<br>