Unverified Commit 1491549b authored by Daniella Joan Francisco's avatar Daniella Joan Francisco Committed by GitHub

Merge pull request #9 from avraiel/event_management

Event management
parents ceb0df7f dfc29402
from accounts import models as accounts from accounts import models as accounts
from django import forms from django import forms
from django.forms import ModelForm from django.forms import ModelForm, BaseModelFormSet, inlineformset_factory
from .models import Event from .models import Event, Promo
# class EventForm(forms.ModelForm):
# class Meta:
# model = Event
# fields = ["event_name", "event_datetime_start", "event_datetime_end", "event_organizer", "event_header", "last_time_bumped"]
class EventForm(ModelForm): class EventForm(ModelForm):
# event_name = forms.CharField(label='Event Name', max_length=150)
# event_datetime_start = forms.DateTimeField(label='Event Start Date and Time')
# event_datetime_end = forms.DateTimeField(label='Event End Date and Time')
# event_organizer = forms.ModelChoiceField(label='Event Organizer', queryset=accounts.CustomUser.objects.all())
# event_header = forms.ImageField(label='Event Header Photo')
# last_time_bumped = forms.DateTimeField(label='Last Time Bump')
class Meta: class Meta:
model = Event model = Event
fields = "__all__" fields = "__all__"
# fields = ["event_name", "event_datetime_start", "event_datetime_end",
# "event_organizer", "event_header", "last_time_bumped"]
# fields = ["event_datetime_start"]
widgets = { widgets = {
'event_datetime_start':forms.TextInput(attrs={'type':'datetime-local'}), 'event_datetime_start':forms.TextInput(attrs={'type':'datetime-local'}),
'event_datetime_end':forms.TextInput(attrs={'type':'datetime-local'}), 'event_datetime_end':forms.TextInput(attrs={'type':'datetime-local'}),
'last_time_bumped':forms.TextInput(attrs={'type':'datetime-local'}), 'last_time_bumped':forms.TextInput(attrs={'type':'datetime-local'}),
} }
class PromoForm(ModelForm):
model = Promo
fields = "__all__"
# Source for the whole formset integration:
# https://www.letscodemore.com/blog/django-inline-formset-factory-with-examples/
PromoFormSet = inlineformset_factory(
Event,
Promo,
form=PromoForm,
extra=1,
fields=['img'],
can_delete=True,
can_delete_extra=True
)
\ No newline at end of file
...@@ -8,24 +8,12 @@ from uuid import uuid4 ...@@ -8,24 +8,12 @@ from uuid import uuid4
# from datetime import timedelta # from datetime import timedelta
class Event(models.Model): class Event(models.Model):
def rename_image(path):
def wrapper(instance, filename):
ext = filename.split('.')[-1]
# get filename
if instance.pk:
filename = 'event{}header.{}'.format(instance.pk, ext)
else:
# set filename as random string
filename = '{}.{}'.format(uuid4().hex, ext)
# return the whole path to the file
return os.path.join(path, filename)
return wrapper
event_name = models.CharField(default='', max_length=150) event_name = models.CharField(default='', max_length=150)
event_description = models.TextField(default='', max_length=255)
event_datetime_start = models.DateTimeField(default=timezone.now, null=False) event_datetime_start = models.DateTimeField(default=timezone.now, null=False)
event_datetime_end = models.DateTimeField(default=None, null=True) event_datetime_end = models.DateTimeField(default=None, null=True)
event_organizer = models.ForeignKey(accounts.CustomUser, on_delete=models.CASCADE, related_name='events_organized') event_organizer = models.ForeignKey(accounts.CustomUser, on_delete=models.CASCADE, related_name='events_organized')
event_header = ResizedImageField(size=[815, 315], crop=['middle', 'center'], quality=75, force_format='WebP', upload_to=rename_image('headers/')) event_header = ResizedImageField(quality=75, force_format='WebP', upload_to='headers/')
last_time_bumped = models.DateTimeField() last_time_bumped = models.DateTimeField()
def __str__(self): def __str__(self):
...@@ -34,6 +22,9 @@ class Event(models.Model): ...@@ -34,6 +22,9 @@ class Event(models.Model):
def get_absolute_url(self): def get_absolute_url(self):
return reverse('event_management:event-details', kwargs={'pk': self.pk}) return reverse('event_management:event-details', kwargs={'pk': self.pk})
def get_update_url(self):
return reverse('event_management:event-update', kwargs={'pk': self.pk})
# def save(self, *args, **kwargs): # def save(self, *args, **kwargs):
# if self.event_datetime_end is None: # if self.event_datetime_end is None:
# self.event_datetime_end = self.event_datetime_start + timedelta(hours=1) # self.event_datetime_end = self.event_datetime_start + timedelta(hours=1)
...@@ -42,8 +33,18 @@ class Event(models.Model): ...@@ -42,8 +33,18 @@ class Event(models.Model):
# super(Event, self).save(*args, **kwargs) # super(Event, self).save(*args, **kwargs)
class Promo(models.Model): class Promo(models.Model):
img = models.ImageField(upload_to='images/', height_field=None, width_field=None, max_length=100, blank=True) event = models.ForeignKey(
event_name = models.ForeignKey(Event, on_delete=models.CASCADE) Event,
related_name="promos",
on_delete=models.CASCADE,
null=True)
img = ResizedImageField(quality=75, force_format='WebP', upload_to='promos/')
def __str__(self):
return self.event.event_name
def get_absolute_url(self):
return reverse('event_management:event-details', kwargs={'pk': self.pk})
class Comment(models.Model): class Comment(models.Model):
event_comment = models.TextField(default='', max_length=255) event_comment = models.TextField(default='', max_length=255)
......
...@@ -3,6 +3,14 @@ ...@@ -3,6 +3,14 @@
{% block title %}Widget's Forum{% endblock %} {% block title %}Widget's Forum{% endblock %}
{% block content %} {% block content %}
<img src="{{ object.event_header.url }}" width = '300'/> <img src="{{ object.event_header.url }}" width = '300'/>
<p><a href='{{ object.get_absolute_url }}'>{{ object }}</a></p> <p>{{ object }}</p>
<p>{{ object.event_organizer }}</p> <p>{{object.event_description}}</p>
<p>{{object.event_datetime_start}}</p>
<p>{{object.event_datetime_end}}</p>
<p>{{object.event_organizer }}</p>
<p>{{object.last_time_bumped}}</p>
{% for promo in object.promos.all %}
<img src="{{ promo.img.url }}"/>
{% endfor %}
<button type="button" onclick="location.href='{{ event.get_update_url }}'">Update</button>
{% endblock %} {% endblock %}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
{% load static %} {% load static %}
{% block title %}Widget's Forum{% endblock %} {% block title %}Widget's Forum{% endblock %}
{% block content %} {% block content %}
{{ form.non_field_errors }} <!-- {{ form.non_field_errors }}
{% for field in form %} {% for field in form %}
{% if field.errors %} {% if field.errors %}
<p>{{ field.label }} has the following errors:</p> <p>{{ field.label }} has the following errors:</p>
...@@ -18,10 +18,135 @@ ...@@ -18,10 +18,135 @@
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}
{% endfor %} {% endfor %} -->
<form enctype="multipart/form-data" method="post"> <form enctype="multipart/form-data" method="post">
{% csrf_token %} {% csrf_token %}
{{ form }} <!-- {{ form }} -->
<input type="submit" value="Save"/> <div class="card">
<div class="card-header card-header-secondary">
<h4 class="card-title">Add Event</h4>
</div>
{% for field in form %}
<div class="form-group card-body">
<label>{{field.label}}</label>
{% if field.field.required %}
<span style="color: red;" class="required">*</span>
{% endif %}
{{field}}
{% if field.help_text %}
<small style="color: grey">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</div>
{% endfor %}
</div>
{% with named_formsets.images as formset %}
{{ formset.management_form }}
<script type="text/html" id="images-template">
<tr id="images-__prefix__" class= hide_all>
{% for fields in formset.empty_form.hidden_fields %}
{{ fields }}
{% endfor %}
{% for fields in formset.empty_form.visible_fields %}
<td>{{ fields }}</td>
{% endfor %}
</tr>
</script>
<div class="table-responsive card mt-4">
<div class="card-header card-header-secondary">
<h4 class="card-title">Add Promotional Images</h4>
</div>
<table class="table card-body">
<thead class="text-secondary">
<th>Image <span style="color: red;" class="required">*</span></th>
<th>Delete?</th>
<th>Custom Delete btn</th>
</thead>
<tbody id="item-images"> <!-- id="item-inlineformsetname" -->
<!-- formset non forms errors -->
{% for error in formset.non_form_errors %}
<span style="color: red">{{ error }}</span>
{% endfor %}
{% for formss in formset %}
{{ formss.management_form }}
<tr id="images-{{ forloop.counter0 }}" class= hide_all> <!-- id="inlineformsetname-counter" -->
{{ formss.id }}
{% for field in formss.visible_fields %}
<td>
{{field}}
{% for error in field.errors %}
<span style="color: red">{{ error }}</span>
{% endfor %}
</td>
{% endfor %}
<!-- delete code -->
{% if formss.instance.pk %}
<td>
<button type="button" class="btn btn-danger" data-toggle="modal" data-target="#exampleModal{{formss.instance.pk}}">
Delete
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal{{formss.instance.pk}}" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel{{formss.instance.pk}}" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel{{formss.instance.pk}}">Are Your Sure You Want To Delete This?</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-footer">
<a href="{% url 'event_management:delete_image' formss.instance.pk %}" type="button" class="btn btn-primary">Yes, Delete</a>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
<a href="#" id="add-image-button" class="btn btn-secondary add-images">Add More</a> <!-- id="add-inlineformsetname-button" -->
</div>
{% endwith %}
<div class="form-group">
<button type="submit" class="btn btn-secondary btn-block">Submit</button>
</div>
</form> </form>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script>
$(document).ready(function() {
// when user clicks add more btn of images
$('.add-images').click(function(ev) {
ev.preventDefault();
var count = $('#item-images').children().length;
var tmplMarkup = $('#images-template').html();
var compiledTmpl = tmplMarkup.replace(/__prefix__/g, count);
$('#item-images').append(compiledTmpl);
// update form count
$('#id_images-TOTAL_FORMS').attr('value', count+1);
});
});
$(document).ready(function() {
// when user clicks add more btn of variants
$('.add-variants').click(function(ev) {
ev.preventDefault();
var count = $('#item-variants').children().length;
var tmplMarkup = $('#variants-template').html();
var compiledTmpl = tmplMarkup.replace(/__prefix__/g, count);
$('#item-variants').append(compiledTmpl);
// update form count
$('#id_variants-TOTAL_FORMS').attr('value', count+1);
});
});
</script>
{% endblock %} {% endblock %}
\ No newline at end of file
...@@ -13,4 +13,5 @@ ...@@ -13,4 +13,5 @@
</ul> </ul>
{% endfor %} {% endfor %}
</ul> </ul>
<button type="button" onclick="location.href='/events/add/'">Add Event</button>
{% endblock %} {% endblock %}
from django.urls import path from django.urls import path
from .views import EventListView, EventDetailView, EventCreateView, EventUpdateView from .views import EventListView, EventDetailView, EventCreateView, EventUpdateView, delete_image
urlpatterns = [ urlpatterns = [
path('', EventListView.as_view(), name='event-list'), path('', EventListView.as_view(), name='event-list'),
path('<int:pk>/details', EventDetailView.as_view(), name='event-details'), path('<int:pk>/details', EventDetailView.as_view(), name='event-details'),
path('add/', EventCreateView.as_view(), name='event-create'), path('add/', EventCreateView.as_view(), name='event-create'),
path('<int:pk>/update', EventUpdateView.as_view(), name='event-update'), path('<int:pk>/update', EventUpdateView.as_view(), name='event-update'),
path('int<pk>/delete-image', delete_image, name='delete_image'),
] ]
app_name = "event_management" app_name = "event_management"
\ No newline at end of file
...@@ -5,11 +5,53 @@ from django.views.generic.detail import DetailView ...@@ -5,11 +5,53 @@ from django.views.generic.detail import DetailView
from django.views.generic.list import ListView from django.views.generic.list import ListView
from django.views.generic.edit import CreateView, UpdateView from django.views.generic.edit import CreateView, UpdateView
from .forms import EventForm from .forms import (EventForm, PromoFormSet)
from .models import Event from .models import Event, Promo
def delete_image(request, pk):
try:
image = Promo.objects.get(id=pk)
except Promo.DoesNotExist:
messages.success(
request, 'Object Does not exist'
)
return redirect('event_management:event-update', pk=image.event.id)
image.delete()
messages.success(
request, 'Image deleted successfully'
)
return redirect('event_management:event-update', pk=image.event.id)
class PromoInline():
form_class = EventForm
template_name = 'event_management/event-form.html'
def form_valid(self, form):
named_formsets = self.get_named_formsets()
if not all((x.is_valid() for x in named_formsets.values())):
return self.render_to_response(self.get_context_data(form=form))
self.object = form.save()
for name, formset in named_formsets.items():
formset_save_func = getattr(self, 'formset_{0}_valid'.format(name), None)
if formset_save_func is not None:
formset_save_func(formset)
else:
formset.save()
return redirect('event_management:event-list')
def formset_images_valid(self, formset):
images = formset.save(commit=False)
for obj in formset.deleted_objects:
obj.delete()
for image in images:
image.event = self.object
image.save()
class EventDetailView(DetailView): class EventDetailView(DetailView):
model = Event model = Event
fields = '__all__'
template_name = 'event_management/event-details.html' template_name = 'event_management/event-details.html'
class EventListView(ListView): class EventListView(ListView):
...@@ -17,13 +59,43 @@ class EventListView(ListView): ...@@ -17,13 +59,43 @@ class EventListView(ListView):
fields = '__all__' fields = '__all__'
template_name = 'event_management/event-list.html' template_name = 'event_management/event-list.html'
class EventCreateView(CreateView): # class EventCreateView(CreateView):
# model = Event
# form_class = EventForm
# success_url = '/events/'
# template_name = 'event_management/event-form.html'
# class EventUpdateView(UpdateView):
# model = Event
# fields = '__all__'
# # success_url =
# template_name = 'event_management/event-form.html'
class EventCreateView(PromoInline, CreateView):
model = Event model = Event
form_class = EventForm def get_context_data(self, **kwargs):
success_url = '/events/' ctx = super(EventCreateView, self).get_context_data(**kwargs)
template_name = 'event_management/event-form.html' ctx['named_formsets'] = self.get_named_formsets()
return ctx
class EventUpdateView(UpdateView): def get_named_formsets(self):
if self.request.method == "GET":
return{
'images': PromoFormSet(prefix='images')
}
else:
return{
'images': PromoFormSet(self.request.POST or None, self.request.FILES or None, prefix='images')
}
class EventUpdateView(PromoInline, UpdateView):
model = Event model = Event
fields = '__all__' def get_context_data(self, **kwargs):
template_name = 'event_management/event-form.html' ctx = super(EventUpdateView, self).get_context_data(**kwargs)
\ No newline at end of file ctx['named_formsets'] = self.get_named_formsets()
return ctx
def get_named_formsets(self):
return {
'images': PromoFormSet(self.request.POST or None, self.request.FILES or None, instance=self.object, prefix='images'),
}
\ No newline at end of file
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