Commit 772b90c5 authored by Nicolas Joyard's avatar Nicolas Joyard

Add theme model, relations, and admin / Remove position tags

parent 69861a94
...@@ -1084,82 +1084,13 @@ ...@@ -1084,82 +1084,13 @@
"model": "representatives_recommendations.recommendation", "model": "representatives_recommendations.recommendation",
"pk": 47 "pk": 47
}, },
{
"fields": {
"name": "acta",
"slug": "acta"
},
"model": "taggit.tag",
"pk": 1
},
{
"fields": {
"name": "foo",
"slug": "foo"
},
"model": "taggit.tag",
"pk": 2
},
{
"fields": {
"name": "bar",
"slug": "bar"
},
"model": "taggit.tag",
"pk": 3
},
{ {
"fields": { "fields": {
"model": "position", "model": "position",
"app_label": "representatives_positions" "app_label": "representatives_positions"
}, },
"model": "contenttypes.contenttype", "model": "contenttypes.contenttype",
"pk": 29 "pk": 31
},
{
"fields": {
"tag": 1,
"object_id": 1,
"content_type": 29
},
"model": "taggit.taggeditem",
"pk": 1
},
{
"fields": {
"tag": 2,
"object_id": 1,
"content_type": 29
},
"model": "taggit.taggeditem",
"pk": 2
},
{
"fields": {
"tag": 1,
"object_id": 3,
"content_type": 29
},
"model": "taggit.taggeditem",
"pk": 5
},
{
"fields": {
"tag": 1,
"object_id": 2,
"content_type": 29
},
"model": "taggit.taggeditem",
"pk": 6
},
{
"fields": {
"tag": 3,
"object_id": 2,
"content_type": 29
},
"model": "taggit.taggeditem",
"pk": 7
}, },
{ {
"fields": { "fields": {
......
...@@ -91,6 +91,7 @@ INSTALLED_APPS = ( ...@@ -91,6 +91,7 @@ INSTALLED_APPS = (
'core', 'core',
'memopol', 'memopol',
'memopol_settings', 'memopol_settings',
'memopol_themes',
'representatives', 'representatives',
'representatives_votes', 'representatives_votes',
'representatives_recommendations', 'representatives_recommendations',
......
...@@ -10,17 +10,6 @@ ...@@ -10,17 +10,6 @@
first-validated first-validated
</a> </a>
</td> </td>
<td>
<span class='label label-default'>
acta
</span>
<span class='label label-default'>
bar
</span>
</td>
<td> <td>
<a href='http://example.com/first-validated'> <a href='http://example.com/first-validated'>
http://example.com/first-validated http://example.com/first-validated
...@@ -36,13 +25,6 @@ ...@@ -36,13 +25,6 @@
other-validated other-validated
</a> </a>
</td> </td>
<td>
<span class='label label-default'>
acta
</span>
</td>
<td> <td>
<a href='http://example.com/second-validated'> <a href='http://example.com/second-validated'>
http://example.com/second-validated http://example.com/second-validated
......
...@@ -12,7 +12,7 @@ class RepresentativeDetailTest(UrlGetTestMixin, TestCase): ...@@ -12,7 +12,7 @@ class RepresentativeDetailTest(UrlGetTestMixin, TestCase):
# Ensure one-time cached queries occur before the actual test # Ensure one-time cached queries occur before the actual test
self.client.get(self.url) self.client.get(self.url)
with self.assertNumQueries(12): with self.assertNumQueries(11):
""" """
- One query for chambers - One query for chambers
- One query for the rep details and foreign key (profile) - One query for the rep details and foreign key (profile)
...@@ -24,7 +24,6 @@ class RepresentativeDetailTest(UrlGetTestMixin, TestCase): ...@@ -24,7 +24,6 @@ class RepresentativeDetailTest(UrlGetTestMixin, TestCase):
- One query for reverse relation on votes - One query for reverse relation on votes
- One query for reverse relation on mandates - One query for reverse relation on mandates
- One query for reverse relation positions - One query for reverse relation positions
- One query for reverse relation tags on positions
""" """
self.client.get(self.url) self.client.get(self.url)
......
...@@ -70,7 +70,6 @@ class RepresentativeDetail(RepresentativeViewMixin, generic.DetailView): ...@@ -70,7 +70,6 @@ class RepresentativeDetail(RepresentativeViewMixin, generic.DetailView):
c['votes'] = c['object'].votes.all() c['votes'] = c['object'].votes.all()
c['mandates'] = c['object'].mandates.all() c['mandates'] = c['object'].mandates.all()
c['positions'] = c['object'].positions.filter(published=True) \ c['positions'] = c['object'].positions.filter(published=True) \
.prefetch_related('tags') \
.order_by('-datetime', 'pk') .order_by('-datetime', 'pk')
c['position_form'] = PositionForm( c['position_form'] = PositionForm(
......
from django import forms
from django.contrib import admin
from representatives_votes.admin import DossierAdmin, ProposalAdmin
from representatives_votes.models import Dossier, Proposal
from representatives_positions.admin import PositionAdmin
from representatives_positions.models import Position
from .models import Theme, ThemeLink
class LinkInline(admin.StackedInline):
model = ThemeLink
extra = 0
class ThemeAdmin(admin.ModelAdmin):
list_display = ('name', 'description')
list_editable = ('name', 'description')
list_filter = ('name',)
fields = ('name', 'description')
inlines = [
LinkInline
]
class ThemeLinkAdmin(admin.ModelAdmin):
list_display = ('title', 'datetime', 'link')
list_editable = ('title', 'datetime', 'link')
list_filter = ('title', 'datetime', 'link')
class ThemedAdminForm(forms.ModelForm):
themes = forms.ModelMultipleChoiceField(
queryset=Theme.objects.all(),
required=False,
widget=admin.widgets.FilteredSelectMultiple(
verbose_name='Themes',
is_stacked=False
)
)
def __init__(self, *args, **kwargs):
super(ThemedAdminForm, self).__init__(*args, **kwargs)
if self.instance and self.instance.pk:
self.fields['themes'].initial = self.instance.themes.all()
def save(self, commit=True):
item = super(ThemedAdminForm, self).save(commit=False)
if commit:
item.save()
if item.pk:
item.themes = self.cleaned_data['themes']
self.save_m2m()
return item
class ThemedDossierAdminForm(ThemedAdminForm):
class Meta:
model = Dossier
fields = ('title', 'reference', 'text', 'themes')
class ThemedProposalAdminForm(ThemedAdminForm):
class Meta:
model = Proposal
fields = ('dossier', 'title', 'description', 'reference', 'datetime',
'kind', 'total_abstain', 'total_against', 'total_for',
'themes')
class ThemedPositionAdminForm(ThemedAdminForm):
class Meta:
model = Position
fields = ('representative', 'datetime', 'text', 'link', 'published',
'themes')
class ThemedDossierAdmin(DossierAdmin):
form = ThemedDossierAdminForm
class ThemedProposalAdmin(ProposalAdmin):
form = ThemedProposalAdminForm
class ThemedPositionAdmin(PositionAdmin):
form = ThemedPositionAdminForm
admin.site.register(Theme, ThemeAdmin)
admin.site.register(ThemeLink, ThemeLinkAdmin)
admin.site.unregister(Dossier)
admin.site.register(Dossier, ThemedDossierAdmin)
admin.site.unregister(Proposal)
admin.site.register(Proposal, ThemedProposalAdmin)
admin.site.unregister(Position)
admin.site.register(Position, ThemedPositionAdmin)
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('representatives_votes', '0012_document'),
('representatives_positions', '0002_increase_link_length'),
]
operations = [
migrations.CreateModel(
name='Theme',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(unique=True, max_length=255)),
('description', models.TextField()),
('dossiers', models.ManyToManyField(related_name='themes', to='representatives_votes.Dossier')),
('positions', models.ManyToManyField(related_name='themes', to='representatives_positions.Position')),
('proposals', models.ManyToManyField(related_name='themes', to='representatives_votes.Proposal')),
],
),
migrations.CreateModel(
name='ThemeLink',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('title', models.CharField(max_length=511)),
('datetime', models.DateField()),
('link', models.URLField(max_length=500)),
('theme', models.ForeignKey(related_name='links', to='memopol_themes.Theme')),
],
),
]
from django.db import models
from django.utils.encoding import smart_unicode
from representatives_votes.models import Dossier, Proposal
from representatives_positions.models import Position
class Theme(models.Model):
name = models.CharField(max_length=255, unique=True)
description = models.TextField()
dossiers = models.ManyToManyField(Dossier, related_name='themes')
proposals = models.ManyToManyField(Proposal, related_name='themes')
positions = models.ManyToManyField(Position, related_name='themes')
def __unicode__(self):
return smart_unicode(self.name)
class ThemeLink(models.Model):
title = models.CharField(max_length=511)
datetime = models.DateField()
link = models.URLField(max_length=500)
theme = models.ForeignKey(Theme, related_name='links')
def __unicode__(self):
return smart_unicode('%s (%s)' % (self.title, self.link))
...@@ -8,7 +8,7 @@ from .models import Position ...@@ -8,7 +8,7 @@ from .models import Position
class PositionForm(forms.ModelForm): class PositionForm(forms.ModelForm):
class Meta: class Meta:
model = Position model = Position
fields = ['tags', 'datetime', 'text', 'link', 'representative'] fields = ['datetime', 'text', 'link', 'representative']
widgets = { widgets = {
# Use localization and bootstrap 3 # Use localization and bootstrap 3
'datetime': DateWidget( 'datetime': DateWidget(
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('representatives_positions', '0002_increase_link_length'),
]
operations = [
migrations.RemoveField(
model_name='position',
name='tags',
),
]
from django.db import models from django.db import models
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.template.defaultfilters import truncatewords from django.template.defaultfilters import truncatewords
from taggit.managers import TaggableManager
from representatives.models import Representative from representatives.models import Representative
class Position(models.Model): class Position(models.Model):
representative = models.ForeignKey(Representative, representative = models.ForeignKey(Representative,
related_name='positions') related_name='positions')
datetime = models.DateField() datetime = models.DateField()
text = models.TextField() text = models.TextField()
link = models.URLField(max_length=500) link = models.URLField(max_length=500)
published = models.BooleanField(default=False) published = models.BooleanField(default=False)
tags = TaggableManager()
@property @property
def short_text(self): def short_text(self):
...@@ -26,4 +24,4 @@ class Position(models.Model): ...@@ -26,4 +24,4 @@ class Position(models.Model):
def get_absolute_url(self): def get_absolute_url(self):
return reverse('representatives_positions:position-detail', return reverse('representatives_positions:position-detail',
args=(self.pk,)) args=(self.pk,))
...@@ -11,10 +11,7 @@ ...@@ -11,10 +11,7 @@
.long-quote .long-quote
= object.text|linebreaks = object.text|linebreaks
%p.tags
- for tag in object.tags.all
%span.label.label-default
= tag
%p %p
Source : Source :
%a{:href => '{{object.link}}'} %a{:href => '{{object.link}}'}
......
...@@ -13,13 +13,11 @@ class PositionTest(TestCase): ...@@ -13,13 +13,11 @@ class PositionTest(TestCase):
def setUp(self): def setUp(self):
self.client = Client() self.client = Client()
self.tags = [u'foo', u'bar']
self.create_url = reverse('representatives_positions:position-create') self.create_url = reverse('representatives_positions:position-create')
self.mep = Representative.objects.get(pk=160) self.mep = Representative.objects.get(pk=160)
self.fixture = { self.fixture = {
'tags': ','.join(self.tags),
'datetime': '2015-12-11', 'datetime': '2015-12-11',
'text': '%stext' % self.id(), 'text': '%stext' % self.id(),
'link': 'http://example.com/%slink' % self.id(), 'link': 'http://example.com/%slink' % self.id(),
...@@ -34,8 +32,6 @@ class PositionTest(TestCase): ...@@ -34,8 +32,6 @@ class PositionTest(TestCase):
assert response['Location'] == expected assert response['Location'] == expected
result = Position.objects.get(text='%stext' % self.id()) result = Position.objects.get(text='%stext' % self.id())
assert list(result.tags.order_by('pk').values_list('name',
flat=True)) == self.tags
assert result.datetime == datetime.date(2015, 12, 11) assert result.datetime == datetime.date(2015, 12, 11)
assert result.link == self.fixture['link'] assert result.link == self.fixture['link']
assert result.representative.pk == self.mep.pk assert result.representative.pk == self.mep.pk
...@@ -73,20 +69,16 @@ class PositionTest(TestCase): ...@@ -73,20 +69,16 @@ class PositionTest(TestCase):
representative=self.mep representative=self.mep
) )
position.tags.add('%stag' % self.id())
# Trigger irrelevant queries that happen only once ie. constance before # Trigger irrelevant queries that happen only once ie. constance before
# testing actual page queries. # testing actual page queries.
self.client.get(position.get_absolute_url()) self.client.get(position.get_absolute_url())
with self.assertNumQueries(4): with self.assertNumQueries(3):
# One for position and rep and score # One for position and rep and score
# One for rep mandates # One for rep mandates
# One for rep chamber # One for rep chamber
# One for position tags
response = self.client.get(position.get_absolute_url()) response = self.client.get(position.get_absolute_url())
assert 'Dec. 11, 2015' in response.content assert 'Dec. 11, 2015' in response.content
assert '%stag' % self.id() in response.content
assert self.fixture['link'] in response.content assert self.fixture['link'] in response.content
assert self.fixture['text'] in response.content assert self.fixture['text'] in response.content
assert self.mep.full_name in response.content assert self.mep.full_name in response.content
...@@ -69,10 +69,6 @@ ...@@ -69,10 +69,6 @@
%td %td
%a{:href => '{{ position.get_absolute_url }}'} %a{:href => '{{ position.get_absolute_url }}'}
=position.text|truncatewords:8 =position.text|truncatewords:8
%td
- for tag in position.tags.all
%span.label.label-default
= tag
%td %td
%a{:href => '{{ position.link }}'} %a{:href => '{{ position.link }}'}
= position.link = position.link
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment