1

I am unable to save MEDIA_CHOICES in the database I don't know why ! The market parameter is saved. But I have problem with sector parameter that has MEDIA_CHOICES as input, The user choose the inputs but after save it is empty in the database. I cant find where is the problem. Image here the user need to check sector than save the value,when i access to the saved page i find the sector field empty not saved

Admin page image here

 class Media(models.Model):
   Media_Choices= models.CharField(max_length=30, choices=MEDIA_CHOICES)

 class Parameters(models.Model):

     user = models.ForeignKey(User)
     title = models.CharField('title', max_length=100, default='', blank=True, help_text='Use an indicative name, related to the chosen parameters')
     type = models.CharField('forecast type', choices=FORECAST_TYPES, max_length=20, default="backtest")

#input characteristics
     price_1_min    = models.FloatField('1. Price, min', default=0.1, validators=[MinValueValidator(0.1), MaxValueValidator(20000)])
     price_1_max    = models.FloatField('1. Price, max', default=20000, validators=[MinValueValidator(0.1), MaxValueValidator(20000)])
     stocks_num_2_min = models.IntegerField('2. Number of selected stock, min', default=3, validators=[MinValueValidator(0), MaxValueValidator(100)])
     stocks_num_2_max = models.IntegerField('2. Number of selected stock, max', default=7, validators=[MinValueValidator(1),])
     limit_3    = models.FloatField('3. Last price to upper straight, %', default=20, validators=[MinValueValidator(-200),])
     learning_days_4_min    = models.IntegerField('4. Number of Learning days, min', default=1, validators=[MinValueValidator(1),MaxValueValidator(30)])
     learning_days_4_max    = models.IntegerField('4. Number of Learning days, max', default=10, validators=[MinValueValidator(1),MaxValueValidator(30)])
     evaluation_days_5 = models.IntegerField('5. Number of Evaluation days', default=10, validators=[MinValueValidator(1),MaxValueValidator(10)])
     delay_days_6 = models.IntegerField('6. Number of “no quarterly reports” days (N)', default=10, validators=[MinValueValidator(0),MaxValueValidator(20)])
     minimum_gain_7 = models.FloatField('7. Minimum gains for winners', default=0, validators=[MinValueValidator(0),MaxValueValidator(100)])
     minimum_loss_8 = models.FloatField('8. Minimum losses for losers', default=0, validators=[MinValueValidator(-100),MaxValueValidator(0)])
     total_gain_min_9 = models.FloatField('9. Minimum total gain', default=0, validators=[MinValueValidator(0),MaxValueValidator(100)])
     winning_stock_percentage_min_10    = models.FloatField('10. Minimum percentage of winning stocks', default=60, validators=[MinValueValidator(0),MaxValueValidator(100)])

     market = models.CharField('Market', max_length=30, null=True)
     sector= models.ManyToManyField(Media) 

forms.py :

class BacktestForm(forms.ModelForm):

period_start = forms.DateField(initial=datetime.datetime.today().date() - datetime.timedelta(days=365+16), widget=forms.widgets.DateInput(format="%Y/%m/%d"), input_formats=["%Y/%m/%d"])
period_end  = forms.DateField(initial=datetime.datetime.today().date() - datetime.timedelta(days=16), widget=forms.widgets.DateInput(format="%Y/%m/%d"), input_formats=["%Y/%m/%d"])

    market = forms.MultipleChoiceField(label='Market', choices=Parameters.MARKET, widget=forms.CheckboxSelectMultiple)




class Meta:
    model = Parameters
    exclude = [
        'user',
        'type',
        'created_at', 
        'updated_at', 
        ]
    widgets={
        'title': forms.TextInput(attrs={'placeholder':'for ex. highLimitLowPrice'}),
                    'sector': forms.CheckboxSelectMultiple(),
        }

views.py

def backtest(request, pk=None):

    if pk is not None:
        param = get_object_or_404(Parameters, pk=pk, user=request.user)
        form = BacktestForm(request.POST or None, instance=param)
    else:
        form = BacktestForm(request.POST or None)

    if request.method == 'POST':
        if form.is_valid():
            if 'save' in request.POST:

                obj = form.save(commit= False)               
                obj.user = request.user
                obj.type = "backtest"

                obj.save()
                messages.info(request, 'Saved!')
                return redirect(obj.get_backtest_url())

            else:
                messages.info(request, 'Please check entered data')
                data = {
                       'active_page': 'backtest',
                        'form': form,
                 }

