Arrow
Arrow14. Januar 2019 11:42

Сохранение данных из выпадающего списка в модель

select, choices

Добрый день!

Возникла проблема с выпадающим списком, а точнее с сохранением из него данных.

Приведу простой пример.

Модель имеет вид (models.py)

from django.db import models

# Create your models here.
class Test(models.Model):
    METRIC = 'metric'
    IMPERIAL = 'imperial'
    ATHER = ''
    UNIT = (
        (METRIC, 'kg'),
        (IMPERIAL, 'lb'),
        (ATHER, 'none')
    )
    name = models.CharField(max_length=25)
    temperature_unit = models.CharField(max_length=8,
                                        choices=UNIT,
                                        default=METRIC)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name_plural = 'tests'

Файл forms.py

from django.forms import ModelForm, TextInput
from .models import Test

class TestForm(ModelForm):
    class Meta:
        model = Test
        fields = ['name', 'unit']
        widgets = {'name': TextInput(attrs={'class': 'input', 'placeholder': 'Name'})}

Файл *.html

<form method="POST">
    {% csrf_token %}
        <div class="field has-addons">
            <div class="control is-expanded">
                {{ form.name }}
            </div>
            <select>
                {% for temp in form.tunit %}
                    <option value=""{{ temp.data.value }}>{{ temp.data.label }}</option>
                {% endfor %}
             </select>
             <div class="control">
                <button type="submit" class="button is-info">
                    Add Unit
                </button>
            </div>
        </div>
</form>

В результате в качестве value выпадающего списка (temp.data.value) оказывается 'metric', 'imperial' и '', а в самом выпадающем списке на странице оказывается (temp.data.label): kg, lb, none. Как и должно быть.

Только при вводе данных в поле формы (name = models.CharField(max_length=25)) и попытке сохранения вылетает ошибка. В результате просмотра request.POST в нем оказывается только значение 'name' без 'unit'.

Файл views.py

import requests
from django.shortcuts import render
from .models import Test
from .forms import TestForm

def index(request):
    url = 'http://api.site.org/data/2.5/?q={}&units={}&id=1111&appid=111111111'

    if request.method == 'POST':
        # Здесь request.POST нет данных unit только name
        # Вылетает ошибка
        form = TestForm(request.POST) 
        form.save()

    tests = Test.objects.all()

    test_data = []

    for test in tests:
        # Преобразование данных из metric в kg итд.
        r = requests.get(url.format(test, test.unit)).json()
        res = [data for (t_type, data) in Test.UNIT if t_type == test.unit]

        test_w = {
            'name': test.name,
            'unit': res[0],
            'temp': r['main']['temp'],
            'description': r['data'][0]['description'],
            'icon': r['data'][0]['icon'],
        }

        test_data.append(test_w)

    context = {'test_data': test_data, 'form': form}

    return render(request, 'module/module.html', context)

Что я делаю не так?
Возможно есть другой способ более правильный:
поместить данные о unit в отдельную таблицу в базе данных и вытягивать от туда или еще как-то?

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

18
Evgenii Legotckoi
  • 14. Januar 2019 11:46

Добрый день!

Так у вас в модели поде unit объявлено как temperature_unit

Вы имя перепутали

Так нужно

from django.forms import ModelForm, TextInput
from .models import Test

class TestForm(ModelForm):
    class Meta:
        model = Test
        fields = ['name', 'temperature_unit']
        widgets = {'name': TextInput(attrs={'class': 'input', 'placeholder': 'Name'})}

