Add Category support for teams and events, including card images. Fixes #37

This commit is contained in:
Michael Hall 2018-02-26 23:03:56 -05:00
parent 7a577250b3
commit 9ff9b55692
17 changed files with 111 additions and 26 deletions

View file

@ -1,8 +1,9 @@
from django.contrib import admin from django.contrib import admin
from django.utils.safestring import mark_safe
# Register your models here. # Register your models here.
from .models.locale import Language, Continent, Country, SPR, City from .models.locale import Language, Continent, Country, SPR, City
from .models.profiles import UserProfile, Organization, Team, Member from .models.profiles import UserProfile, Organization, Team, Member, Category, Topic
from .models.search import Searchable from .models.search import Searchable
from .models.events import Place, Event, Attendee from .models.events import Place, Event, Attendee
@ -61,4 +62,13 @@ admin.site.register(Event, EventAdmin)
admin.site.register(Member) admin.site.register(Member)
admin.site.register(Attendee) admin.site.register(Attendee)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('name', 'image')
def image(self, obj):
return (mark_safe('<img src="%s" title="%s" height="64px" />' % (obj.img_url, obj.name)))
image.short_description = 'Image'
admin.site.register(Category, CategoryAdmin)
class TopicAdmin(admin.ModelAdmin):
list_display = ('name', 'category')
list_filter = ('category',)

View file

@ -150,7 +150,7 @@ class DateTimeWidget(forms.SplitDateTimeWidget):
class TeamForm(forms.ModelForm): class TeamForm(forms.ModelForm):
class Meta: class Meta:
model = Team model = Team
fields = ['name', 'description', 'city', 'web_url', 'tz'] fields = ['name', 'description', 'category', 'city', 'web_url', 'tz']
widgets = { widgets = {
'city': Lookup(source='/api/cities/', label='name'), 'city': Lookup(source='/api/cities/', label='name'),
} }
@ -162,7 +162,7 @@ class TeamForm(forms.ModelForm):
class NewTeamForm(forms.ModelForm): class NewTeamForm(forms.ModelForm):
class Meta: class Meta:
model = Team model = Team
fields = ['name', 'description', 'city', 'web_url', 'tz'] fields = ['name', 'description', 'category', 'city', 'web_url', 'tz']
widgets = { widgets = {
'city': Lookup(source='/api/cities/', label='name'), 'city': Lookup(source='/api/cities/', label='name'),
} }

View file

