2016-02-02 1 views
3

Я использую форму Bannerform для создания нового объекта Banner через add_banner просмотров (и шаблона). Я использую класс Options, чтобы определить, какие affiliation объектов, разрешающих в форме Bannerform (affiliation).Пропустить выбор из представлений в форму

Я пытаюсь передать выбор из взглядов на форму, но это дает мне ValueError: слишком много значений для распаковки (ожидается 2)

Мой код работает, когда new_affiliation был ForeignKey, но теперь мне нужно больше значения , Я думаю, что я должен определить «выбор» в views или у меня возникнут проблемы при первом переносе (он, как представляется, вызывает таблицы базы данных из models.py, но не из views.py, поэтому, если я положил Options.objects.get(id=1) на , он дал ошибку, поскольку таблицы еще не существуют).

Мои form.py:

from django import forms 
from core.models import Options, Banner, Affiliation #somethings other 

class BannerForm(forms.ModelForm): 
    name = forms.CharField(max_length=32) 
    affiliation = forms.ChoiceField('choices') 
    #affiliation = forms.ModelChoiceField('choices') #same error 
    class Meta: 
     model = Banner 
     exclude = (#some fields) 

Мои models.py:

from django.db import models 
from django.contrib.auth.models import User 
from django import forms 

class Options(models.Model): 
    new_affiliation = models.ManyToManyField('Affiliation') 
    #new_affiliation = models.ForeignKey('Affiliation') #this worked (with some changes in views) 

class Affiliation(models.Model): 
    name = models.CharField(max_length=32, unique=True) 

class Banner(models.Model): 
    name = models.CharField(max_length=32, unique=True) 
    affiliation = models.ForeignKey(Affiliation) 

views.py Мои:

def add_banner(request): 
    if request.method == 'POST': 
     #some code here 
    else: 
     options = Options.objects.get(id=1) 
     print(options.new_affiliation.all()) #controll 
     choices = options.new_affiliation.all() 
     print(choices) #controll 
     form = BannerForm(choices, initial={    
      #some code regarding other fields 
      })  
    return render(request, 'core/add_banner.html', {'form': form}) 

Мои add_banner.html:

<form role="form" id="banner_form" enctype="multipart/form-data "method="post" action="../add_banner/"> 

    {% csrf_token %} 
    {% for hidden in form.hidden_fields %} 
    {{ hidden }} 
    {% endfor %} 

    {% for field in form.visible_fields %} 
    {{ field.errors }} 
    {{ field.label }} 
    {{ field }}  
    {{ field.help_text }} 
    <br /> 
    {% endfor %} 

Любая помощь будет оценена.

Обновлено. Я изменил только views.py:

def add_banner(request): 
    if request.method == 'POST': 
     #some code here 
    else: 
     options = Options.objects.get(id=1) 
     print(options.new_affiliation.all()) #controll 
     choices = tuple(options.new_affiliation.all()) 
     print(choices) #controll 
     form = BannerForm(choices, initial={    
      #some code regarding other fields 
      })  
    return render(request, 'core/add_banner.html', {'form': form}) 

Но все же дайте ошибку.

Update 2. Если я прохожу выбор непосредственно из form.py это работает: Мои views.py:

def add_banner(request): 
    if request.method == 'POST': 
     #some code here 
    else: 
     form = BannerForm(request.POST or None, initial={ 
      #some code regarding other fields 
      }) 
    return render(request, 'core/add_banner.html', {'form': form}) 

forms.py Мои:

class BannerForm(forms.ModelForm): 
    options = Options.objects.get(id=1) 
    choices = options.new_affiliation.all() 
    name = forms.CharField(max_length=32) 
    affiliation = forms.ModelChoiceField(choices) 

Unluckly это дает проблемы на первой миграции (см выше).

Я пытаюсь передать выбор с помощью какой-либо метод инициализации ...

forms.py Мои:

class BannerForm(forms.ModelForm): 
    name = forms.CharField(max_length=32) 
    affiliation = forms.ModelChoiceField(choices) 

    def __init__(self, *args, **kwargs): 
     options = Options.objects.get(id=1) 
     choices = options.new_affiliation.all() 
     #choices = kwargs.pop('choices') 
     super(RegentForm, self).__init__(*args, **kwargs) 
     self.fields['affiliation'] = choices 

, но говорят, что выбор не однозначен

ответ

2

Из того, что я могу видеть здесь , похоже, что вы получаете сообщение об ошибке «слишком много значений для распаковки», потому что вы не отправляете «выбор» в качестве правильного типа. ChoiceField принимает выбор только как кортеж, как показано в the documentation для моделей. Если вы хотите определить выбор на основе QuerySet, вам придется преобразовать его в кортеж, который можно интерпретировать как действительный «выбор». Например, в одном из моих проектов мне нужно было подготовить набор лет как кортеж, чтобы я мог разрешить пользователям выбирать из списка заранее определенных лет.Я указал следующую функцию, чтобы сделать это:

def years(): 
    response = [] 
    now = datetime.utcnow() 
    for i in range(1900, now.year + 1): 
     response.append([i, str(i)]) 
    return tuple(response) 

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

В вашей конкретной ситуации, вы могли бы рассмотреть возможность сделать что-то вроде этого:

choices = tuple(options.new_affiliation.all().values()) 

Я не проверял этот код, и я, честно говоря я не совсем знакомы с проектом и может быть ошибочно в какой-то части этого ответ. В результате это может потребовать дополнительной настройки, но попробуйте. Основываясь на вашей ошибке, это определенно там, где программа ломается в настоящее время. Обновите здесь, если вы достигнете какого-либо прогресса.

+0

Это приведет к ошибке: AttributeError: 'кортеж' объект не имеет атрибута 'получить'. Ошибка при рендеринге шаблона. Ошибка находится в строке {{hidden}}. Может может помочь узнать, что мой выбор = options.new_affiliation.all() Печатаемый: [<Принадлежность: Красный>, <Принадлежности: Black>], Вашего выбора = кортеж (options.new_affiliation.all () .values ​​()) напечатан: ({'id': 1, 'name': 'Red'}, {'id': 2, 'name': 'Black'}). Здесь последняя строка ошибки http://dpaste.com/30AY564 – fabio

+0

@fabio Возможно, вам захочется отправить ее в другом формате, чтобы ее можно было читать без каких-либо ключевых слов. Вы можете сделать что-то вроде этого: choice = tuple (options.new_affiliation.all(). Get ('name'). Values ​​()) Это будет извлекать только имена типа ((«Черный»), («Красный») - Основываясь на отрывках здесь, все еще немного сложно определить, что происходит, поэтому попробуйте немного поработать с результатами и отправить обратно с дополнительной информацией. Я могу попробовать некоторые из этого кода в моей собственной среде IDE, чтобы узнать, дает ли он желаемый результат. –

+0

Я не знаю, что вам дает информация ... Я редактировал свой первый пост, добавляя что-то. Может быть, проблема в том, что он принимает такие варианты, как поле, и он пытается отобразить его на шаблоне ... может быть, нам нужно пройти выбор в каком-то методе __init__? – fabio

1

Done!

Мои form.py:

class BannerForm(forms.ModelForm): 
    name = forms.CharField(max_length=32, label='Nome') 

    def __init__(self, *args, **kwargs): 
     options = Options.objects.get(id=1) 
     choices = options.new_affiliation.all() 
     super(BannerForm, self).__init__(*args, **kwargs) 
     self.fields['affiliation'] = forms.ModelChoiceField(choices) 
     self.fields['affiliation'].initial = choices 

    class Meta: 
     model = Banner 

views.py Мои:

def add_banner(request): 
    if request.method == 'POST': 
     #some code here 
    else: 
     form = BannerForm(request.POST or None, initial={ 
     #some code here 
      }) 
    return render(request, 'core/add_banner.html', {'form': form}) 

Спасибо

+0

Прохладный, вы получили его. Да, метод init был хорошим дополнением. Вам нужно было обработать информацию еще до рендеринга. Выглядит неплохо –

 Смежные вопросы

  • Нет связанных вопросов^_^