Django MultiValueKeyDictError в forms.py при фильтрации набора запросов - PullRequest
1 голос
/ 01 октября 2019

Я пытаюсь отфильтровать набор запросов в forms.py так, чтобы конкретный автор (отношение 1: 1 со встроенным пользователем django) мог просматривать только символы, принадлежащие им. Когда я пытаюсь фильтровать что-либо кроме автора, все работает нормально. Когда я фильтрую по автору, форма изначально загружается правильно, но при POST я получаю MultiValueKeyDictError.

Вот текст ошибки:

MultiValueDictKeyError at /rmi/1/post/new
'cur_author'
Request Method: POST
Request URL:    http://127.0.0.1:8000/rmi/1/post/new
Django Version: 3.0.dev20190323160439
Exception Type: MultiValueDictKeyError
Exception Value:    
'cur_author'
Exception Location: c:\users\user\desktop\learnpython\django\django\utils\datastructures.py in __getitem__, line 78
Python Executable:  C:\.virtualenvs\djangodev\Scripts\python.exe
Python Version: 3.7.2
Python Path:    
['C:\\Users\\USER\\Desktop\\rmi',
 'C:\\Users\\USER\\AppData\\Local\\Programs\\Python\\Python37\\python37.zip',
 'C:\\Users\\USER\\AppData\\Local\\Programs\\Python\\Python37\\DLLs',
 'C:\\Users\\USER\\AppData\\Local\\Programs\\Python\\Python37\\lib',
 'C:\\Users\\USER\\AppData\\Local\\Programs\\Python\\Python37',
 'C:\\.virtualenvs\\djangodev',
 'C:\\.virtualenvs\\djangodev\\lib\\site-packages',
 'c:\\users\\user\\desktop\\learnpython\\django']

views.py:

@login_required
def create_thread(request, board_id):
    board_style = 'css/board' + str(board_id) + '.css'
    cur_author = get_object_or_404(Author, user=request.user)

    if request.method == "POST":    
        form = CreatePost(request.POST)

        if form.is_valid():
            post = form.save(commit = False)
            post.board = get_object_or_404(Board, pk=board_id)
            post.created_at = timezone.now()
            post.parent = None

            post.save()

            return redirect('board', board_id)
    else: 

        data ={
            'cur_author': cur_author,
        }

        form = CreatePost(data)

        context ={
            'form': form,
            'board_id': board_id,
            'board_style': board_style,
        }

    return render(request, 'rmi/create_post.html', context)

и это Forms.py:

class CreatePost(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['character', 'title', 'content', 'parent']
        widgets = {'parent': forms.HiddenInput()}

    def __init__(self,cur_author):
        super(CreatePost, self).__init__(cur_author)
        self.fields['character'].queryset = Character.objects.filter(author=cur_author['cur_author'])

и сам шаблон:

{% block content %}
<form method="POST" class="create-post" style="margin-top: -2%">
    {% csrf_token %}

    <div class="container-fluid">
        <div class="row">
            <div class="col-sm-1 offset-2" style="margin-top:.25%">
                <label for="{{ form.character.id_for_character }}">Character</label>
            </div>
            <div class="col-sm-5">
                {{ form.character }}
            </div>
        </div>

        <div class="row">
            <div class="col-sm-1 offset-2" style="margin-top:.5%;">
                <label for="{{ form.title.id_for_title }}">Subject</label>
            </div>
            <div class="col-sm-5">
                {{ form.title }}
            </div>
        </div>

        <br />

        <div class="row">
            <div class="col-sm-1 offset-2">
                <label for="{{ form.content.id_for_content }}">Message</label>
            </div>
        </div>

        <div class="row">
            <div class="col-sm-5 offset-2">
                {{ form.content }}
            </div>
        </div>
    </div>

    <div class="row" style="margin-top:2%; margin-left:auto; margin-right:auto">
        <div class="col-sm-2 offset-2">
            <button type="submit" class="button" style="margin-right:2%">Submit Post</button>
        </div>

        <div class="col-sm-3">
            <a class="button" href="{% url 'board' board_id %}">Return to Messages</a>
        </div>
    </div>

</form>
{% endblock %}

Я попытался специально передать cur_author в форму, но когдав этом случае я получаю TypeError:

TypeError at /rmi/1/post/new
__init__() takes 2 positional arguments but 3 were given
Request Method: POST
Request URL:    http://127.0.0.1:8000/rmi/1/post/new
Django Version: 3.0.dev20190323160439
Exception Type: TypeError
Exception Value:    
__init__() takes 2 positional arguments but 3 were given
Exception Location: C:\Users\USER\Desktop\rmi\rmi\views.py in create_thread, line 102
Python Executable:  C:\.virtualenvs\djangodev\Scripts\python.exe
Python Version: 3.7.2
Python Path:    
['C:\\Users\\USER\\Desktop\\rmi',
 'C:\\Users\\USER\\AppData\\Local\\Programs\\Python\\Python37\\python37.zip',
 'C:\\Users\\USER\\AppData\\Local\\Programs\\Python\\Python37\\DLLs',
 'C:\\Users\\USER\\AppData\\Local\\Programs\\Python\\Python37\\lib',
 'C:\\Users\\USER\\AppData\\Local\\Programs\\Python\\Python37',
 'C:\\.virtualenvs\\djangodev',
 'C:\\.virtualenvs\\djangodev\\lib\\site-packages',
 'c:\\users\\user\\desktop\\learnpython\\django']

Извинения, если я пропускаю какую-либо информацию, я впервые публикую это сообщение вместо того, чтобы просто просматривать.

1 Ответ

2 голосов
/ 01 октября 2019

Вы неправильно переопределяете метод __init__. В общем, вы хотите оставить нетронутыми аргументы ModelForm и просто добавить свой собственный параметр в kwargs:

def __init__(self, *args, **kwargs):
    cur_author = kwargs.pop('cur_author', None)  # pop custom param before calling super()
    super().__init__(*args, **kwargs)
    self.fields['character'].queryset = ...  # use custom param

Это потому, что ModelForm принимает несколько аргументов, а не только data. И также таким образом, вы не добавляете cur_author к data, что портит вашу форму, поскольку она должна быть несвязанной, когда нет данных: form = CreatePost(cur_author=cur_author) инициализирует несвязанную форму, а form = CreatePost(request.POST) инициализируетсвязанная форма с data = request.POST и cur_author unset.

Вы также можете явно использовать параметр cur_author, но тогда вам также нужно явно использовать data при инициализации формы с данными:

def __init__(self, cur_author=None, **kwargs)
    super().__init__(**kwargs)  # data is in kwargs
    self.fields['character'].queryset = ...

Тогда вы инициализируете связанную форму с CreatePost(data=request.POST), иначе данные будут присвоены cur_author.

...