Arrow
ArrowJan. 14, 2019, 11:42 a.m.

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

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 в отдельную таблицу в базе данных и вытягивать от туда или еще как-то?

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

18
Evgenii Legotckoi
  • Jan. 14, 2019, 11:46 a.m.

Добрый день!

Так у вас в модели поде 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
    • Jan. 14, 2019, 11:52 a.m.

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

      Arrow
      • Jan. 14, 2019, 11:53 a.m.
      • (edited)

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

        Arrow
        • Jan. 14, 2019, 1:59 p.m.

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

          Evgenii Legotckoi
          • Jan. 14, 2019, 2:54 p.m.

          я так понимаю, у вас там в шаблоне пропущены 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
            • Jan. 14, 2019, 2:55 p.m.

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

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

            а не:

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

              Evgenii Legotckoi
              • Jan. 14, 2019, 3:03 p.m.
              • (edited)

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

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

                <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
                  • Jan. 14, 2019, 3:12 p.m.

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

                  Вот отсюда

                    Arrow
                    • Jan. 14, 2019, 3:16 p.m.

                    Все ясно:

                      Evgenii Legotckoi
                      • Jan. 14, 2019, 3:18 p.m.
                      • The answer was marked as a solution.

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

                      вот ваш код

                      <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
                        • Jan. 14, 2019, 3:18 p.m.
                        • (edited)

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

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

                        Нужно:

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

                          Arrow
                          • Jan. 14, 2019, 3:20 p.m.

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

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

                            Evgenii Legotckoi
                            • Jan. 14, 2019, 3:22 p.m.

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

                              Arrow
                              • Jan. 14, 2019, 3:25 p.m.

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

                                Arrow
                                • Jan. 14, 2019, 3:53 p.m.
                                • (edited)

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

                                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
                                  • Jan. 14, 2019, 4 p.m.

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

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

                                    Arrow
                                    • Jan. 14, 2019, 4:46 p.m.

                                    Спасибо.

                                      Comments

                                      Only authorized users can post comments.
                                      Please, Log in or Sign up
                                      d
                                      • dsfs
                                      • April 26, 2024, 2:56 p.m.

                                      C ++ - Test 004. Pointers, Arrays and Loops

                                      • Result:80points,
                                      • Rating points4
                                      d
                                      • dsfs
                                      • April 26, 2024, 2:45 p.m.

                                      C++ - Test 002. Constants

                                      • Result:50points,
                                      • Rating points-4
                                      d
                                      • dsfs
                                      • April 26, 2024, 2:35 p.m.

                                      C++ - Test 001. The first program and data types

                                      • Result:73points,
                                      • Rating points1
                                      Last comments
                                      k
                                      kmssrFeb. 9, 2024, 5:43 a.m.
                                      Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
                                      Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
                                      EVA
                                      EVADec. 25, 2023, 9:30 p.m.
                                      Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
                                      J
                                      JonnyJoDec. 25, 2023, 7:38 p.m.
                                      Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
                                      G
                                      GvozdikDec. 19, 2023, 8:01 a.m.
                                      Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
                                      Now discuss on the forum
                                      G
                                      GarApril 22, 2024, 3:46 p.m.
                                      Clipboard Как скопировать окно целиком в clipb?
                                      DA
                                      Dr Gangil AcademicsApril 20, 2024, 5:45 p.m.
                                      Unlock Your Aesthetic Potential: Explore MSC in Facial Aesthetics and Cosmetology in India Embark on a transformative journey with an msc in facial aesthetics and cosmetology in india . Delve into the intricate world of beauty and rejuvenation, guided by expert faculty and …
                                      a
                                      a_vlasovApril 14, 2024, 4:41 p.m.
                                      Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
                                      Павел Дорофеев
                                      Павел ДорофеевApril 14, 2024, 12:35 p.m.
                                      QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
                                      f
                                      fastrexApril 4, 2024, 2:47 p.m.
                                      Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

                                      Follow us in social networks