2014-02-18 5 views
0

У меня есть три модели User (django.contrib.auth), Screening и User_Screening. User_Screening - таблица m2m с дополнительным полем status.Django: одна и та же форма несколько раз в одном виде

#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 таблицы). Также может быть, что у пользователя еще нет записи для этого скрининга, поэтому нужно создать.

Я не понимаю, как я мог архивировать поле выпадающего списка формы для каждого экрана, где пользователь может выбрать свой статус. (Либо ? если не статус не установлен еще, attending, not attending или projection)

Из того, что я понимаю, что нужно несколько форм, которые знают, что скрининг они связаны.

Кроме того, Formsets, похоже, не работает, потому что я не всегда могу заполнить форму исходными данными, так как на некоторых или всех экранах могут отсутствовать записи. Кроме того, я не знаю, какая форма относится к какому из экранирующих объектов.

Update: То, что я хочу, чтобы в конечном итоге в 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> 

Поэтому изменение количества форм требуется, из одной и той же формы с предварительно загруженными данными в соответствии с зарегистрированным в пользователе.

ответ

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', ] 

Formset:

ScreeningFormSet = modelformset_factory(Screenig, max_num=1) 
formset = ScreeningFormSet(Screening=Screening.objects.filter(date__gte=now)) 
+0

Ладно, я мог бы уточнить, что есть больше, чем просто 'status'«наступающий»и«не придет». Я сократил их для этого вопроса. Кроме того: если у меня есть отношение к статусу «не придет», я знаю, что пользователь активно решил не приезжать, что мне действительно нужно, для целей напоминания по электронной почте. –

0

С одной стороны, вы можете отправить данные формы с помощью запроса AJAX. В этом запросе вы просто отправляете одну форму и обрабатываете данные. Вам не нужны никакие формы. В зависимости от вашего использования он может добавить ненужный трафик на ваш сервер.

Другим решением было бы добавить еще один STATUS_CHOICE как «ничего не выбрано» в качестве значения по умолчанию для формы, которая используется, если нет записи для комбинации Screening User в db. В обработчике POST вашего представления вы можете просто проверить, установлено ли для данных формы это значение. В этом случае вы просто игнорируете форму. Если это другое значение, вы соответственно устанавливаете запись db.

+0

То, что я действительно хочу архивировать, - иметь одну и ту же форму несколько раз в одном представлении (например, в заголовке). Я обновил свой вопрос, чтобы уточнить, какой вывод html я ожидал бы. –

+0

Я не вижу проблемы там. просто создайте список форм в своем представлении и создайте шаблон, который перебирает этот список форм и отображает их. когда вызывается изменение формы на Change(), и данные формы, включая идентификатор формы, передаются в соответствующее представление и обрабатываются там. – 7tupel

0

С некоторой помощью #django на feenode, я решил свою проблему. В конце концов, я придерживался форм.

Учитывая мои модели. Из моего вопроса мне пришлось слегка изменить User_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) 

The formset.forms заархивированы вместе с current_screening_set, чтобы предоставить дополнительные данные для каждого из. 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 %} 

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

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