Home > Software design >  How to filter by author in Django? Getting error: Field 'id' expected a number
How to filter by author in Django? Getting error: Field 'id' expected a number

Time:07-09

I have a Django application that functions like a diary, where the homepage is an index list of all diary entries previously created. I am now trying to filter the index so that the user will only see the diary entries that they have created. Here is what I have done:

Views.py

from django.shortcuts import render
from .models import DiaryEntry
from django.views import generic
from django.views.generic.edit import CreateView

def index(request):
    """View function for MyDiary."""

    author = DiaryEntry.author
    diary_entry = DiaryEntry.objects.filter(author=author).order_by('-created_on')

    context = {
         "diary_entry": diary_entry,
    }

    return render(request, 'diary_index.html', context=context)


class EntryDetailView(generic.DetailView):
    model = DiaryEntry
    def get_data(self, **kwargs):
        context = super(EntryDetailView, self).get_data(**kwargs)
        return context
 
class EntryCreate(CreateView):
    model = DiaryEntry
    fields = ['title', 'content']
    def form_valid(self, form):
       form.instance.author = self.request.user
       return super().form_valid(form)

Models.py

from django.db import models
from django.urls import reverse
from django.conf import settings

User = settings.AUTH_USER_MODEL

class DiaryEntry(models.Model):
    title = models.CharField(max_length=255)
    content = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    author = models.ForeignKey(User, 
                        on_delete = models.CASCADE
                        )
    def __str__(self):
        """String for representing the diary object."""
        return self.title
    def get_absolute_url(self):
        """Returns the url to access a detail record for this user entry."""
        return reverse('entry-detail', args=[str(self.id)])

HTML:

{% extends "base.html" %}
{% block page_content %}
<div >
    <h1>This is your diary!</h1>
    <hr>
    <h2>Here, you can write about anything you want to.</h2>
    <br>
    <div >
    <a  href="{% url 'entry-create' %}" role="button">Create a new diary entry</a>
    </div>
    <br>
    <br>
    {% for entry in diary_entry %}
    <h2><a href="{% url 'entry-detail' entry.pk %}">{{ entry.title }}</a></h2>
    <small>
        {{ entry.created_on.date }} |&nbsp;
    </small>
    <p>{{ entry.content | slice:":400" }}...</p>
    {% endfor %}

</div>
{% endblock %}

And URLs:

from django.urls import path
from . import views

urlpatterns = [
path('', views.index, name='diary_index'),
 path('entry_detail/<int:pk>/', views.EntryDetailView.as_view(),  name='entry-detail'),
 path('entry/create/', views.EntryCreate.as_view(), name='entry-create'),
]

When I run the above, I get the following error: Field 'id' expected a number but got <django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x7f12feef3400>.

Can someone please help me resolve this? I have reviewed other answers to similar issues but I am still lost as to how to correctly filter the entries by author.

Thanks in advance!

CodePudding user response:

The issue is on this line author = DiaryEntry.author. If you want to filter by author, you need to have an author to filter by, this line only selects the property, it does not give you an author. Let's take this example:

author = Author.objects.get(id=1)
diary_entry = DiaryEntry.objects.filter(author=author).order_by('-created_on')

This would filter the diary entries by the author with id 1. You can even do this in one line so you don't need to query twice:

diary_entry = DiaryEntry.objects.filter(author__id=1).order_by('-created_on')

Hope this makes sense. So the question to you is, what author do you want to filter by, how do you get that author?

Assuming the author is the user:

diary_entry = DiaryEntry.objects.filter(author=request.user).order_by('-created_on')
  • Related