@ -1,4 +1,4 @@
# Generated by Django 2.0 on 2018-02-25 22:02 # Generated by Django 2.0 on 2018-02-27 02:10
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
@ -7,7 +7,7 @@ import django.db.models.deletion
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('events', '0008_add-team-description'), ('events', '0010_userprofile_send_notifications'),
] ]
operations = [ operations = [
@ -17,7 +17,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=256)), ('name', models.CharField(max_length=256)),
('description', models.TextField()), ('description', models.TextField()),
('img', models.URLField()), ('img_url', models.URLField()),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
@ -34,16 +34,6 @@ class Migration(migrations.Migration):
name='tags', name='tags',
field=models.CharField(blank=True, help_text='Comma-separates list of tags', max_length=128, null=True, verbose_name='Keyword Tags'), field=models.CharField(blank=True, help_text='Comma-separates list of tags', max_length=128, null=True, verbose_name='Keyword Tags'),
), ),
migrations.AlterField(
model_name='searchable',
name='venue_name',
field=models.CharField(blank=True, max_length=256),
),
migrations.AlterField(
model_name='userprofile',
name='avatar',
field=models.URLField(blank=True, max_length=150, null=True, verbose_name='Photo Image'),
),
migrations.AddField( migrations.AddField(
model_name='event', model_name='event',
name='topics', name='topics',
@ -51,8 +41,8 @@ class Migration(migrations.Migration):
), ),
migrations.AddField( migrations.AddField(
model_name='team', model_name='team',
name='categories', name='category',
field=models.ManyToManyField(blank=True, to='events.Category'), field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='events.Category'),
), ),
migrations.AddField( migrations.AddField(
model_name='team', model_name='team',

View file

@ -0,0 +1,28 @@
# Generated by Django 2.0 on 2018-02-27 03:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('events', '0011_auto_20180227_0210'),
]
operations = [
migrations.RemoveField(
model_name='event',
name='topics',
),
migrations.AddField(
model_name='searchable',
name='img_url',
field=models.URLField(default='https://gettogether.community/static/img/team_placeholder.png'),
preserve_default=False,
),
migrations.AlterField(
model_name='event',
name='tags',
field=models.CharField(blank=True, max_length=128, null=True, verbose_name='Keyword Tags'),
),
]

View file

@ -64,14 +64,12 @@ class Event(models.Model):
created_by = models.ForeignKey(UserProfile, on_delete=models.CASCADE) created_by = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
created_time = models.DateTimeField(help_text=_('the date and time when the event was created'), default=datetime.datetime.now, db_index=True) created_time = models.DateTimeField(help_text=_('the date and time when the event was created'), default=datetime.datetime.now, db_index=True)
tags = models.CharField(verbose_name=_("Keyword Tags"), help_text=_('Comma-separates list of tags'), blank=True, null=True, max_length=128) tags = models.CharField(verbose_name=_("Keyword Tags"), blank=True, null=True, max_length=128)
#image #image
#replies #replies
attendees = models.ManyToManyField(UserProfile, through='Attendee', related_name="attending", blank=True) attendees = models.ManyToManyField(UserProfile, through='Attendee', related_name="attending", blank=True)
topics = models.ManyToManyField('Topic', blank=True)
def get_absolute_url(self): def get_absolute_url(self):
return reverse('show-event', kwargs={'event_id': self.id, 'event_slug': self.slug}) return reverse('show-event', kwargs={'event_id': self.id, 'event_slug': self.slug})
@ -102,6 +100,10 @@ def update_event_searchable(event):
searchable.federation_node = origin_url searchable.federation_node = origin_url
searchable.federation_time = datetime.datetime.now() searchable.federation_time = datetime.datetime.now()
if event.team.category:
searchable.img_url = event.team.category.img_url
else:
searchable.img_url = "https://%s%s" % (site.domain, '/static/img/team_placeholder.png')
searchable.event_title = event.name searchable.event_title = event.name
searchable.group_name = event.team.name searchable.group_name = event.team.name
searchable.start_time = event.start_time searchable.start_time = event.start_time

View file

@ -157,7 +157,7 @@ class Team(models.Model):
members = models.ManyToManyField(UserProfile, through='Member', related_name="memberships", blank=True) members = models.ManyToManyField(UserProfile, through='Member', related_name="memberships", blank=True)
categories = models.ManyToManyField('Category', blank=True) category = models.ForeignKey('Category', on_delete=models.SET_NULL, blank=False, null=True)
topics = models.ManyToManyField('Topic', blank=True) topics = models.ManyToManyField('Topic', blank=True)
@property @property
@ -205,9 +205,17 @@ class Member(models.Model):
class Category(models.Model): class Category(models.Model):
name = models.CharField(max_length=256) name = models.CharField(max_length=256)
description = models.TextField() description = models.TextField()
img = models.URLField(blank=False, null=False) img_url = models.URLField(blank=False, null=False)
def __str__(self):
return self.name
class Topic(models.Model): class Topic(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=False, blank=False) category = models.ForeignKey(Category, on_delete=models.CASCADE, null=False, blank=False)
name = models.CharField(max_length=256) name = models.CharField(max_length=256)
description = models.TextField() description = models.TextField()
def __str__(self):
return self.name

View file

@ -8,6 +8,7 @@ import datetime
class Searchable(models.Model): class Searchable(models.Model):
event_url = models.URLField(primary_key=True, null=False, blank=False) event_url = models.URLField(primary_key=True, null=False, blank=False)
event_title = models.CharField(max_length=256, null=False, blank=False) event_title = models.CharField(max_length=256, null=False, blank=False)
img_url = models.URLField(null=False, blank=False)
location_name = models.CharField(max_length=256, null=False, blank=False) location_name = models.CharField(max_length=256, null=False, blank=False)
group_name = models.CharField(max_length=256, null=False, blank=False) group_name = models.CharField(max_length=256, null=False, blank=False)
venue_name = models.CharField(max_length=256, null=False, blank=True) venue_name = models.CharField(max_length=256, null=False, blank=True)

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

View file

@ -14,7 +14,11 @@
<div class="col-md-4"> <div class="col-md-4">
<div class="card mb-4 box-shadow"> <div class="card mb-4 box-shadow">
<div class="card-banner"> <div class="card-banner">
{% if event.team.category %}
<img class="card-img-top" src="{{event.team.category.img_url}}" alt="{{event.name}}">
{% else %}
<img class="card-img-top" src="{% static 'img/team_placeholder.png' %}" alt="{{event.name}}"> <img class="card-img-top" src="{% static 'img/team_placeholder.png' %}" alt="{{event.name}}">
{% endif %}
<p class="card-title">{{event.team.name}}</p> <p class="card-title">{{event.team.name}}</p>
</div> </div>
<div class="card-body"> <div class="card-body">

View file

@ -25,7 +25,11 @@
<div class="col-md-4"> <div class="col-md-4">
<div class="card mb-4 box-shadow"> <div class="card mb-4 box-shadow">
<div class="card-banner"> <div class="card-banner">
{% if event.team.category %}
<img class="card-img-top" src="{{event.team.category.img_url}}" alt="{{event.event_title}}">
{% else %}
<img class="card-img-top" src="{% static 'img/team_placeholder.png' %}" alt="{{event.event_title}}"> <img class="card-img-top" src="{% static 'img/team_placeholder.png' %}" alt="{{event.event_title}}">
{% endif %}
<p class="card-title">{{event.group_name}}</p> <p class="card-title">{{event.group_name}}</p>
</div> </div>
<div class="card-body"> <div class="card-body">
@ -57,7 +61,11 @@
<div class="col-md-4"> <div class="col-md-4">
<div class="card mb-4 box-shadow"> <div class="card mb-4 box-shadow">
<div class="card-banner"> <div class="card-banner">
{% if team.category %}
<img class="card-img-top" src="{{team.category.img_url}}" alt="{{team.name}}">
{% else %}
<img class="card-img-top" src="{% static 'img/team_placeholder.png' %}" alt="{{team.name}}"> <img class="card-img-top" src="{% static 'img/team_placeholder.png' %}" alt="{{team.name}}">
{% endif %}
<p class="card-title">{{team.name}}</p> <p class="card-title">{{team.name}}</p>
</div> </div>
<div class="card-body"> <div class="card-body">

View file

@ -30,6 +30,7 @@ $(document).ready(function(){
}); });
} }
}) })
$("#id_category").selectmenu();
$("#id_tz").selectmenu(); $("#id_tz").selectmenu();
}); });
</script> </script>