The error is in HTML (form.sector not iterable):

        <td>{{form.sector.label}}</td>



        <td> {{form.sector}} </td>



  </tr>
faro
  • 89
  • 7
  • In your model, you have defined sector as a characterfield. But in forms you are using MultipleChoiceField and trying to save all the selected choices to db. It doesn't work that way. Try using a ManyToManyField for sector. And create a model for your MEDIA_CHOICES. – Sandeep Balagopal Jun 01 '17 at 09:07
  • Do you mean ? class Media(models.Model): Media_Choices= models.CharField(max_length=30) Class Parameters (models.Model): sector= models.ManyToManyField(Media) How will be forms .py to have widget as checkbox ? And what about The access in html i can use {{form.sector}} ?? Sector must be as checkbox ! please I am a beginner if you can help with this, i will be very thankful – faro Jun 01 '17 at 09:21
  • Exactly. If you register in admin, you can see the default widget. It is not checkboxes. To bring the checkbox widget, you can define the widget in meta class like this https://stackoverflow.com/a/22250192/2282638. And in your forms you only have to do {{ form.sector }} (mind the space between braces and text. It is a coding standard). – Sandeep Balagopal Jun 01 '17 at 09:35
  • Sandeep the code don't work with. class BacktestForm(forms.ModelForm): market = forms.MultipleChoiceField(label='Market', choices=Parameters.MARKET, widget=forms.CheckboxSelectMultiple) sector = forms.MultipleChoiceField(label='sector', ?????, widget=forms.CheckboxSelectMultiple) class Meta: model = Parameters – faro Jun 01 '17 at 10:14
  • what should i write here ???? how to make the relation in form.py to get checkbox from media – faro Jun 01 '17 at 10:14
  • you don't have to do anything in your form at all. Also remove the field from form. And define the widget in form meta like in the link above. – Sandeep Balagopal Jun 01 '17 at 10:17
  • where should i put the choices for sector ? class Media(models.Model): Media_Choices= models.CharField(max_length=30, choices=MEDIA_CHOICES) here ??? If i put here i have an error with html {{form.sector}} .. the error is : it is not iterable – faro Jun 01 '17 at 10:53
  • can you update your answer with new code ? Model, View, form, template – Sandeep Balagopal Jun 01 '17 at 10:57
  • Done... I updated everything .. waiting for your help – faro Jun 01 '17 at 11:13
  • You don't need the choices here Media_Choices= models.CharField(max_length=30, choices=MEDIA_CHOICES) just do without choices. The choices will be each object of Media – Sandeep Balagopal Jun 01 '17 at 11:31
  • I don't understand where should i put the choices. What do you mean by object ? I am sorry i am really confused i am new with Django. – faro Jun 01 '17 at 11:38
  • Okay. remove the choices first Media_Choices= models.CharField(max_length=30) then register the model Media in admin and add couple of objects. Then in your form, when you do {{ form.sector }}, you will have all the choices as checkbox. Basically the choices you need are now are the objects of the model Media. – Sandeep Balagopal Jun 01 '17 at 12:02
  • on the admin page media are saved as object. And again nothing is saved. I am really confused about this. I added the image. – faro Jun 01 '17 at 12:55
  • okay try form.save_m2m() it is needed to save many to many fields. – Sandeep Balagopal Jun 01 '17 at 13:05

1 Answers1

1

If you have sector as Charfield in models and in forms you have CheckboxSelectMultiple widget then you can iterate sector field as below in html

{{ form.sector.label }}
{% for f in form.sector %}
                        <li>
                            <div class="checkbox"><label>
                                <input id="{{ f.id_for_label }}" type="checkbox" name="{{ f.name }}"
                                       value="{{ f.choice_value }}" {% if f.choice_value in field.value %}checked{% endif %}><span>{{ f.choice_label }}</span></label>
                            </div>
                        </li>
                    {% endfor %}

If you want to show checkbox in admin then pass BacktestForm as admin form.

Neeraj Kumar
  • 3,851
  • 2
  • 19
  • 41