Reputation: 125
I have trying to filter objects in a model to avoid people putting events in their calendars which over lap. I found the below link which helped (Django form field clean to check if entered date is in a stored range). It has left me with another issue that it blocks any other user from having an event at the same time.
My Question is, can I pass the user id number to filter the queryset? it works if I manually input my user ID number?
Code below with my last attempt?
model.py
from django.db import models
from django.contrib.auth.models import User
class Event(models.Model):
manage = models.ForeignKey(User, on_delete=models.CASCADE, default=None)
title = models.CharField(max_length=200, default='free')
description = models.TextField()
start_time = models.DateTimeField()
end_time = models.DateTimeField()
def __str__(self):
return self.title + " - " + str(self.start_time) + " - " + str(self.end_time)
Form.py
from django import forms
from django.forms import ModelForm, DateInput
from calendar_app.models import Event
from django.contrib.auth.models import User
class EventForm(ModelForm):
class Meta:
model = Event
# datetime-local is a HTML5 input type, format to make date time show on fields
widgets = {
'start_time': DateInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M'),
'end_time': DateInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M'),
}
fields = ['title','description','start_time','end_time']
def __init__(self, *args, **kwargs):
super(EventForm, self).__init__(*args, **kwargs)
# input_formats parses HTML5 datetime-local input to datetime field
self.fields['start_time'].input_formats = ('%Y-%m-%dT%H:%M',)
self.fields['end_time'].input_formats = ('%Y-%m-%dT%H:%M',)
def clean(self):
form_start_time = self.cleaned_data.get('start_time')
form_end_time = self.cleaned_data.get('end_time')
form_manage = self.cleaned_data.get('manage')
between = Event.objects.filter(manage=form_manage, start_time__gte=form_start_time, end_time__lte=form_end_time)
if between:
raise forms.ValidationError('Already Calendar entry for this time')
super(EventForm,self).clean()
views.py
def event(request, event_id=None):
instance = Event()
if event_id:
instance = get_object_or_404(Event, pk=event_id)
else:
instance = Event()
form = EventForm(request.POST or None, instance=instance)
if request.POST and form.is_valid():
instance.manage = request.user
form.save()
return HttpResponseRedirect(reverse('calendar_app:calendar'))
return render(request, 'event.html', {'form': form})
Upvotes: 1
Views: 772
Reputation: 477794
You can make use of the manage_id
of the Event
object wrapped in the form:
class EventForm(ModelForm):
# …
def clean(self):
form_start_time = self.cleaned_data.get('start_time')
form_end_time = self.cleaned_data.get('end_time')
between = Event.objects.filter(
manage_id=self.instance.manage_id,
start_time__gte=form_start_time,
end_time__lte=form_end_time
)
if between.exists():
raise forms.ValidationError('Already Calendar entry for this time')
super().clean()
of course this only works if the Event
alreadh has a manage_id
, but that is not a problem, since we can add the primary key of the user if necessary. It is probably also safer to filter on the manage_id
in the get_object_or_404
to prevent users from editing each others events:
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
@login_required
def event(request, event_id=None):
instance = Event()
if event_id:
instance = get_object_or_404(Event, pk=event_id, manage_id=request.user.pk)
else:
instance = Event(manage_id=request.user.pk)
if request.method == 'POST':
form = EventForm(request.POST, request.FILES, instance=instance)
if form.is_valid():
form.save()
return redirect('calendar_app:calendar')
else:
form = EventForm(instance=instance)
return render(request, 'event.html', {'form': form})
Note: You can limit views to a view to authenticated users with the
@login_required
decorator [Django-doc].
Note: It is normally better to make use of the
settings.AUTH_USER_MODEL
[Django-doc] to refer to the user model, than to use theUser
model [Django-doc] directly. For more information you can see the referencing theUser
model section of the documentation.
Upvotes: 1