View file

@ -29,6 +29,7 @@ $(document).ready(function(){
}); });
} }
}) })
$("#id_category").selectmenu();
$("#id_tz").selectmenu(); $("#id_tz").selectmenu();
}); });

View file

@ -1,4 +1,9 @@
{% extends "get_together/base.html" %} {% extends "get_together/base.html" %}
{% load static %}
{% block styles %}
<link href="{% static 'css/bootstrap-album.css' %}" rel="stylesheet"/>
{% endblock %}
{% block content %} {% block content %}
{% if my_teams %} {% if my_teams %}
@ -7,14 +12,41 @@
<br/> <br/>
{% endif %} {% endif %}
<h4>All Teams</h4>
{% include "events/team_list.html" with teams_list=all_teams%}
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<br/> <br/>
<form action="{% url 'create-team' %}" method="get"> <form action="{% url 'create-team' %}" method="get">
<button type="submit" class="btn btn-primary">Start a Team</button> <button type="submit" class="btn btn-primary">Start a Team</button>
</form> </form>
{% endif %} {% endif %}
<h4>All Teams</h4>
<div class="fluid-container">
<div class="row">
{% for team in all_teams %}
<div class="col-md-4">
<div class="card mb-4 box-shadow">
<div class="card-banner">
{% if team.category %}
<img class="card-img-top" src="{{team.category.img_url}}" alt="{{team.name}}">
{% else %}
<img class="card-img-top" src="{% static 'img/team_placeholder.png' %}" alt="{{team.name}}">
{% endif %}
<p class="card-title">{{team.name}}</p>
</div>
<div class="card-body">
<p class="card-text"><strong><a class="card-link" href="{% url 'show-team' team.id %}">{{team.city}}</a></strong></p>
<div class="d-flex justify-content-between align-items-center">
<small class="text-muted">{{ team.members.count }} members</small>
<div class="btn-group">
<a class="btn btn-primary" href="{% url 'show-team' team.id %}">View</a></span>
</div>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %} {% endblock %}