Django - Как отобразить ModelForm с полем Select, указав отключенный вариант?

У меня есть следующие модели:

# Get or create a 'Not selected' category
def get_placeholder_categoy():
    category, _ = ListingCategories.objects.get_or_create(category='Not selected')
    return category


# Get default's category ID
def get_placeholder_category_id():
    return get_placeholder_categoy().id


class ListingCategories(models.Model):
    category = models.CharField(max_length=128, unique=True)
    
    def __str__(self):
        return f'{self.category}'


class Listing(models.Model):
    title = models.CharField(max_length=256)
    seller = models.ForeignKey(User, on_delete=models.CASCADE, related_name='listings')
    description = models.TextField(max_length=5120, blank=True)
    img_url = models.URLField(default='https://media.istockphoto.com/vectors/no-image-available-picture-coming-soon-missing-photo-image-vector-id1379257950?b=1&k=20&m=1379257950&s=170667a&w=0&h=RyBlzT5Jt2U87CNkopCku3Use3c_3bsKS3yj6InGx1I=')
    category = models.ForeignKey(ListingCategories, on_delete=models.CASCADE, default=get_placeholder_category_id, related_name='listings')
    creation_date = models.DateTimeField()
    base_price = models.DecimalField(max_digits=10, decimal_places=2, validators=[
        MinValueValidator(0.01),
        MaxValueValidator(99999999.99)
    ])

С ними я имею следующую форму:

class ListingForm(ModelForm):
    class Meta:
        model = Listing
        exclude = ['seller', 'creation_date']
        widgets = {
            'title': TextInput(attrs=base_html_classes),
            'description': Textarea(attrs=base_html_classes),
            'img_url': URLInput(attrs=base_html_classes),
            'category': Select(attrs=base_html_classes),
            'base_price': NumberInput(attrs=base_html_classes)
        }

Одной из доступных категорий у меня является "Не выбран", поскольку я хочу позволить, чтобы, если в какой-то момент категория будет удалена, элементы могли быть переназначены в эту категорию, однако, при выводе формы я сделаю некоторую проверку в функции представления, чтобы предотвратить ее отправку, если категория "Не выбран" будет отправлена вместе с формой.

Поэтому я хочу, чтобы HTML-форма в шаблоне присваивала атрибут 'disabled' опции, соответствующей этой категории, однако, я искал уже несколько дней, не найдя ничего, что я смог бы понять настолько, чтобы попробовать это сделать.

Идеально, еще одна вещь, которую я хотел бы достичь, это возможность изменять порядок отображаемых опций на форме так, чтобы я мог перемещать на верхнюю "не выбранную", независимо от ее первичного ключа в модели.

Я знаю, что могу просто создать форму вместо формы модели, или просто изменить шаблон, чтобы вручную указать, как отображать саму форму, но я чувствую, что есть простое решение для этого либо в модели, либо в форме модели, которое я пока не нашел.

Заранее спасибо!

Я бы предложил вам использовать (в определении модели)

class Listing(models.Model):
    ..
    category = model.ForeignKey(ListingCategories, on_delete=models.SET_NULL, null=True, related_name='listings')
    ..

и опционально в определении формы

class ListingForm(ModelForm):
    category = forms.ModelChoiceField(ListingCategories, empty_label='Not Selected')
    ..

При рендеринге формы модели атрибут required будет добавлен автоматически, а при валидации формы он также обязателен. Только при валидации базы данных поле можно оставить NULL

Вернуться на верх