Skip to content

Commit 3116dfe

Browse files
committed
Creator roles update
1 parent 2485f6b commit 3116dfe

File tree

8 files changed

+156
-25
lines changed

8 files changed

+156
-25
lines changed

comics/admin.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from django.contrib import admin
22
from solo.admin import SingletonModelAdmin
3-
from .models import Arc, Character, Creator, Team, Publisher, Series, Issue, Settings
3+
from .models import Arc, Character, Creator, Team, Publisher, Series, Issue, Roles, Settings
44

55
admin.site.site_header = 'Tenma'
66
admin.site.site_title = 'Tenma'
@@ -12,4 +12,5 @@
1212
admin.site.register(Team)
1313
admin.site.register(Publisher)
1414
admin.site.register(Series)
15-
admin.site.register(Issue)
15+
admin.site.register(Issue)
16+
admin.site.register(Roles)
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# -*- coding: utf-8 -*-
2+
# Generated by Django 1.10.1 on 2017-08-02 20:11
3+
from __future__ import unicode_literals
4+
5+
from django.db import migrations, models
6+
import django.db.models.deletion
7+
import multiselectfield.db.fields
8+
9+
10+
class Migration(migrations.Migration):
11+
12+
dependencies = [
13+
('comics', '0001_initial'),
14+
]
15+
16+
operations = [
17+
migrations.CreateModel(
18+
name='Roles',
19+
fields=[
20+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21+
('roles', multiselectfield.db.fields.MultiSelectField(choices=[('artist', 'Artist'), ('colorist', 'Colorist'), ('cover', 'Cover'), ('editor', 'Editor'), ('inker', 'Inker'), ('journalist', 'Journalist'), ('letterer', 'Letterer'), ('other', 'Other'), ('penciler', 'Penciler'), ('production', 'Production'), ('writer', 'Writer')], max_length=87)),
22+
],
23+
),
24+
migrations.AlterModelOptions(
25+
name='series',
26+
options={'verbose_name_plural': 'Series'},
27+
),
28+
migrations.RemoveField(
29+
model_name='issue',
30+
name='creators',
31+
),
32+
migrations.AlterField(
33+
model_name='arc',
34+
name='image',
35+
field=models.FilePathField(blank=True, path='media/images', verbose_name='Image file path'),
36+
),
37+
migrations.AlterField(
38+
model_name='character',
39+
name='image',
40+
field=models.FilePathField(blank=True, path='media/images', verbose_name='Image file path'),
41+
),
42+
migrations.AlterField(
43+
model_name='creator',
44+
name='image',
45+
field=models.FilePathField(blank=True, path='media/images', verbose_name='Image file path'),
46+
),
47+
migrations.AlterField(
48+
model_name='issue',
49+
name='cover',
50+
field=models.FilePathField(blank=True, path='media/images', verbose_name='Cover file path'),
51+
),
52+
migrations.AlterField(
53+
model_name='issue',
54+
name='cvid',
55+
field=models.CharField(blank=True, max_length=15, verbose_name='ComicVine ID'),
56+
),
57+
migrations.AlterField(
58+
model_name='publisher',
59+
name='logo',
60+
field=models.FilePathField(blank=True, path='media/images', verbose_name='Logo file path'),
61+
),
62+
migrations.AlterField(
63+
model_name='series',
64+
name='year',
65+
field=models.PositiveSmallIntegerField(blank=True, choices=[(1837, 1837), (1838, 1838), (1839, 1839), (1840, 1840), (1841, 1841), (1842, 1842), (1843, 1843), (1844, 1844), (1845, 1845), (1846, 1846), (1847, 1847), (1848, 1848), (1849, 1849), (1850, 1850), (1851, 1851), (1852, 1852), (1853, 1853), (1854, 1854), (1855, 1855), (1856, 1856), (1857, 1857), (1858, 1858), (1859, 1859), (1860, 1860), (1861, 1861), (1862, 1862), (1863, 1863), (1864, 1864), (1865, 1865), (1866, 1866), (1867, 1867), (1868, 1868), (1869, 1869), (1870, 1870), (1871, 1871), (1872, 1872), (1873, 1873), (1874, 1874), (1875, 1875), (1876, 1876), (1877, 1877), (1878, 1878), (1879, 1879), (1880, 1880), (1881, 1881), (1882, 1882), (1883, 1883), (1884, 1884), (1885, 1885), (1886, 1886), (1887, 1887), (1888, 1888), (1889, 1889), (1890, 1890), (1891, 1891), (1892, 1892), (1893, 1893), (1894, 1894), (1895, 1895), (1896, 1896), (1897, 1897), (1898, 1898), (1899, 1899), (1900, 1900), (1901, 1901), (1902, 1902), (1903, 1903), (1904, 1904), (1905, 1905), (1906, 1906), (1907, 1907), (1908, 1908), (1909, 1909), (1910, 1910), (1911, 1911), (1912, 1912), (1913, 1913), (1914, 1914), (1915, 1915), (1916, 1916), (1917, 1917), (1918, 1918), (1919, 1919), (1920, 1920), (1921, 1921), (1922, 1922), (1923, 1923), (1924, 1924), (1925, 1925), (1926, 1926), (1927, 1927), (1928, 1928), (1929, 1929), (1930, 1930), (1931, 1931), (1932, 1932), (1933, 1933), (1934, 1934), (1935, 1935), (1936, 1936), (1937, 1937), (1938, 1938), (1939, 1939), (1940, 1940), (1941, 1941), (1942, 1942), (1943, 1943), (1944, 1944), (1945, 1945), (1946, 1946), (1947, 1947), (1948, 1948), (1949, 1949), (1950, 1950), (1951, 1951), (1952, 1952), (1953, 1953), (1954, 1954), (1955, 1955), (1956, 1956), (1957, 1957), (1958, 1958), (1959, 1959), (1960, 1960), (1961, 1961), (1962, 1962), (1963, 1963), (1964, 1964), (1965, 1965), (1966, 1966), (1967, 1967), (1968, 1968), (1969, 1969), (1970, 1970), (1971, 1971), (1972, 1972), (1973, 1973), (1974, 1974), (1975, 1975), (1976, 1976), (1977, 1977), (1978, 1978), (1979, 1979), (1980, 1980), (1981, 1981), (1982, 1982), (1983, 1983), (1984, 1984), (1985, 1985), (1986, 1986), (1987, 1987), (1988, 1988), (1989, 1989), (1990, 1990), (1991, 1991), (1992, 1992), (1993, 1993), (1994, 1994), (1995, 1995), (1996, 1996), (1997, 1997), (1998, 1998), (1999, 1999), (2000, 2000), (2001, 2001), (2002, 2002), (2003, 2003), (2004, 2004), (2005, 2005), (2006, 2006), (2007, 2007), (2008, 2008), (2009, 2009), (2010, 2010), (2011, 2011), (2012, 2012), (2013, 2013), (2014, 2014), (2015, 2015), (2016, 2016), (2017, 2017)], default=2017, verbose_name='year'),
66+
),
67+
migrations.AlterField(
68+
model_name='team',
69+
name='image',
70+
field=models.FilePathField(blank=True, path='media/images', verbose_name='Image file path'),
71+
),
72+
migrations.AddField(
73+
model_name='roles',
74+
name='creator',
75+
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='comics.Creator'),
76+
),
77+
migrations.AddField(
78+
model_name='roles',
79+
name='issue',
80+
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='comics.Issue'),
81+
),
82+
]