Ну и так далее везде поменяйте unit на temperature_unit

    Arrow
    • 14. Januar 2019 11:52

    Я уже поправил. Скопировал данные из реального и тестово проектов. Ошибка вышла. Извините. :(

      Arrow
      • 14. Januar 2019 11:53
      • (bearbeitet)

      Но вопрос остался

        Arrow
        • 14. Januar 2019 13:59

        Посмотрел документацию, делаю правильно, но не работает.

          Evgenii Legotckoi
          • 14. Januar 2019 14:54

          я так понимаю, у вас там в шаблоне пропущены id и name поля, поэтому и пропускаются значения, а они там должны быть.

          <select id="id_temperature_unit" name="temperature_unit">
              {% for temp in form.temperature_unit %}
                   <option value=""{{ temp.data.value }}>{{ temp.data.label }}</option>
              {% endfor %}
          </select>
          

          Вообще у Field есть методы для получения этих всех id и name, но я как-то не помню их, нужно в документации покопаться.

          А так я использую django_bootstrap4, там эти моменты уже реализованы, так что всё автоматически работает. Не нужно всю эту вёрстку делать вручную.

            Arrow
            • 14. Januar 2019 14:55

            Все исправил, все пересмотрел еще раз.
            Понять не могу почему я в качестве request.POST при попытке сохранения данных, от формы получаю:

            {'csrfmiddlewaretoken': 'BrD9OchYiCLJJAV3U8MX7NewnCO2uZ2EjmyfOIesySZp6dmcyoA1GRwnwReSch0T',
            'name': 'Unit1'}

            а не:

            {'csrfmiddlewaretoken': 'BrD9OchYiCLJJAV3U8MX7NewnCO2uZ2EjmyfOIesySZp6dmcyoA1GRwnwReSch0T',
            'name': 'Unit1', temperature_unit: 'kg'}

              Evgenii Legotckoi
              • 14. Januar 2019 15:03
              • (bearbeitet)

              А как выглядит отрендеренная форма? В смысле html можете показать итоговый?
              То есть открываете страницу с формой и через браузер посмотрите html и покажите, что там вышло.
              Вот например у меня в одной из форм так получается.

              <select name="type" id="id_type" class="form-control" title="">
                  <option value="T" selected="">Руководство</option>
                  <option value="N">Новости</option>
                  <option value="S">Сниппет</option>
                  <option value="O">Заметка</option>
              </select>
              
                Arrow
                • 14. Januar 2019 15:08
                • (bearbeitet)

                После исправления:

                <select id="id_temperature_unit" name="temperature_unit">
                    {% for temp in form.temperature_unit %}
                         <option value=""{{ temp.data.value }}>{{ temp.data.label }}</option>
                    {% endfor %}
                </select>
                

                Получаю:

                {'csrfmiddlewaretoken': ['EvCSJRprJbsn3Rte7AxtnpeXeNO3pIThmqxYJnmVZrG3quUnLQlxWtwOn2eT70Rw'], 'name': ['Lviv'], 'temperature_unit': ['']}

                Только что-бы я не выбрал в списке значение temperature_unit не меняется.

                Форма выглядит так:

                Пытаюсь на сайт притулить индикатор погоды с выбором в каких унитах показывать температеру.

                  Evgenii Legotckoi
                  • 14. Januar 2019 15:12

                  Нет, вы не поняли, покажите мне отрендеренный html из консоли браузера.

                  Вот отсюда

                    Arrow
                    • 14. Januar 2019 15:16

                    Все ясно:

                      Evgenii Legotckoi
                      • 14. Januar 2019 15:18
                      • Die Antwort wurde als Lösung markiert.

                      И кстати да, я увидел вашу ошибку,

                      вот ваш код

                      <select id="id_temperature_unit" name="temperature_unit">
                          {% for temp in form.temperature_unit %}
                               <option value=""{{ temp.data.value }}>{{ temp.data.label }}</option>
                          {% endfor %}
                      </select>
                      

                      а вот как надо

                      <select id="id_temperature_unit" name="temperature_unit">
                          {% for temp in form.temperature_unit %}
                               <option value="{{ temp.data.value }}">{{ temp.data.label }}</option>
                          {% endfor %}
                      </select>
                      

                      Найдёте, где кавычки перепутали?

                        Arrow
                        • 14. Januar 2019 15:18
                        • (bearbeitet)

                        Нашел ошибку. Было:

                        option value=""{{ temperature.data.value }}>{{ temperature.data.label }}

                        Нужно:

                        option value="{{ temperature.data.value }}">{{ temperature.data.label }}

                          Arrow
                          • 14. Januar 2019 15:20

                          Оказывается все было правильно кроме кавычки :) Буду чаше заглядывать в Инспектор.

                          Огромное спасибо! :)

                            Evgenii Legotckoi
                            • 14. Januar 2019 15:22

                            Я с консолью браузера при разработке на django вообще не расстаюсь. Иначе можно голову долго ломать.

                              Arrow
                              • 14. Januar 2019 15:25

                              Теперь так и буду делать :)

                                Arrow
                                • 14. Januar 2019 15:53
                                • (bearbeitet)

                                Если кому-то понадобится есть еще один вариант, который я думаю более верный:

                                models.py

                                from django.db import models
                                
                                class TempUnit(models.Model):
                                    name = models.CharField(max_length=2)
                                    unit = models.CharField(max_length=8)
                                
                                    def __str__(self):
                                        return self.name
                                
                                
                                class City(models.Model):
                                    name = models.CharField(max_length=25)
                                    temperature_unit = models.ForeignKey(TempUnit, on_delete=models.CASCADE)
                                
                                    def __str__(self):
                                        return self.name
                                
                                    class Meta:
                                        verbose_name_plural = 'cities'
                                
                                

                                views.py

                                def index(request):
                                    url = 'http://api.site.org/data/2.5/?q={}&units={}&id=1111&appid=111111111111'
                                
                                    if request.method == 'POST':
                                        form = CityForm(request.POST)
                                        form.save()
                                
                                    cities = City.objects.all()
                                    weather_data = []
                                
                                    for city in cities:
                                        r = requests.get(url.format(city, city.temperature_unit)).json()
                                
                                        city_weather = {
                                            'city': city.name,
                                            'temperature_unit': city.temperature_unit,
                                            'temperature': r['main']['temp'],
                                            'description': r['weather'][0]['description'],
                                            'icon': r['weather'][0]['icon'],
                                        }
                                
                                        weather_data.append(city_weather)
                                
                                    context = {'weather_data': weather_data, 'form': form}
                                
                                    return render(request, 'data/data.html', context)
                                
                                

                                Тоесть просто создал новую модель и все скинул туда.

                                  Evgenii Legotckoi
                                  • 14. Januar 2019 16:00

                                  Если вы создадите вручную несколько TempUnit, а потом только установка этих TempUnit через выпадающий список, то да, будет даже лучше.

                                  Однако переходите к CBV (Class Based View) вместо обычных вьюшек. Так лучше будет, в будущем оцените.

                                    Arrow
                                    • 14. Januar 2019 16:46

                                    Спасибо.

                                      Kommentare

                                      Nur autorisierte Benutzer können Kommentare posten.
                                      Bitte Anmelden oder Registrieren
                                      Letzte Kommentare
                                      A
                                      ALO1ZE19. Oktober 2024 08:19
                                      Fb3-Dateileser auf Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
                                      ИМ
                                      Игорь Максимов5. Oktober 2024 07:51
                                      Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
                                      d
                                      dblas55. Juli 2024 11:02
                                      QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
                                      k
                                      kmssr8. Februar 2024 18:43
                                      Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                                      Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                                      Jetzt im Forum diskutieren
                                      J
                                      JacobFib17. Oktober 2024 03:27
                                      добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
                                      JW
                                      Jhon Wick1. Oktober 2024 15:52
                                      Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
                                      КГ
                                      Кирилл Гусарев27. September 2024 09:09
                                      Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
                                      F
                                      Fynjy22. Juli 2024 04:15
                                      при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

                                      Folgen Sie uns in sozialen Netzwerken