I have a model have ForeignKey
and I want to use HTML <datalist>
in ModelForm.
But the value in <option>
should be key of ForeignKey
, not the __str__
or something else.
I can use label
for <option>
but, it rendered different by browser.
So, I tried to override clean
or clean_<fieldname>
method, but I don’t know how to handle input from there.
How can I intercept form input and fix it to correct value?
models.py
from django.conf import settings
from django.db import models
# Create your models here.
class Schedule(models.Model):
srl = models.BigAutoField(
primary_key=True,
verbose_name="Serial",
)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
verbose_name="User",
)
branch = models.ForeignKey(
"branches.Branch",
on_delete=models.CASCADE,
verbose_name="Branch",
)
date = models.DateField(
verbose_name="Date",
)
period = models.DecimalField(
max_digits=2,
decimal_places=0,
verbose_name="Period",
)
class Meta:
verbose_name = "Schedule"
verbose_name_plural = "Schedules"
ordering = [
"branch",
"date",
"period",
]
unique_together = [
"user",
"date",
"period",
]
def __str__(self):
if self.user.gender == "M":
gender_short = "M"
elif self.user.gender == "F":
gender_short = "F"
return f"{self.branch} {self.date.strftime('%y%m%d')} {self.period}th {self.user.name}{self.user.birthday.strftime('%y%m%d')}{gender_short}"
forms.py
import datetime
from django import forms
from django.forms import ModelChoiceField, ModelForm
from branches.models import Branch
from schedules.models import Schedule
from timetables.models import Timetable
from users.models import User
class ScheduleForm(ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user")
super(ScheduleForm, self).__init__(*args, **kwargs)
if self.user.superuser:
self.fields["branch"] = ModelChoiceField(
queryset=Branch.objects.all(),
required=True,
label="Branch",
widget=forms.Select(
attrs={
"class": "form-select",
}
),
)
else:
self.fields["branch"] = ModelChoiceField(
queryset=Branch.objects.filter(branch=self.user.branch),
required=True,
label="Branch",
widget=forms.Select(
attrs={
"class": "form-select",
}
),
)
def clean(self):
cleaned_data = super(ScheduleForm, self).clean()
user_input = cleaned_data["user"]
name = user_input.split(" ")[0]
user_info = user_input.split(" ")[1]
user_info = user_info.strip("()")
user_info = user_info.split("/")
branch = Branch.objects.get(name=user_info[0])
birthday = datetime.datetime.strptime(user_info[1], "%y%m%d")
if user_info[2] == "M":
gender = "M"
else:
gender = "F"
user = User.objects.get(
name=name,
birthday=birthday,
gender=gender,
branch=branch,
)
cleaned_data["user"] = user
return cleaned_data
class Meta:
model = Schedule
fields = (
"branch",
"user",
"date",
"period",
)
widgets = {
"user": forms.TextInput(
attrs={
"class": "form-control",
"list": "user-list",
},
),
"date": forms.DateInput(
attrs={
"type": "date",
"class": "form-control",
},
),
"period": forms.NumberInput(
attrs={
"class": "form-control",
"min": 1,
},
),
}
views.py
...
class ScheduleCreateView(LoginRequiredMixin, CreateView):
model = Schedule
form_class = ScheduleForm
success_url = reverse_lazy("schedules:list")
login_url = reverse_lazy("users:login")
def get_form_kwargs(self):
kwargs = super(ScheduleCreateView, self).get_form_kwargs()
kwargs.update({"user": self.request.user})
return kwargs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["page_title"] = "Add Schedule"
if self.request.user.superuser:
context["user_list"] = User.objects.all()
else:
context["user_list"] = User.objects.filter(branch=self.request.user.branch)
return context
I add print(locals())
to clean()
method after super().clean()
and there is no user
.
What’s the problem?