Arrow
ArrowҚаң. 14, 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
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

18
Evgenii Legotckoi
  • Қаң. 14, 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, 2019, 11:52 Т.Ж.

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

      Arrow
      • Қаң. 14, 2019, 11:53 Т.Ж.
      • (өңделген)

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

        Arrow
        • Қаң. 14, 2019, 1:59 Т.Қ.

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

          Evgenii Legotckoi
          • Қаң. 14, 2019, 2: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, 2019, 2:55 Т.Қ.

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

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

            а не:

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

              Evgenii Legotckoi
              • Қаң. 14, 2019, 3:03 Т.Қ.
              • (өңделген)

              А как выглядит отрендеренная форма? В смысле 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, 2019, 3:08 Т.Қ.
                • (өңделген)

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

                <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, 2019, 3:12 Т.Қ.

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

                  Вот отсюда

                    Arrow
                    • Қаң. 14, 2019, 3:16 Т.Қ.

                    Все ясно:

                      Evgenii Legotckoi
                      • Қаң. 14, 2019, 3:18 Т.Қ.
                      • Жауап шешім ретінде белгіленді.

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

                      вот ваш код

                      <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, 2019, 3:18 Т.Қ.
                        • (өңделген)

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

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

                        Нужно:

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

                          Arrow
                          • Қаң. 14, 2019, 3:20 Т.Қ.

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

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

                            Evgenii Legotckoi
                            • Қаң. 14, 2019, 3:22 Т.Қ.

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

                              Arrow
                              • Қаң. 14, 2019, 3:25 Т.Қ.

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

                                Arrow
                                • Қаң. 14, 2019, 3:53 Т.Қ.
                                • (өңделген)

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

                                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, 2019, 4 Т.Қ.

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

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

                                    Arrow
                                    • Қаң. 14, 2019, 4:46 Т.Қ.

                                    Спасибо.

                                      Пікірлер

                                      Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
                                      Кіріңіз немесе Тіркеліңіз
                                      Г

                                      C++ - Тест 001. Первая программа и типы данных

                                      • Нәтиже:66ұпай,
                                      • Бағалау ұпайлары-1
                                      t

                                      C++ - Тест 001. Первая программа и типы данных

                                      • Нәтиже:33ұпай,
                                      • Бағалау ұпайлары-10
                                      t

                                      Qt - Тест 001. Сигналы и слоты

                                      • Нәтиже:52ұпай,
                                      • Бағалау ұпайлары-4
                                      Соңғы пікірлер
                                      G
                                      GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
                                      Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
                                      d
                                      dblas5Шілде 5, 2024, 11:02 Т.Ж.
                                      QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
                                      k
                                      kmssrАқп. 8, 2024, 6:43 Т.Қ.
                                      Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                                      АК
                                      Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
                                      Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                                      Енді форумда талқылаңыз
                                      Evgenii Legotckoi
                                      Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
                                      добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
                                      F
                                      FynjyШілде 22, 2024, 4:15 Т.Ж.
                                      при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
                                      BlinCT
                                      BlinCTМаусым 25, 2024, 1 Т.Ж.
                                      Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
                                      BlinCT
                                      BlinCTМамыр 5, 2024, 5:46 Т.Ж.
                                      Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
                                      Evgenii Legotckoi
                                      Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
                                      Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

                                      Бізді әлеуметтік желілерде бақылаңыз