TypeError: Поле 'id' ожидало число, но получило объект DeferredAttribute в 0x000002B6ADE878D0 - PullRequest
3 голосов
/ 06 января 2020

Я использую набор запросов в Django - всякий раз, когда я запускаю сервер, он выдает ошибку.

TypeError: Field 'id' expected a number but got <django.db.models.query_utils.DeferredAttribute object at 0x000002B6ADE878D0

Что-то в наборе запросов моей формы вызывает ошибку.

Я не знаю, является ли это проблемой с моими моделями .py или мой forms.py Я попытался найти этот объект DeferredAttribute в Google, но я не нашел ни одного ответа, который бы мне помог.

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:

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})    

1 Ответ

2 голосов
/ 06 января 2020

Такое утверждение, как:

form = TaskForm(<s>get_user_model()</s>)

не имеет большого смысла. Действительно, get_user_model() возвращает ссылку на пользователя class , а не на пользователя object (как вошедший в систему пользователь). Вы можете создать такую ​​форму с помощью:

from django.contrib.auth.decorators import login_required

<b>@login_required</b>
def task_create(request):
    form = TaskForm(<b>request.user</b>)
    context = {'form': form}
    html_form = render_to_string('tasks/partial_task_create.html',
        context,
        request=request,
    )
    return JsonResponse({'html_form': html_form})

Здесь мы используем @login_required декоратор [Django -doc] , чтобы запретить пользователю, который не является авторизовался для доступа к представлению. Это полезно, поскольку в этом случае request.user не является пользовательским объектом.

или в CreateView [Django -doc] вы можете переопределить метод get_form_kwargs [Django -doc] на:

from django.contrib.auth.mixins import LoginRequiredMixin

class TaskCreateView(<b>LoginRequiredMixin</b>, CreateView):
    template_name = 'create.html'
    form_class = <b>TaskForm</b>
    success_url = reverse_lazy('task_list')

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        <b>kwargs.update(user=self.request.user)</b>
        return kwargs

Для того, чтобы заставить пользователя войти в систему, мы затем используем a LoginRequiredMixin mixin [Django -doc] .

...