I am using a queryset in Django- whenever I run the server, it gives an error.
TypeError: Field 'id' expected a number but got <django.db.models.query_utils.DeferredAttribute object at 0x000002B6ADE878D0
It is something about the queryset of my form that causes the error.
I don't know whether its an issue with my models.py or my forms.py I tried looking up this DeferredAttribute object on Google, but I didn't really see any answer that works for me.
forms.py:
from .models import Task, Categories
from django import forms
from django.forms import ModelForm
from django.db.models import Q
class TaskForm(ModelForm):
task_title = forms.CharField(max_length=100)
task_description = forms.CharField(widget=forms.Textarea)
due_date = forms.DateTimeField()
is_completed = forms.BooleanField()
#categories = forms.ModelChoiceField(empty_label="---None---")
class Meta:
model = Task
fields = ['task_title', 'task_description', 'due_date', 'is_completed', 'categories', 'parent']
def __init__(self, user, *args, **kwargs):
# Get all the categories from the database for that specific user
super(TaskForm, self).__init__(*args, **kwargs)
# It is something about this line that causes the error
self.fields['categories'].queryset = Categories.objects.filter(Q(user_id__isnull=True) | Q(user_id=user.id))
models.py:
from django.db import models
from django.db.models import Q
from users.models import CustomUser
from django.urls import reverse
from django.contrib.auth import get_user_model
class Categories(models.Model):
category_type = models.CharField(max_length=50)
user = models.ForeignKey(CustomUser, null = True, on_delete=models.CASCADE)
def __str__(self):
return '%s ' % (self.category_type)
def get_absolute_url(self):
return reverse('task_list')
class Task(models.Model):
task_title = models.CharField(max_length=100)
task_description = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
due_date = models.DateTimeField()
is_completed = models.BooleanField(default=False)
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
categories = models.ForeignKey('Categories', on_delete=models.CASCADE)
parent = models.ForeignKey("self", on_delete=models.CASCADE)
class Meta:
verbose_name = "Task"
verbose_name_plural = "Tasks"
def __str__(self):
return '%s ID: %s' % (self.task_title, self.last_name)
def get_absolute_url(self):
return reverse('task_detail')
CustomUser model:
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
nationality = models.CharField(null=True, blank=True, max_length=60)
views.py:
from django.views.generic import TemplateView
from django.views.generic.edit import UpdateView, DeleteView , CreateView
from django.urls import reverse_lazy
from .forms import TaskForm
from django.contrib.auth import get_user_model
from django.http import JsonResponse
from django.template.loader import render_to_string
class TaskListView(TemplateView):
template_name = "tasks.html"
# This is the actual create view I am for using now
class TaskCreateView(CreateView):
template_name = 'create.html'
form_class = TaskForm(get_user_model())
success_url = reverse_lazy('task_list')
# I am using this for a modal, but its not working so I fell back to the normal create view
def task_create(request):
form = TaskForm(get_user_model())
context = {'form': form}
html_form = render_to_string('tasks/partial_task_create.html',
context,
request=request,
)
return JsonResponse({'html_form': html_form})
A statement like:
form = TaskForm(get_user_model())
does not make much sense. Indeed, get_user_model()
returns a reference to the user class, not to a user object (like the logged in user). You can construct such a form with:
from django.contrib.auth.decorators import login_required
@login_required
def task_create(request):
form = TaskForm(request.user)
context = {'form': form}
html_form = render_to_string('tasks/partial_task_create.html',
context,
request=request,
)
return JsonResponse({'html_form': html_form})
Here we use the @login_required
decorator [Django-doc] to prevent user that are not logged in to access the view. This is useful, since in that case request.user
is not a user object.
or in the CreateView
[Django-doc] you can override the get_form_kwargs
method [Django-doc] to :
from django.contrib.auth.mixins import LoginRequiredMixin
class TaskCreateView(LoginRequiredMixin, CreateView):
template_name = 'create.html'
form_class = TaskForm
success_url = reverse_lazy('task_list')
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.update(user=self.request.user)
return kwargs
In order to enforce a user to be logged in, we then use a LoginRequiredMixin
mixin [Django-doc].
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With