comics/models.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import datetime,os,rarfile,zipfile,tarfile
44

55
from shutil import copyfile
6+
from multiselectfield import MultiSelectField
67

78
from django.db import models
89
from solo.models import SingletonModel
@@ -13,10 +14,26 @@
1314
from .utils.comicfilehandler import ComicFileHandler
1415

1516
"""
16-
Create a choice for years
17+
Choices for model use.
1718
"""
19+
# Generated years
1820
YEAR_CHOICES = [(r,r) for r in range(1837, datetime.date.today().year+1)]
1921

22+
# Creator roles for an issue
23+
ROLE_CHOICES = (
24+
('artist', 'Artist'),
25+
('colorist', 'Colorist'),
26+
('cover', 'Cover'),
27+
('editor', 'Editor'),
28+
('inker', 'Inker'),
29+
('journalist', 'Journalist'),
30+
('letterer', 'Letterer'),
31+
('other', 'Other'),
32+
('penciler', 'Penciler'),
33+
('production', 'Production'),
34+
('writer', 'Writer'),
35+
)
36+
2037
class Settings(SingletonModel):
2138
api_key = models.CharField(
2239
'ComicVine API Key',
@@ -111,7 +128,6 @@ class Issue(models.Model):
111128
desc = models.TextField('Description', max_length=500, blank=True)
112129
arcs = models.ManyToManyField(Arc, blank=True)
113130
characters = models.ManyToManyField(Character, blank=True)
114-
creators = models.ManyToManyField(Creator, blank=True)
115131
teams = models.ManyToManyField(Team, blank=True)
116132
file = models.FilePathField('File path', path="files/", recursive=True)
117133
cover = models.FilePathField('Cover file path', path="media/images", blank=True)
@@ -126,4 +142,15 @@ def page_set(self):
126142
comicfilehandler = ComicFileHandler()
127143
comic = comicfilehandler.extract_comic(self.file, self.id)
128144

129-
return comic
145+
return comic
146+
147+
class Roles(models.Model):
148+
creator = models.ForeignKey(Creator, on_delete=models.CASCADE)
149+
issue = models.ForeignKey(Issue, on_delete=models.CASCADE)
150+
roles = MultiSelectField(choices=ROLE_CHOICES)
151+
152+
def __str__(self):
153+
return self.issue.series.name + ' #' + str(self.issue.number) + ' - ' + self.creator.name
154+
155+
class Meta:
156+
verbose_name_plural = "Roles"

comics/templates/comics/issue.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ <h3>Issue #{{ issue.number }}{% if issue.name %} - <i>{{ issue.name }}</i>{% end
5050

5151
{% include "comics/related_characters.html" with character_list=issue.characters.all %}
5252

53-
{% include "comics/related_creators.html" with creator_list=issue.creators.all %}
53+
{% include "comics/related_creators.html" with roles_list=roles_list.all %}
5454

5555
{% include "comics/related_teams.html" with team_list=issue.teams.all %}
5656
<script>
@@ -64,4 +64,4 @@ <h3>Issue #{{ issue.number }}{% if issue.name %} - <i>{{ issue.name }}</i>{% end
6464
});
6565
})
6666
</script>
67-
{% endblock content %}
67+
{% endblock content %}
Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,27 @@
11
{% load simple_crop %}
22
{% load staticfiles %}
33

