Django CreateView передает текущий идентификатор пользователя в Modelform

#python #django

#python #django

Вопрос:

Я пытаюсь создать приложение для календаря и в настоящее время пытаюсь помешать людям сохранять событие, когда они уже заняты в течение этого периода времени. Я считаю, что моя проблема заключается в том, что в ModelForm нет идентификатора пользователя как части объекта формы. как я могу передать идентификатор пользователя, чтобы я мог использовать его для фильтрации с помощью clean().

Я пытался использовать get_form_kwargs(), но, похоже, это не правильный путь.

Пожалуйста, не могли бы вы указать мне правильное направление, как это сделать.

view.py

 class CalendarEventAdd(LoginRequiredMixin, CreateView):
    model = Event
    form_class = EventForm
    template_name = 'calendar_create_event_form.html' 
    success_url = reverse_lazy('calendar_list')

def form_valid(self, form):
    form.instance.manage = self.request.user
    return super(CalendarEventAdd, self).form_valid(form)

def get_form_kwargs(self, *args, **kwargs):
    kwargs = super(CalendarEventAdd, self).get_form_kwargs()
    kwargs['user_id'] = self.request.user
    return kwargs
  

form.py

 class EventForm(forms.ModelForm):

class Meta:
    model = Event
    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 = ['avilibility','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, *args, **kwargs):
    form_start_time = self.cleaned_data.get('start_time')
    form_end_time = self.cleaned_data.get('end_time')
    form_manage_id = self.cleaned_data.get('manage_id')
    between = Event.objects.filter(manage_id=1, end_time__gte=form_start_time, start_time__lte=form_end_time)
    if between:
        raise forms.ValidationError('Already Calendar entry for this time')
    super().clean()
  

model.py

 class Event(models.Model):

    avilibility_choices = [
    ('Avilible', 'Avilible'),
    ('Busy', 'Busy'),
]
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    manage = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
    avilibility = models.CharField(max_length=10, choices=avilibility_choices, editable=True)
    start_time = models.DateTimeField()
    end_time = models.DateTimeField()

    def __str__(self):
        return self.avilibility   " - "   str(self.start_time)   " - "   str(self.end_time)   " - "  str(self.id)

    def get_absolute_url(self):
        return reverse('calendar_event_detail', args=[str(self.id)])

    def get_absolute_url_edit(self):
        return reverse('calendar_event_detail_update', args=[str(self.id)])

    def get_html_url(self):
        url = reverse('event_edit', args=(self.id,))
        return f'<a href="{url}"> {self.avilibility} </a>'
  

Ответ №1:

По вашему мнению, вы должны передать первичный ключ пользователя, поэтому:

     def get_form_kwargs(self, *args, **kwargs):
        kwargs = super(CalendarEventAdd, self).get_form_kwargs()
        kwargs['user_id'] = self.request.user.pk
        return kwargs  

Вы можете сохранить его в EventForm объекте:

 class EventForm(forms.ModelForm):
    
    def __init__(self, *args, user_id=None, **kwargs):   
        super(EventForm, self).__init__(*args, **kwargs)
        self.user_id = user_id
        # 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, *args, **kwargs):
        form_start_time = self.cleaned_data.get('start_time')
        form_end_time = self.cleaned_data.get('end_time')
        form_manage_id = self.cleaned_data.get('manage_id')
        between = Event.objects.exclude(pk=self.instance.pk).filter(
            manage_id=self.user_id,
            end_time__gte=form_start_time,
            start_time__lte=form_end_time
        )
        if between.exists():
            raise forms.ValidationError('Already Calendar entry for this time')
        return super().clean()  

Объект, который .exclude(pk=self.instance.pk) вы редактируете, будет исключен, если позже вы решите использовать EventForm не только для создания, но и для обновления Event объекта.


В документации рекомендуется использовать AUTH_USER_MODEL параметр [Django-doc] вместо get_user_model() [Django-doc] . Это безопаснее, поскольку, если приложение аутентификации еще не загружено, в настройках все равно можно указать имя модели. Поэтому лучше написать:

 from django.conf import settings

class Event(models.Model):
    # …
    manage = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE
    )