سؤال

So I have 2 models which relate via Many-to-many relationship. As I need an extra file I am using extra model CategoryByDay

basically what I want in my application, is create a habit or everyday list that will log various things I have to do today. So I want to connect each new day with each category and record it's status (if it's done 1, if not 0). I am using CharField, because later I want to log other things as books read etc, it's not relevant here

models.py

from django.db import models

class Day(models.Model):
    name = models.CharField(max_length=8)
    date = models.DateField()

    def __unicode__(self):
        return self.name

class Category(models.Model):
    name = models.CharField(max_length=100)
    categoryBD = models.ManyToManyField(Day, through='CategoryByDay')

    def __unicode__(self):
        return self.name

class CategoryByDay(models.Model):
    day = models.ForeignKey(Day)
    category = models.ForeignKey(Category)
    status = models.CharField(max_length=64)

In my html I want to show a list of Categories and a form near it, where one will only post a status and day as well as category will be filled automatically. Now I have no idea how to do it. This is what I got so far, reading on some forum that you can pass extra data from view (This is not working, and form demands that I fill day and category form)

views.py

def today(request):
    if request.method == 'POST':
#... POST validation here, not relevant
    else:
        day = datetime.date.today().strftime("%d/%m/%y")
        categories_list = Category.objects.all()
        category_form_list = []
# I am doing this strange list, because later in template I had problem
# accessing list through iteration like forloop.counter. 
# I will access it via for x,y in pair
        for category in categories_list:
            data = {'day': day,
            'category': category.name,}
            form = CategoryByDayForm(data)
            #So I tried adding data to form, it didn't work and can be ignored
            part = [category, form]
            category_form_list.append(part)
        context = { 't': t,
        'category_form_list': category_form_list,}
        return render(request, 'today/today.html', context)

This is my form, should have added it earlier I guess.

forms py

class CategoryByDayForm(forms.ModelForm):
    status = forms.CharField(max_length=64, initial="0")
    day = forms.ModelMultipleChoiceField(queryset=Day.objects.all())
    category = forms.ModelMultipleChoiceField(queryset=Category.objects.all())
    class Meta:
        model = CategoryByDay

Now, in forms I am unsure what form type should I use for day and category. Maybe I should somehow omit it?

Finally template:

today html

#...
    <ul>
        {% for category, form in category_form_list %}
            <li>                   
                {{ category.name }}
                <form action="" method="post">
                    {% csrf_token %}
                    {{ form.non_field_errors}}
                    <div class="status">
                        {{ form.status.errors}}
                        {{ form.status }}
                        <input type="submit" value="Submit" />
                    </div>
                </form>
            </li>
        {% endfor %}
    </ul>
#...

This works, by only showing one form status but when I click submit and debug it in my way, I have errors that I haven't filled day and category forms.

Can someone show me how to proceed?

هل كانت مفيدة؟

المحلول

I managed to make it work.

For anyone in the future by accident googling and getting on this page here is what I did.

1.Changed the form of CategoryByDayForm so it accepts only status and excludes day and category

forms.py

from django import forms
from today.models import CategoryByDay, Category, Day

class CategoryByDayForm(forms.ModelForm):
    status = forms.CharField(max_length=64, initial="0")
    class Meta:
        model = CategoryByDay
        exclude = ['day', 'category']
  1. In the template, added hidden form input sending current category iteration:

today.html

#...
{% for category, form in category_form_list %}
                <li>                   
                    {{ category.name }}
                    <form action="" method="post">
                        {% csrf_token %}
                        {{ form.non_field_errors}}
                        <input type="hidden" value="{{ category.name }}" name="category">
                        <div class="status">
                            {{ form.status }}
                            <input type="submit" value="Submit" />
                        </div>
                    </form>
                </li>
            {% endfor %}
# ...

Finally, in views, I manipulated the form I got, so I added missing elements (from form I have status, I still need to set day and category)

views.py

def today(request):
    t = datetime.date.today().strftime("%d/%m/%y")
    day = Day.objects.filter(name=t)
    if request.method == 'POST':
            form = CategoryByDayForm(request.POST)
        if form.is_valid():
            category_status = form.save(commit=False)
            category_status.day = day[0]
            category_name = request.POST['category']
            category_status.category = Category.objects.filter(name=category_name)[0]
            category_status.save()
            form.save_m2m()

...

Hope that it can help someone in the future.

نصائح أخرى

Another solution views.py:

class ViewIndex(TemplateResponseMixin, View):
    template_name = 'frontend/view_index.html'

    def dispatch(self, request, *args, **kwargs):
       FS = modelformset_factory(CategoryByDay, extra=1)
       queryset = CategoryByDay.objects.filter(day__date=datetime.date.today())

       if request.method == 'POST':
           formset = FS(request.POST, request.FILES)

           if formset.is_valid():
               formset.save()
               formset = FS(queryset=queryset)

       else:
           formset = FS(queryset=queryset)


       return self.render_to_response({'formset':formset})

frontend/view_index.html:

{% extends 'base.html' %}
{% block content_main %}
<form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ formset.management_form }}
    {% for form in formset %}
       {{ form }}
       <hr/>
    {% endfor %}

    <input type="submit">
</form>
{% endblock %}

and urls.py

urlpatterns = patterns('',
   url(r'^$', ViewIndex.as_view(), name='view_index'),
)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top