4-
{% if creator_list %}
4+
{% if roles_list %}
55
<div class="related related-creators">
66
<h2>Creators</h2>
77
<div class="flexslider related-slider">
88
<ul class="slides">
9-
{% for creator in creator_list %}
9+
{% for roles in roles_list %}
1010
<li>
11-
<a href="{% url 'comics:creator' creator.id %}">
11+
<a href="{% url 'comics:creator' roles.creator.id %}">
1212
<div class="image">
13-
{% if creator.image %}
14-
<img src="{{ creator.image|smartcrop:"200x305"|urlencode }}" alt="{{ creator.name }}" >
13+
{% if roles.creator.image %}
14+
<img src="{{ roles.creator.image|smartcrop:"200x305"|urlencode }}" alt="{{ roles.creator.name }}" >
1515
{% else %}
16-
<img src="{% static 'comics/image-not-found.png' %}" alt="{{ creator.name }}" >
16+
<img src="{% static 'comics/image-not-found.png' %}" alt="{{ roles.creator.name }}" >
1717
{% endif %}
1818
</div>
1919
</a>
20-
<a href="{% url 'comics:creator' creator.id %}"><p>{{ creator.name }}</p></a>
20+
<a href="{% url 'comics:creator' roles.creator.id %}"><p>{{ roles.creator.name }}</p></a>
21+
<p><small><em>{{ roles.roles }}</em></small></p>
2122
</li>
2223
{% endfor %}
2324
</ul>
2425
</div>
2526
</div>
26-
{% endif %}
27+
{% endif %}

comics/utils/comicimporter.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import json, os, time, datetime, re, requests, requests_cache
22
from urllib.request import urlretrieve
33
from urllib.parse import quote_plus, unquote_plus
4-
from comics.models import Arc, Character, Creator, Team, Publisher, Series, Issue, Settings
4+
from comics.models import Arc, Character, Creator, Team, Publisher, Series, Issue, Roles, Settings
55
from .comicfilehandler import ComicFileHandler
66
from . import fnameparser, utils
77

