0001-review-backoffice-homepage-and-announce-management-1.patch
corbo/manage_urls.py | ||
---|---|---|
1 | 1 |
from django.conf.urls import patterns, include, url |
2 | 2 | |
3 | 3 |
from .views import add_announce, edit_announce, delete_announce, \ |
4 |
add_category, edit_category, delete_category, manage, menu_json |
|
4 |
add_category, edit_category, view_category, delete_category, manage, \ |
|
5 |
add_announce_for_category, menu_json |
|
5 | 6 | |
6 | 7 |
urlpatterns = patterns('', |
7 | 8 |
url(r'^$', manage, name='manage'), |
... | ... | |
10 | 11 |
name='edit_announce'), |
11 | 12 |
url(r'^announce/delete/(?P<pk>\d+)$', delete_announce, |
12 | 13 |
name='delete_announce'), |
14 |
url(r'^category/(?P<pk>\d+)/$', view_category, |
|
15 |
name='view_category'), |
|
16 |
url(r'^category/(?P<pk>\d+)/announce/$', add_announce_for_category, |
|
17 |
name='add_announce_for_category'), |
|
13 | 18 |
url(r'^category/add$', add_category, |
14 | 19 |
name='add_category'), |
15 | 20 |
url(r'^category/edit/(?P<pk>\d+)$', edit_category, |
corbo/models.py | ||
---|---|---|
31 | 31 |
def __unicode__(self): |
32 | 32 |
return self.name |
33 | 33 | |
34 |
def get_announces_number(self): |
|
35 |
return self.announce_set.all().count() |
|
36 | ||
37 |
def get_subscriptions_number(self): |
|
38 |
return self.subscription_set.all().count() |
|
39 | ||
34 | 40 | |
35 | 41 |
class Announce(models.Model): |
36 | 42 |
category = models.ForeignKey('Category', verbose_name=_('category')) |
corbo/static/css/corbo.css | ||
---|---|---|
2 | 2 |
font-family: FontAwesome; |
3 | 3 |
} |
4 | 4 | |
5 | ||
6 | 5 |
body { |
7 | 6 |
margin: 0; |
8 | 7 |
} |
9 | 8 | |
10 | 9 |
a:link, a:visited, a:hover { |
11 | 10 |
text-decoration: none; |
12 |
color: #000; |
|
13 | 11 |
} |
14 | 12 | |
15 | 13 |
header h1 { |
... | ... | |
29 | 27 |
padding: 0 10px; |
30 | 28 |
} |
31 | 29 | |
32 |
ul.announces { |
|
33 |
margin: 0; |
|
34 |
padding: 0; |
|
35 |
} |
|
36 | ||
37 |
ul.announces li, ul.auth li, #management ul li { |
|
30 |
ul.auth li { |
|
38 | 31 |
list-style-type: none; |
39 | 32 |
padding: .1em .5em; |
40 | 33 |
} |
41 | 34 | |
42 |
li.bright { |
|
43 |
background: #fff; |
|
44 |
} |
|
45 | ||
46 |
li.bluesky { |
|
47 |
background: #d3d8e8 !important; |
|
48 |
} |
|
49 | ||
50 |
div.pub_time { |
|
51 |
float: right; |
|
52 |
font: bold Arial .8em; |
|
53 |
} |
|
54 | ||
55 | 35 |
div.clear { |
56 | 36 |
clear: both; |
57 | 37 |
} |
58 | 38 | |
59 |
ul.pagination { |
|
60 |
font-size: .8em; |
|
61 |
margin: 0; |
|
62 |
padding: 0; |
|
63 |
} |
|
64 | ||
65 |
#management ul.pagination li { |
|
66 |
display: inline; |
|
67 |
margin: 0 2px; |
|
68 |
} |
|
69 | ||
70 |
ul.pagination li.current { |
|
71 |
border: 0; |
|
72 |
} |
|
73 | ||
74 |
ul.pagination a { |
|
75 |
color: #000; |
|
76 |
} |
|
77 | ||
78 |
ul.pagination li.next a:before { |
|
79 |
content: '\f105'; |
|
80 |
} |
|
81 | ||
82 |
ul.pagination li.prev a:before { |
|
83 |
content: '\f104'; |
|
84 |
} |
|
85 | ||
86 | 39 |
ul.auth { |
87 | 40 |
border-radius: .2em; |
88 | 41 |
-moz-border-radius: .2em; |
... | ... | |
142 | 95 |
margin-left: .4em; |
143 | 96 |
} |
144 | 97 | |
145 |
#management { |
|
146 |
margin: 1em 0 .5em 0; |
|
147 |
} |
|
148 | ||
149 |
#management ul { |
|
150 |
margin: 1em 0 0 0; |
|
151 |
padding: 0; |
|
152 |
} |
|
153 | 98 | |
154 | 99 |
#management ul li { |
155 | 100 |
padding: 5px; |
156 |
border: 1px solid #aaa; |
|
157 |
background: #eee; |
|
158 |
margin:2px 0; |
|
159 |
border-radius: .3em; |
|
160 |
position: relative; |
|
161 |
} |
|
162 | ||
163 |
#management h4 { |
|
164 |
margin: .4em 0; |
|
165 |
} |
|
166 | ||
167 |
.title { |
|
168 |
font-size: .9em; |
|
169 |
font-weight: bold; |
|
170 | 101 |
} |
171 | 102 | |
172 |
.preview {
|
|
173 |
padding-left: 10px;
|
|
174 |
font-size: .8em;
|
|
175 |
color: #777;
|
|
103 |
ul.objects-list.single-links li .actions a {
|
|
104 |
color: #999;
|
|
105 |
display: inline;
|
|
106 |
padding: 0;
|
|
176 | 107 |
} |
177 | 108 | |
178 |
.actions { |
|
179 |
position: absolute; |
|
180 |
top: 2px; |
|
181 |
right: 5px; |
|
109 |
.actions a:hover { |
|
110 |
color: #333; |
|
182 | 111 |
} |
183 | 112 | |
184 | 113 |
.status { |
... | ... | |
190 | 119 |
width: 20px; |
191 | 120 |
} |
192 | 121 | |
193 |
.edit:before { |
|
194 |
content: '\f044'; |
|
195 |
} |
|
196 | ||
197 |
.delete:before { |
|
198 |
content: '\f1f8'; |
|
199 |
} |
|
200 | ||
201 | 122 |
.status .icon { |
202 | 123 |
color: #888; |
124 |
font-size: 0.9em; |
|
203 | 125 |
} |
204 | 126 | |
205 | 127 |
.status .published:before { |
... | ... | |
220 | 142 |
} |
221 | 143 | |
222 | 144 |
#management .datetime { |
223 |
width: 15%; |
|
224 |
float: right; |
|
225 |
margin-right: 35px; |
|
145 |
position: absolute; |
|
146 |
top: 3px; |
|
147 |
right: 0; |
|
148 |
width: 25%; |
|
226 | 149 |
} |
227 | 150 | |
228 | 151 |
.empty { |
... | ... | |
232 | 155 |
margin: 0 auto; |
233 | 156 |
} |
234 | 157 | |
235 |
.categories { |
|
236 |
float: right; |
|
237 |
} |
|
238 | ||
239 |
.categories select { |
|
240 |
border: 1px solid #aaa; |
|
241 |
display: inline; |
|
242 |
} |
|
243 | ||
244 |
.categories a, #management > span a { |
|
245 |
color: #000; |
|
246 |
padding: 1px 3px; |
|
247 |
margin: 0; |
|
248 |
font-weight: bold; |
|
249 |
font-size: .75em; |
|
250 |
} |
|
251 | ||
252 |
a.add:before { |
|
253 |
content: '\f067'; |
|
254 |
padding-right:3px; |
|
255 |
} |
|
256 | ||
257 | 158 |
form ul li { |
258 | 159 |
list-style-type: none; |
259 | 160 |
margin: 5px 0; |
260 | 161 |
} |
261 | 162 | |
262 |
li.datetime:after { |
|
263 |
margin-left: 5px; |
|
264 |
font-family: FontAwesome; |
|
265 |
content: '\f073'; |
|
266 |
color: #555; |
|
267 |
} |
|
268 | ||
269 | 163 |
form ul li label { |
270 | 164 |
display: block; |
271 | 165 |
} |
272 | 166 | |
273 |
#id_transport_channel li, #id_transport_channel label { |
|
274 |
display: inline; |
|
275 |
} |
|
276 | ||
277 | 167 |
.content { |
278 | 168 |
width: 50%; |
279 | 169 |
margin: auto; |
... | ... | |
283 | 173 |
background: #e6db74; |
284 | 174 |
border: 1px solid #aaa; |
285 | 175 |
padding: 5px; |
286 |
} |
|
287 | ||
288 |
.info { |
|
289 |
background: #a6e22e; |
|
290 |
border: 1px solid #aaa; |
|
291 |
padding: 5px; |
|
292 |
} |
|
176 |
} |
corbo/templates/corbo/announce_confirm_delete.html | ||
---|---|---|
1 | 1 |
{% extends "corbo/manage.html" %} |
2 | 2 |
{% load i18n %} |
3 |
{% block appbar %} |
|
4 |
{% endblock %} |
|
3 | 5 |
{% block content %} |
4 | 6 |
<form method="post"> |
5 | 7 |
<p> |
corbo/templates/corbo/announce_form.html | ||
---|---|---|
1 | 1 |
{% extends "corbo/manage.html" %} |
2 | 2 |
{% load i18n %} |
3 | 3 | |
4 |
{% block breadcrumb %} |
|
5 |
{{ block.super }} |
|
6 |
{% if category %} |
|
7 |
<a href='{% url "view_category" pk=category.pk %}'>{{ category }}</a> |
|
8 |
{% endif %} |
|
9 |
{% endblock %} |
|
10 | ||
4 | 11 |
{% block appbar %} |
5 | 12 |
{% if object %} |
6 |
<h2>{% trans "Modify Announce" %}</h2> |
|
13 |
<h2>{% trans "Edit Announce" %}</h2> |
|
14 |
<a href='{% url "delete_announce" pk=object.pk %}' rel='popup'>{% trans 'Delete' %}</a> |
|
7 | 15 |
{% else %} |
8 |
<h2>{% trans "New Announce" %}</h2>
|
|
16 |
<h2>{% trans "New Announce" %}</h2> |
|
9 | 17 |
{% endif %} |
18 |
</h2> |
|
19 | ||
10 | 20 |
{% endblock %} |
11 | 21 | |
12 | 22 |
{% block content %} |
corbo/templates/corbo/category_confirm_delete.html | ||
---|---|---|
1 | 1 |
{% extends "corbo/manage.html" %} |
2 | 2 |
{% load i18n %} |
3 |
{% block appbar %} |
|
4 |
{% endblock %} |
|
3 | 5 |
{% block content %} |
4 | 6 |
<form method="post"> |
5 | 7 |
{% csrf_token %} |
corbo/templates/corbo/category_detail.html | ||
---|---|---|
1 |
{% extends 'corbo/manage.html' %} |
|
2 |
{% load i18n %} |
|
3 | ||
4 |
{% block appbar %} |
|
5 |
<h2>{{ object.name }}</h2> |
|
6 |
<a href="{% url 'delete_category' object.id %}" rel="popup">{% trans 'Delete' %}</a> |
|
7 |
<a href="{% url 'edit_category' object.id %}" rel="popup">{% trans 'Rename' %}</a> |
|
8 |
<a href="{% url 'add_announce_for_category' pk=object.pk %}">{% trans 'New announce' %}</a> |
|
9 |
{% endblock %} |
|
10 | ||
11 |
{% block content %} |
|
12 |
<div id="management"> |
|
13 |
<ul class='objects-list single-links'> |
|
14 |
{% for announce in announces %} |
|
15 |
<li> |
|
16 |
<div class="status"> |
|
17 |
{% if announce.is_published %} |
|
18 |
<span class="icon published" title="{% trans "published" %}"></span> |
|
19 |
{% endif %} |
|
20 |
{% if not announce.is_published %} |
|
21 |
{% if announce.is_expired %} |
|
22 |
<span class="icon expired" title="{% trans "expired" %}"></span> |
|
23 |
{% else %} |
|
24 |
<span class="icon unpublished" title="{% trans "not published yet" %}"></span> |
|
25 |
{% endif %} |
|
26 |
{% endif %} |
|
27 |
</div> |
|
28 |
<a href="{% url 'edit_announce' announce.id %}">{{ announce.title }}</a> |
|
29 |
<div class="datetime"> |
|
30 |
{% blocktrans with mtime=announce.mtime|date:'DATETIME_FORMAT' %} |
|
31 |
Modified on {{ mtime }} |
|
32 |
{% endblocktrans %} |
|
33 |
</div> |
|
34 |
</li> |
|
35 |
{% empty %} |
|
36 |
<div class="empty"> |
|
37 |
{% trans "No announces yet." %} |
|
38 |
</div> |
|
39 |
{% endfor %} |
|
40 |
</ul> |
|
41 |
{% endblock %} |
corbo/templates/corbo/manage.html | ||
---|---|---|
1 | 1 |
{% extends 'corbo/base.html' %} |
2 |
{% load i18n static %} |
|
3 |
{% block page-title %} |
|
4 |
{{ block.super }} :: {% trans "Management" %} |
|
5 |
{% endblock %} |
|
6 | ||
2 |
{% load i18n %} |
|
7 | 3 | |
4 |
{% block appbar %} |
|
5 |
<h2>{% trans "Categories" %}</h2> |
|
6 |
<a href="{% url 'add_category' %}" rel='popup'>{% trans 'New category' %}</a> |
|
7 |
<a href="{% url 'add_announce' %}">{% trans 'New announce' %}</a> |
|
8 |
{% endblock %} |
|
8 | 9 | |
9 | 10 |
{% block content %} |
10 |
<div class="categories"> |
|
11 |
<span class="title">{% trans "Category:" %}</span> |
|
12 |
<select> |
|
13 |
<option value=''>{% trans "All" %}</option> |
|
14 |
{% for category in categories %} |
|
15 |
<option value='{{ category.id }}'{% if category_id == category.id %} selected{% endif %}>{{ category }}</option> |
|
16 |
{% endfor %} |
|
17 |
</select> |
|
18 |
<span> |
|
19 |
{% if category_id %} |
|
20 |
<a class="icon edit" href="{% url "edit_category" category_id %}" rel="popup" title="{% trans "edit category" %}"></a> |
|
21 |
<a class="icon delete" href="{% url "delete_category" category_id %}" rel="popup" title="{% trans "delete category" %}"></a> |
|
22 |
{% endif %} |
|
23 |
<a class="icon add" href="{% url "add_category" %}" rel="popup" title="{% trans "add category" %}"></a></span> |
|
24 |
</div> |
|
25 | 11 |
<div id="management"> |
26 |
<h4>{% trans "Announces" %}</h4> |
|
27 |
<span><a class="icon add" href="{% url "add_announce" %}">{% trans "add announce" %}</a></span> |
|
28 |
<ul> |
|
29 |
{% for obj in object_list %} |
|
30 |
<li class='{% cycle 'bluesky' '' %}'> |
|
31 |
<div class="status"> |
|
32 |
{% if obj.is_published %} |
|
33 |
<span class="icon published" title="{% trans "published" %}"></span> |
|
34 |
{% endif %} |
|
35 |
{% if not obj.is_published %} |
|
36 |
{% if obj.is_expired %} |
|
37 |
<span class="icon expired" title="{% trans "expired" %}"></span> |
|
38 |
{% else %} |
|
39 |
<span class="icon unpublished" title="{% trans "not published yet" %}"></span> |
|
40 |
{% endif %} |
|
41 |
{% endif %} |
|
42 |
</div> |
|
43 |
<div class="preview datetime"> |
|
44 |
{% blocktrans with mtime=obj.mtime|date:'DATETIME_FORMAT' %} |
|
45 |
Modified on {{ mtime }} |
|
46 |
{% endblocktrans %} |
|
47 |
</div> |
|
48 |
<div class="actions"> |
|
49 |
<span><a class="icon edit" href="{% url 'edit_announce' obj.id %}"></a></span> |
|
50 |
<span><a class="icon delete" href="{% url 'delete_announce' obj.id %}" rel="popup"></a></span> |
|
51 |
</div> |
|
52 |
<div class="announce"> |
|
53 |
<div class="title">{{ obj.title }}</div> |
|
54 |
<div class="preview">{{ obj.text|safe|truncatechars_html:128 }}</div> |
|
55 |
</div> |
|
56 |
</li> |
|
57 |
{% empty %} |
|
58 |
<div class="empty"> |
|
59 |
{% trans "No announces matching this category" %} |
|
60 |
</div> |
|
61 |
{% endfor %} |
|
62 |
</ul> |
|
63 | ||
64 |
{% if is_paginated %} |
|
65 |
<ul class="pagination"> |
|
66 |
{% if page_obj.has_previous %} |
|
67 |
<li class="prev"> |
|
68 |
<a href="?{% if category_id %}category={{ category_id}}&{% endif %}page={{ page_obj.previous_page_number }}" class="icon"></a> |
|
69 |
</li> |
|
70 |
{% endif %} |
|
71 |
<li class="current"> |
|
72 |
page {{ page_obj.number }} of {{ paginator.num_pages }} |
|
73 |
</li> |
|
74 |
{% if page_obj.has_next %} |
|
75 |
<li class="next"> |
|
76 |
<a href="?{% if category_id %}category={{ category_id}}&{% endif %}page={{ page_obj.next_page_number }}" class="icon"></a> |
|
77 |
</li> |
|
78 |
{% endif %} |
|
79 |
</ul> |
|
80 |
{% endif %} |
|
12 |
<ul class='objects-list single-links'> |
|
13 |
{% for obj in object_list %} |
|
14 |
<li class='category'> |
|
15 |
<a href="{% url 'view_category' pk=obj.id %}">{{ obj.name }} / |
|
16 |
{% blocktrans with creation_date=obj.ctime|date:"SHORT_DATETIME_FORMAT" %} |
|
17 |
created on {{ creation_date }} |
|
18 |
{% endblocktrans %} / |
|
19 |
{% blocktrans count announces_number=obj.get_announces_number %} |
|
20 |
{{ announces_number }} announce |
|
21 |
{% plural %} |
|
22 |
{{ announces_number }} announces |
|
23 |
{% endblocktrans %} / |
|
24 |
{% blocktrans count subscriptions_number=obj.get_subscriptions_number %} |
|
25 |
{{ subscriptions_number }} subscription |
|
26 |
{% plural %} |
|
27 |
{{ subscriptions_number }} subscriptions |
|
28 |
{% endblocktrans %} |
|
29 |
</a> |
|
30 |
</li> |
|
31 |
{% empty %} |
|
32 |
<div class="empty"> |
|
33 |
{% trans "No categories yet." %} |
|
34 |
</div> |
|
35 |
{% endfor %} |
|
36 |
</ul> |
|
81 | 37 |
</div> |
82 |
{% endblock %} |
|
83 | ||
84 |
{% block page-end %} |
|
85 |
<script type="text/javascript"> |
|
86 |
$(function() { |
|
87 |
$('div.categories select').on('change', function() { |
|
88 |
var category = $(this).val(); |
|
89 |
if (category) |
|
90 |
window.location.replace('{% url "manage" %}?category=' + category); |
|
91 |
else |
|
92 |
window.location.replace({% url "manage" %}); |
|
93 |
}) |
|
94 |
}) |
|
95 |
</script> |
|
96 |
{% endblock %} |
|
38 |
{% endblock %} |
corbo/views.py | ||
---|---|---|
6 | 6 |
from django.core import signing |
7 | 7 |
from django.core.urlresolvers import reverse |
8 | 8 |
from django.views.generic import CreateView, UpdateView, DeleteView, \ |
9 |
ListView, TemplateView, RedirectView |
|
9 |
ListView, TemplateView, RedirectView, \ |
|
10 |
DetailView |
|
10 | 11 |
from django.contrib.syndication.views import Feed |
11 | 12 |
from django.shortcuts import resolve_url |
12 | 13 |
from django.utils.encoding import force_text |
... | ... | |
54 | 55 |
template_name = 'corbo/announce_form.html' |
55 | 56 | |
56 | 57 |
def get_success_url(self): |
57 |
""" |
|
58 |
redirect to the category page of the new created announce |
|
59 |
""" |
|
60 |
return reverse('manage') + '?' + urlencode({'category': self.object.category.id}) |
|
58 |
return reverse('view_category', kwargs={'pk': self.object.category.pk}) |
|
61 | 59 | |
62 | 60 |
add_announce = AnnounceCreateView.as_view() |
63 | 61 | |
62 | ||
63 |
class AnnounceForCategoryCreateView(AnnounceCreateView): |
|
64 | ||
65 |
def get_initial(self): |
|
66 |
initial = super(AnnounceForCategoryCreateView, self).get_initial() |
|
67 |
initial['category'] = models.Category.objects.get(pk=self.kwargs['pk']) |
|
68 |
return initial |
|
69 | ||
70 |
def get_context_data(self, **kwargs): |
|
71 |
context = super(AnnounceForCategoryCreateView, self).get_context_data(**kwargs) |
|
72 |
context['category'] = kwargs['form'].initial['category'] |
|
73 |
return context |
|
74 | ||
75 |
add_announce_for_category = AnnounceForCategoryCreateView.as_view() |
|
76 | ||
77 | ||
64 | 78 |
class AnnounceEditView(UpdateView): |
65 | 79 |
model = models.Announce |
66 | 80 |
form_class = AnnounceForm |
67 | 81 | |
82 |
def get_context_data(self, **kwargs): |
|
83 |
context = super(AnnounceEditView, self).get_context_data(**kwargs) |
|
84 |
category_id = kwargs['form'].initial['category'] |
|
85 |
context['category'] = models.Category.objects.get(pk=category_id) |
|
86 |
return context |
|
87 | ||
68 | 88 |
def get_success_url(self): |
69 |
return reverse('manage') + '?' + urlencode({'category': self.object.category.id})
|
|
89 |
return reverse('view_category', kwargs={'pk': self.object.category.pk})
|
|
70 | 90 | |
71 | 91 |
edit_announce = AnnounceEditView.as_view() |
72 | 92 | |
... | ... | |
74 | 94 |
model = models.Announce |
75 | 95 | |
76 | 96 |
def get_success_url(self): |
77 |
return self.request.META['HTTP_REFERER'] or \ |
|
78 |
reverse('manage') + '?' + urlencode({'category': self.object.category.id}) |
|
97 |
return reverse('view_category', kwargs={'pk': self.object.category.pk}) |
|
79 | 98 | |
80 | 99 |
delete_announce = AnnounceDeleteView.as_view() |
81 | 100 | |
... | ... | |
92 | 111 | |
93 | 112 |
add_category = CategoryCreateView.as_view() |
94 | 113 | |
114 | ||
95 | 115 |
class CategoryEditView(UpdateView): |
96 | 116 |
form_class = CategoryForm |
97 | 117 |
model = models.Category |
98 | 118 | |
99 | 119 |
def get_success_url(self): |
100 |
return self.request.META['HTTP_REFERER'] or \ |
|
101 |
reverse('manage') + '?' + urlencode({'category': self.object.id}) |
|
120 |
return reverse('view_category', kwargs={'pk': self.object.pk}) |
|
102 | 121 | |
103 | 122 |
edit_category = CategoryEditView.as_view() |
104 | 123 | |
124 | ||
125 |
class CategoryView(DetailView): |
|
126 |
model = models.Category |
|
127 | ||
128 |
def get_context_data(self, **kwargs): |
|
129 |
context = super(CategoryView, self).get_context_data(**kwargs) |
|
130 |
context['announces'] = self.object.announce_set.all() |
|
131 |
return context |
|
132 | ||
133 |
view_category = CategoryView.as_view() |
|
134 | ||
135 | ||
105 | 136 |
class CategoryDeleteView(DeleteView): |
106 | 137 |
model = models.Category |
107 | 138 | |
... | ... | |
135 | 166 | |
136 | 167 | |
137 | 168 |
class ManageView(ListView): |
138 |
paginate_by = settings.ANNOUNCES_PER_PAGE |
|
139 | 169 |
template_name = 'corbo/manage.html' |
140 |
model = models.Announce |
|
141 | ||
142 |
def get_queryset(self): |
|
143 |
queryset = super(ManageView, self).get_queryset() |
|
144 |
if self.request.GET.get('category'): |
|
145 |
queryset = queryset.filter(category__id=self.request.GET['category']) |
|
146 |
return queryset |
|
147 | ||
148 |
def get_context_data(self, **kwargs): |
|
149 |
context = super(ManageView, self).get_context_data(**kwargs) |
|
150 |
context['categories'] = models.Category.objects.all().order_by('-ctime') |
|
151 |
if self.request.GET.get('category'): |
|
152 |
try: |
|
153 |
context['category_id'] = int(self.request.GET['category']) |
|
154 |
except: |
|
155 |
pass |
|
156 |
return context |
|
170 |
model = models.Category |
|
157 | 171 | |
158 | 172 |
manage = ManageView.as_view() |
159 | 173 | |
174 | ||
160 | 175 |
class Atom1Feed(DjangoAtom1Feed): |
161 | 176 |
def root_attributes(self): |
162 | 177 |
attrs = super(Atom1Feed, self).root_attributes() |
163 |
- |