Save the submitters to the motion

This commit is contained in:
Oskar Hahn 2013-01-26 15:25:54 +01:00
parent 1ae140c11e
commit 1f87749742
7 changed files with 104 additions and 75 deletions

View File

@ -19,6 +19,9 @@ from .models import Motion
class BaseMotionForm(forms.ModelForm, CssClassMixin): class BaseMotionForm(forms.ModelForm, CssClassMixin):
"""
Form to automaticly save the version data for a motion.
"""
class Meta: class Meta:
model = Motion model = Motion
fields = () fields = ()
@ -38,12 +41,20 @@ class BaseMotionForm(forms.ModelForm, CssClassMixin):
widget=forms.Textarea(), required=False, label=_("Reason")) widget=forms.Textarea(), required=False, label=_("Reason"))
class MotionCreateForm(BaseMotionForm): class MotionSubmitterMixin(forms.ModelForm):
pass submitter = MultiplePersonFormField(label=_("Submitter"))
class MotionUpdateForm(BaseMotionForm): class MotionSupporterMixin(forms.ModelForm):
pass supporter = MultiplePersonFormField(required=False, label=_("Supporters"))
class MotionTrivialChangesMixin(object):
trivial_change = forms.BooleanField(
required=False, label=_("Trivial change"),
help_text=_("Trivial changes don't create a new version."))
class ConfigForm(forms.Form, CssClassMixin): class ConfigForm(forms.Form, CssClassMixin):

View File