@@ -464,9 +464,14 @@ def _process_issue(self, filename, cvid):
464464
for person in response_issue['results']['person_credits']:
465465
matching_creator = Creator.objects.filter(cvid=person['id'])
466466
if not matching_creator:
467-
self._create_creator(person['api_detail_url'], issue.id)
467+
self._create_creator(person['api_detail_url'], re.sub(' ', '', person['role']), issue.id)
468468
else:
469-
issue.creators.add(self._update_creator(matching_creator[0].id, person['api_detail_url']))
469+
#TODO: Create many-to-many relationship through Role
470+
Roles.objects.create(
471+
creator=matching_creator[0],
472+
issue=issue,
473+
roles=re.sub(' ', '', person['role'])
474+
)
470475

471476
# 8. Set Teams
472477
for team in response_issue['results']['team_credits']:
@@ -734,7 +739,7 @@ def _create_character(self, api_url, issue_id):
734739

735740
#==================================================================================================
736741

737-
def _create_creator(self, api_url, issue_id):
742+
def _create_creator(self, api_url, roles, issue_id):
738743
'''
739744
Creates Creator from ComicVine API URL and adds it to
740745
it's corresponding Issue.
@@ -757,14 +762,21 @@ def _create_creator(self, api_url, issue_id):
757762
issue = Issue.objects.get(id=issue_id)
758763

759764
# Create Creator
760-
cr = issue.creators.create(
765+
cr = Creator.objects.create(
761766
cvid=data['cvid'],
762767
cvurl=data['cvurl'],
763768
name=data['name'],
764769
desc=data['desc'],
765770
image=data['image'],
766771
)
767772

773+
# Create Role in issue
774+
r = Roles.objects.create(
775+
creator=cr,
776+
issue=issue,
777+
roles=roles
778+
)
779+
768780
return cr
769781

770782

@@ -1176,7 +1188,7 @@ def _reset_issue(self, obj_id):
11761188
issue.desc = ''
11771189
issue.arcs.clear()
11781190
issue.characters.clear()
1179-
issue.creators.clear()
1191+
Roles.objects.filter(issue=issue).delete()
11801192
issue.teams.clear()
11811193
issue.cover = ''
11821194

comics/views.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from django.views.generic import ListView, DetailView
33
from django.views.generic.edit import UpdateView
44
from django.http import HttpResponseRedirect
5-
from .models import Series, Issue, Character, Arc, Team, Publisher, Creator, Settings
5+
from .models import Series, Issue, Character, Arc, Team, Publisher, Creator, Settings, Roles
66
from .tasks import import_comic_files_task, reprocess_issue_task
77
from .utils.comicimporter import ComicImporter
88

@@ -20,7 +20,13 @@ class SeriesView(DetailView):
2020
class IssueView(DetailView):
2121
model = Issue
2222
template_name = 'comics/issue.html'
23-
23+
24+
def get_context_data(self, **kwargs):
25+
context = super(IssueView, self).get_context_data(**kwargs)
26+
issue = self.get_object()
27+
context['roles_list'] = Roles.objects.filter(issue=issue)
28+
return context
29+
2430
class CharacterView(DetailView):
2531
model = Character
2632
template_name = 'comics/character.html'
@@ -62,7 +68,8 @@ class CreatorView(DetailView):
6268
def get_context_data(self, **kwargs):
6369
context = super(CreatorView, self).get_context_data(**kwargs)
6470
creator = self.get_object()
65-
context['issue_list'] = creator.issue_set.all().order_by('series__name', 'number')
71+
roles = Roles.objects.filter(creator=creator)
72+
context['issue_list'] = Issue.objects.filter(id__in=roles.values('issue_id'))
6673
return context
6774

6875
class ServerSettingsView(UpdateView):
@@ -96,4 +103,4 @@ def importer(request):
96103

97104
def reprocess(request, issue_id):
98105
reprocess_issue_task.delay(issue_id)
99-
return HttpResponseRedirect('/issue/' + issue_id)
106+
return HttpResponseRedirect('/issue/' + issue_id)

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ anyjson==0.3.3
33
billiard==3.3.0.23
44
celery==3.1.23
55
Django==1.10.1
6+
django-multiselectfield==0.1.7
67
django-solo==1.1.2
78
django-widget-tweaks==1.4.1
89
kombu==3.0.35

0 commit comments

Comments
 (0)