Как изменить сообщения об ошибках по умолчанию, отображаемые формами Django

Я создал форму в Django с полем char с max_length=255 следующим образом:

task = models.CharField(max_length= 255)

Теперь я хочу, чтобы пользователь знал, сколько символов он набрал, если он превышает ограничение в 255 символов, поэтому я сделал следующее:

if form.is_valid():
    #some code
else:
    messages.info(request,(form.errors.get("task").as_text()))

теперь предположим, что если я наберу 445 символов в поле формы и отправлю, то по умолчанию я получу следующее сообщение об ошибке:

* Ensure this value has at most 255 characters (it has 445).

но вместо этого я хочу изменить это сообщение на:

Error: maximum length limit is 255 characters (it has 445).

Поэтому я попробовал следующее:

class ListForm(ModelForm):
    class Meta:
        model = ListModel
        fields = ["task", "status"]

        error_messages = {
            'task': {
                'max_length': ("Error: maximum length limit is 255 characters"),
                
            },
        }

Теперь сообщение было изменено на:

* Error: maximum length limit is 255 characters.

Моя проблема:

  1. Я не хочу, чтобы * отображалось перед сообщениями
  2. Мне не удалось зафиксировать количество введенных пользователем символов, которое отображалось в сообщении по умолчанию, т.е. (it has 445)

Что я могу сделать, чтобы напечатать Error: maximum length limit is 255 characters (it has 445). вместо * Error: maximum length limit is 255 characters.?


person yogeshiitm    schedule 09.01.2021    source источник
comment
Не могли бы вы показать нам HTML для формы? Я почти уверен, что звездочка * — это HTML <li>.   -  person Countour-Integral    schedule 09.01.2021
comment
Я использовал класс формы Django для создания формы, поэтому я не определял HTML исключительно для формы.   -  person yogeshiitm    schedule 09.01.2021
comment
Конечно, но проблема в том, как вы получаете доступ к messages.info в своем шаблоне. Для меня messages.info не содержит звездочки, если я обращаюсь к нему без каких-либо тегов HTML. Стандартный класс django.forms.Form не отображает HTML для messages.info, вы должны получить к нему доступ самостоятельно.   -  person Countour-Integral    schedule 09.01.2021
comment
Хорошо, теперь я понял вашу точку зрения, чтобы получить доступ к сообщению в HTML, я делаю следующее: {% if messages %}{% for message in messages %} <p>{{ message }}</p> {% endfor %}{% endif %}, поэтому я не думаю, что использую какой-либо класс ‹li› в своем HTML.   -  person yogeshiitm    schedule 09.01.2021
comment
Странный. Может быть, вы могли бы попробовать поставить messages.info(request, "some test string") и сообщить нам, есть ли та же проблема. Вы также можете попробовать print(form.errors.get("task").as_text()), чтобы увидеть, есть ли там звездочка или это проблема HTML. Также скобки лишние   -  person Countour-Integral    schedule 09.01.2021
comment
messages.info(request, "string") просто отображает строку без *, но да, * появляется даже на print(form.errors.get("task").as_text()). На самом деле, если я делаю print(form.errors.get("task")), то он печатает <ul class="errorlist"><li>"some_string"</li></ul>, поэтому класс ‹li› находится в пределах form.errors   -  person yogeshiitm    schedule 09.01.2021


Ответы (2)


Я не хочу *, который отображается перед сообщениями

Проблема, как вы наконец пришли к выводу (в комментариях), заключается в

form.errors.get("task").as_text()

Это отправляет клиенту элемент <ul> HTML, а не обычный текст. Чтобы решить эту и другую проблему, вы можете просто проверить, можно ли найти max_length в form.errors, и использовать свой собственный string. Следующее должно появиться в вашем представлении после вызова form.is_valid

# After this point form.is_valid() has been called
if "max_length" in form.errors:
    task = request.POST.get("task") # Get the text that was entered in `task`
    length_of_task = len(task) 
    # Simply send your own message
    messages.info(request, f"Error: maximum length limit is 255 characters (it has {length_of_task}).")

Обратите внимание на несколько вещей здесь

  • Доступ к данным с помощью request.POST.get

@SaeX указал, что вы можете использовать self.cleaned_data.get для получения данных, которые были отправлены в запросе POST. Хотя это верно, это работает только в том случае, если form.is_valid вернуло значение true. Вы можете узнать больше здесь.

  • Что делать, если я хочу поймать несколько ошибок и использовать словарь

Вы все еще можете использовать словарь, но для значений вам придется использовать функции. Что-то вроде следующего

def handle_max_length(data):
    datalen = len(data) > 255 # Do your stuff
    
def handle_some_other_error(data):
    pass 

errors = {
    'max_length' : handle_max_length,
    'some_other_error': handle_some_other_error
}

def myView(request):
    # ... code
    form = MyForm()
    if not form.is_valid():
        for field in form.errors:
            field_value = request.POST.get(field)
            for error in field:
                messages.info(
                    request, errors.get(error)(field_value) # Getting the function and calling it with the data
                )
person Countour-Integral    schedule 09.01.2021
comment
Итак, я напечатал form.errors, это примерно так: <ul class="errorlist"><li>item<ul class="errorlist"><li>Ensure this value has at most 255 characters (it has 445).</li></ul></li></ul>, поэтому max_length отсутствует в form.errors, и поэтому условие if "max_length" in form.errors всегда будет возвращать False. Но все же ваше решение решило мою проблему, так как, когда form.is_valid() имеет значение False, нам больше не нужно if "max_length" in form.errors, мы можем напрямую выполнить if length_of_task > 255 и напечатать сообщение. Большое спасибо за вашу помощь. - person yogeshiitm; 10.01.2021
comment
Доступ к request.POST и выполнение собственной проверки в большинстве случаев является лучшим выбором. Обратите внимание, что в некоторых крайних случаях, когда вы можете отправлять файлы, вы можете получить доступ к данным из request.POST только один раз (данные файла). В остальном все работает нормально. - person Countour-Integral; 10.01.2021

Вы можете использовать clean_<fieldname>() в своей форме, например:

def clean_task(self):
    task = self.cleaned_data.get("task")

    if len(task) > 255:
        raise ValidationError("Error: maximum length limit is 255 characters (it has %s.") % len(task)

    return task

См. https://docs.djangoproject.com/en/3.1/ref/forms/validation/#cleaning-a-specific-field-attribute

person SaeX    schedule 09.01.2021
comment
после добавления функции в мою форму мне нужно вызвать ее где-нибудь в моем views.py, потому что после добавления я получаю сообщение по умолчанию * Ensure this value has at most 255 characters (it has 445). вместо пользовательского сообщения - person yogeshiitm; 09.01.2021
comment
Это будет работать только тогда, когда form.is_valid() возвращает true. - person Countour-Integral; 09.01.2021