0

我有三个模型User(django.contrib.auth)ScreeningUser_Screening. 这User_Screening是一个带有额外字段的 m2m 表status

#models.py
from django.db import models
from django.contrib.auth.models import User

class Screening(models.Model):
    title = models.CharField(max_length=255)
    start = models.DateTimeField()
    user_relation = models.ManyToManyField(User, blank=True,
        through='User_Status')

class User_Status(models.Model):
    ATTENDING = 'c'
    NOT_ATTENDING = 'n'
    PROJECTION = 'p'
    STATUS_CHOICES = (
        (ATTENDING, 'attending'),
        (NOT_ATTENDING, 'not attending'),
        (PROJECTING, 'projecting'),
    )
    screening = models.ForeignKey(Screening)
    user = models.ForeignKey(User)
    status = models.CharField(max_length=1, choices=STATUS_CHOICES)

现在我想制作一个视图,显示所有即将上映的电影。到目前为止,很容易:

#views.py
@login_required()
def index(request):
    current_screenings = Screening.objects.filter(start__gte=timezone.now())
    context = {'current_screenings': current_screenings}
    return render(request, 'schedule/index.html', context)

在这个视图中,登录的用户应该能够更新他们的status(从User_Screening表中)。也可能是用户还没有此筛选的记录,因此应该创建一个。

我不明白,我如何为每个筛选存档一个表单下拉字段,用户可以在其中选择他的状态。(?如果尚未设置状态attendingnot attendingprojection

据我了解,我需要多种表格,这些表格都知道它们与哪些筛选有关。

此外,Formsets似乎不起作用,因为我不能总是用初始数据填写表格,因为某些或所有筛选可能会丢失记录。此外,我不知道哪种形式属于哪种筛选对象。

更新: 我想在 HTML 中得到的结果是这样的:

<form>
  <h1>Current Screening 1</h1>
    <select onchange="submit()" name="screening_user" id="s1">
      <option value="att">Attending</option>
      <option value="not_att">Not Attending</option>
      <option selected="selected" value="pro">Projection</option>
    </select>
  <h1>Current Screening 2</h1>
    <select onchange="submit()" name="screening_user" id="s2">
      <!-- The 'Please Select' option is only visible, if the user does not
        have a relation in 'User_Screening' for this screening -->
      <option selected="selected" value="none">Please Select</option>
      <option value="att">Attending</option>
      <option value="not_att">Not Attending</option>
      <option value="pro">Projection</option>
    </select>
  <!-- More Screenings -->
  <h1>Current Screening n</h1>
    <!-- select for screening n -->
</form>

因此,需要根据登录用户从具有预加载数据的相同表单中更改表单数量。

4

3 回答 3

0

一方面,您可以通过 ajax 请求发送表单数据。在该请求中,您只需发送一个表格并处理数据。您不需要任何表单集。根据您的用例,这可能会给您的服务器增加不必要的流量。

STATUS_CHOICE如果数据库中没有筛选用户组合的条目,另一种解决方案是添加另一个类似“未选择”的表单作为默认值。在您的视图的 POST 处理程序中,您可以检查表单数据是否设置为此值。在这种情况下,您只需忽略该表单。如果它是另一个值,则相应地设置 db 条目。

于 2014-02-18T21:48:09.203 回答
0

如果筛选与用户有 m2m 关系,则参加的用户可以在该列表中。如果不参加……好吧,比他们不参加!那有意义吗?

class Screening(models.Model):
    title = models.CharField(max_length=255)
    date = models.DateTimeField()
    attending = models.ManyToManyField(User)

形式:

class ScreeningForm(ModelForm):
    class Meta:
        model = Screening
        fieds = ['attending', ]

表单集:

ScreeningFormSet = modelformset_factory(Screenig, max_num=1)
formset = ScreeningFormSet(Screening=Screening.objects.filter(date__gte=now))
于 2014-02-18T14:25:01.610 回答
0

在feenode上#django的帮助下,我解决了我的问题。最后,我坚持使用表单集。

考虑到我的问题中的 models.py,我不得不User_Status稍微改变一下,NO_STATUS如果筛选尚不存在关系,则为 Select-Widget 添加一个选项。请注意,这NO_STATUS不是model.CharField!

#models.py
class User_Status(models.Model):
NO_STATUS = '?'
PROJECTIONIST = 'p'
ATTENDING = 'c'
NOT_ATTENDING = 'n'
STATUS_CHOICES = [
    (ATTENDING, 'Anwesend'),
    (NOT_ATTENDING, 'Nicht anwesend'),
    (PROJECTIONIST, 'Vorführer'),
]
STATUS_CHOICES_AND_EMPTY = [(NO_STATUS, 'Please choose')] + STATUS_CHOICES
screening = models.ForeignKey(Screening)
user = models.ForeignKey(User)
status = models.CharField(max_length=1, choices=STATUS_CHOICES,
    default=ATTENDING)

接下来,表格。修改后__init__的注意,“请选择”只是一个有效的选择,如果它被设置为初始值status。否则,选择只是不显示。

#forms.py
class ScreeningUserStatusForm(forms.Form):
    screening_id = forms.IntegerField(min_value=1)
    status = forms.ChoiceField(choices=User_Status.STATUS_CHOICES_AND_EMPTY, 
        widget=forms.Select(attrs={"onChange":'submit()'}))

    def __init__(self, *args, **kwargs):
        super(ScreeningUserStatusForm, self).__init__(*args, **kwargs)
        if self['status'].value() != User_Status.NO_STATUS:
            #Once, a status is selected, the status should not be unset.
            self.fields['status'].choices=User_Status.STATUS_CHOICES

最后是视图,它使用一个表单集将所有当前放映的内容放入其中。

def update_user_status(screening, user, status):
    #Get old status, if already exists.
    new_status = User_Status.objects.get_or_create(screening=screening,
        user=user)

    # Add to selected status
    new_status.status = status 
    new_status.save()

@login_required()
def index(request):
    """
    displays all upcoming screenings
    """

    # Get current screenings
    current_screening_set = Screening.objects.filter(start__gte=timezone.now() - datetime.timedelta(hours=24)).order_by('start')
    current_screening_list = current_screening_set.values('id')

    ScreeningFormSet = formset_factory(ScreeningUserStatusForm, extra=0)

    if request.method == 'POST':
        #Get a formset bound to data from POST
        formset = ScreeningFormSet(request.POST, request.FILES)
        if formset.is_valid():
            for form in formset.cleaned_data:
                s = get_object_or_404(Screening, pk=form['screening_id'])
                if form['status'] != User_Status.NO_STATUS:
                    update_user_status(screening=s, user=request.user, status=form['status'])
    else:
        #create a fresh formset
        for form_data in current_screening_list:
            screening = Screening.objects.get(pk=form_data['id'])
            status = User_Status.objects.filter(user=request.user, screening=screening)
            if status.count() != 1:
                form_data['status'] = u'?'
            else:
                form_data['status'] = status.first().status
            form_data['screening_id'] = form_data['id']

        formset = ScreeningFormSet(initial=current_screening_list)

    forms_and_curr_screenings = zip(formset.forms, current_screening_set)

    context = {'formset' : formset, 'current_screenings' : forms_and_curr_screenings}
    return render(request, 'schedule/index.html', context)

与,formset.forms一起压缩current_screening_set,为每个 from 提供额外的数据。formset被额外提供给management_form.

模板可能看起来像这样

<!-- index.html -->
{% if current_screenings %}
    <form method="post">
    {{ formset.management_form }}
    {% csrf_token %}
    <table>
      <thead>
        <tr>
          <th>Screening</th>
          <th>My Status</th>
        </tr>
      </thead>
      <tbody>
      {% for form, screening in current_screenings %}
        <tr>
          <td>{{ screening }}</a></td>
          <td>
            {{ form.screening_id.as_hidden }}
            {{ form.status }}
          </td>
        </tr>
      {% endfor %}
      </tbody>
    </table>
  </form>
{% endif %}
于 2014-02-19T17:19:53.680 回答