@ -31,49 +31,21 @@ from openslides.projector.models import SlideMixin
from openslides.agenda.models import Item from openslides.agenda.models import Item
RELATION = ( # TODO: Save submitter and supporter in the same table
(1, _('Submitter')), class MotionSubmitter(models.Model):
(2, _('Supporter')))
class RelatedPersonsManager(models.Manager):
"""
Manager for MotionRelatedPersons.
Returns a custom manager with gives a specific queryset for one type of
persons.
"""
def __init__(self, relation, *args, **kwargs):
super(RelatedPersonsManager, self).__init__(*args, **kwargs)
for key, value in RELATION:
if key == relation:
self.relation = key
break
else:
raise ValueError('Unknown relation with id %d' % relation)
def get_query_set(self):
return (super(RelatedPersonsManager, self).get_query_set()
.filter(relation=self.relation))
class MotionRelatedPersons(models.Model):
"""
Saves the all persons related to a motion.
relation = 1: submitter
relation = 2: supporter
The custom manager submitter and supporter return a queryset with the
specific persons.
"""
submitter = RelatedPersonsManager(relation=1)
supporter = RelatedPersonsManager(relation=2)
objects = models.Manager()
person = PersonField() person = PersonField()
relation = models.IntegerField(default=1, choices=RELATION) motion = models.ForeignKey('Motion', related_name="submitter")
motion = models.ForeignKey('Motion', related_name="persons")
def __unicode__(self):
return unicode(self.person)
class MotionSupporter(models.Model):
person = PersonField()
motion = models.ForeignKey('Motion', related_name="supporter")
def __unicode__(self):
return unicode(self.person)
class Motion(SlideMixin, models.Model): class Motion(SlideMixin, models.Model):
@ -198,20 +170,6 @@ class Motion(SlideMixin, models.Model):
reason = property(get_reason, set_reason) reason = property(get_reason, set_reason)
@property
def submitter(self):
"""
Return a queryset with all submitter of this motion.
"""
return MotionRelatedPersons.submitter.filter(motion=self)
@property
def supporter(self):
"""
Returns a queryset with all supporter of this motion.
"""
return MotionRelatedPersons.supporter.filter(motion=self)
@property @property
def new_version(self): def new_version(self):
""" """
@ -292,9 +250,15 @@ class MotionVersion(models.Model):
note = models.TextField(null=True, blank=True) note = models.TextField(null=True, blank=True)
def __unicode__(self): def __unicode__(self):
return "%s Version %s" % (self.motion, self.get_version_number()) return "%s Version %s" % (self.motion, self.version_number)
def get_version_number(self): def get_absolute_url(self, link='detail'):
if link == 'view' or link == 'detail':
return reverse('motion_version_detail', args=[str(self.motion.id),
str(self.version_number)])
@property
def version_number(self):
if self.pk is None: if self.pk is None:
return 'new' return 'new'
return (MotionVersion.objects.filter(motion=self.motion) return (MotionVersion.objects.filter(motion=self.motion)

View File

@ -4,9 +4,21 @@
{% load i18n %} {% load i18n %}
{% load staticfiles %} {% load staticfiles %}
{% block title %}{{ block.super }} {% trans "Motion" %} "{{ version.title }}"{% endblock %} {% block title %}{{ block.super }} {% trans "Motion" %} "{{ motion.title }}"{% endblock %}
{% block content %} {% block content %}
<p>Titel: {{ object.title }} </p> <p>Titel: {{ motion.title }} </p>
<p>Text: {{ object.text }}</p> <p>Text: {{ motion.text }}</p>
<p>Reason: {{ motion.reason }}</p>
<p>Submitter: {% for submitter in motion.submitter.all %}{{ submitter.person }} {% endfor %}</p>
<ol>
{% for motion_version in motion.versions.all %}
{% if motion_version.id == motion.version.id %}
<li><strong><a href="{% model_url motion_version %}">{{ motion_version }}</a></strong></li>
{% else %}
<li><a href="{% model_url motion_version %}">{{ motion_version }}</a></li>
{% endif %}
{% endfor %}
</ol>
{% endblock %} {% endblock %}

View File

@ -8,9 +8,9 @@
{% block content %} {% block content %}
<h1>{% trans "Motions" %}</h1> <h1>{% trans "Motions" %}</h1>
<ul> <ol>
{% for motion in motion_list %} {% for motion in motion_list %}
<li>{{ motion }}</li> <li><a href="{% model_url motion %}">{{ motion }}</a></li>
{% endfor %} {% endfor %}
</ul> </ol>
{% endblock %} {% endblock %}

View File

@ -17,6 +17,7 @@ from django.db import transaction
from django.db.models import Model from django.db.models import Model
from django.utils.translation import ugettext as _, ugettext_lazy from django.utils.translation import ugettext as _, ugettext_lazy
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin
from django.http import Http404
from openslides.utils.pdf import stylesheet from openslides.utils.pdf import stylesheet
from openslides.utils.views import ( from openslides.utils.views import (
@ -26,8 +27,10 @@ from openslides.utils.template import Tab
from openslides.utils.utils import html_strong from openslides.utils.utils import html_strong
from openslides.projector.api import get_active_slide from openslides.projector.api import get_active_slide
from openslides.projector.projector import Widget, SLIDE from openslides.projector.projector import Widget, SLIDE
from .models import Motion from openslides.config.models import config
from .forms import MotionCreateForm, MotionUpdateForm from .models import Motion, MotionSubmitter
from .forms import (BaseMotionForm, MotionSubmitterMixin, MotionSupporterMixin,
MotionTrivialChangesMixin)
from django.views.generic.edit import ModelFormMixin from django.views.generic.edit import ModelFormMixin
@ -55,7 +58,10 @@ class MotionDetailView(DetailView):
object = super(MotionDetailView, self).get_object() object = super(MotionDetailView, self).get_object()
version_id = self.kwargs.get('version_id', None) version_id = self.kwargs.get('version_id', None)
if version_id is not None: if version_id is not None:
try:
object.version = int(version_id) -1 object.version = int(version_id) -1
except IndexError:
raise Http404
return object return object
motion_detail = MotionDetailView.as_view() motion_detail = MotionDetailView.as_view()
@ -66,9 +72,28 @@ class MotionMixin(object):
Mixin to add save the version-data to the motion-object Mixin to add save the version-data to the motion-object
""" """
def manipulate_object(self, form): def manipulate_object(self, form):
super(MotionMixin, self).manipulate_object(form)
for attr in ['title', 'text', 'reason']: for attr in ['title', 'text', 'reason']:
setattr(self.object, attr, form.cleaned_data[attr]) setattr(self.object, attr, form.cleaned_data[attr])
def post_save(self, form):
super(MotionMixin, self).post_save(form)
# TODO: only delete and save neccessary submitters
self.object.submitter.all().delete()
MotionSubmitter.objects.bulk_create(
[MotionSubmitter(motion=self.object, person=person)
for person in form.cleaned_data['submitter']])
def get_form_class(self):
form_classes = [BaseMotionForm]
if config['motion_allow_trivial_change']:
form_classes.append(MotionTrivialChangesMixin)
if self.request.user.has_perm('motion.can_manage_motion'):
form_classes.append(MotionSubmitterMixin)
if config['motion_min_supporters'] > 0:
form_classes.append(MotionSupporterMixin)
return type('MotionForm', tuple(form_classes), {})
class MotionCreateView(MotionMixin, CreateView): class MotionCreateView(MotionMixin, CreateView):
""" """
@ -76,7 +101,6 @@ class MotionCreateView(MotionMixin, CreateView):
""" """
permission_required = 'motion.can_create_motion' permission_required = 'motion.can_create_motion'
model = Motion model = Motion
form_class = MotionCreateForm
motion_create = MotionCreateView.as_view() motion_create = MotionCreateView.as_view()
@ -85,7 +109,21 @@ class MotionUpdateView(MotionMixin, UpdateView):
""" """
Update a motion. Update a motion.
""" """
# TODO: set permissions
model = Motion model = Motion
form_class = MotionUpdateForm apply_url = ''
motion_edit = MotionUpdateView.as_view() motion_edit = MotionUpdateView.as_view()
def register_tab(request):
"""
Register the projector tab.
"""
selected = request.path.startswith('/motion/')
return Tab(
title=_('Motions'),
url=reverse('motion_list'),
permission=request.user.has_perm('motion.can_see_motion'),
selected=selected,
)

View File

@ -35,6 +35,7 @@ def active(request, pattern):
@register.simple_tag @register.simple_tag
def model_url(object, link='view'): def model_url(object, link='view'):
# TODO: Rename to object_url
return object.get_absolute_url(link) return object.get_absolute_url(link)

View File

@ -113,7 +113,7 @@ class SuccessUrlMixin(object):
if 'apply' in self.request.POST: if 'apply' in self.request.POST:
return reverse(self.get_apply_url(), args=[self.object.id]) return reverse(self.get_apply_url(), args=[self.object.id])
if self.success_url: if self.success_url:
url = reverse(success_url) url = reverse(self.success_url)
else: else:
try: try:
url = self.object.get_absolute_url() url = self.object.get_absolute_url()
@ -230,12 +230,15 @@ class ModelFormMixin(object):
self.object = form.save(commit=False) self.object = form.save(commit=False)
self.manipulate_object(form) self.manipulate_object(form)
self.object.save() self.object.save()
form.save_m2m() self.post_save(form)
return HttpResponseRedirect(self.get_success_url()) return HttpResponseRedirect(self.get_success_url())
def manipulate_object(self, form): def manipulate_object(self, form):
pass pass
def post_save(self, form):
form.save_m2m()
class UpdateView(PermissionMixin, SuccessUrlMixin, ExtraContextMixin, class UpdateView(PermissionMixin, SuccessUrlMixin, ExtraContextMixin,
ModelFormMixin, _UpdateView): ModelFormMixin, _UpdateView):