首页 > 解决方案 > Django 传递用户 ID 来过滤模型

问题描述

我试图过滤模型中的对象,以避免人们将事件放在重叠的日历中。我发现以下链接有助于(Django 表单字段清理以检查输入的日期是否在存储范围内)。它给我留下了另一个问题,它阻止任何其他用户同时进行活动。

我的问题是,我可以通过用户 ID 号来过滤查询集吗?如果我手动输入我的用户 ID 号,它会起作用吗?

下面是我最后一次尝试的代码?

模型.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)

表格.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()

视图.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})

标签: pythondjango

解决方案


您可以使用包装在表单manage_id中的对象:Event

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()

当然,这仅在Eventalreadh 有 a时才有效manage_id,但这不是问题,因为我们可以在必要时添加用户的主键。manage_id在中过滤get_object_or_404以防止用户编辑彼此的事件可能也更安全:

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})

注意:您可以使用@login_required装饰器 [Django-doc]将视图限制为经过身份验证的用户的视图 。


注意:通常使用settings.AUTH_USER_MODEL[Django-doc]引用用户模型比直接使用User模型 [Django-doc]更好。有关更多信息,您可以查看文档的引用User模型部分


推荐阅读