Django: установить параметры поля выбора модели для значений набора запросов и других значений - PullRequest
0 голосов
/ 22 декабря 2019

В приведенных ниже моделях Django

class Post(models.Model):
    author = models.ForeignKey(CustomUser, on_delete=models.CASCADE,)
    title = models.CharField(max_length=200, null=True)
    text = models.TextField()
    post_url = models.URLField(max_length = 200, blank=True)
    post_type = models.IntegerField()
    slug = models.SlugField(unique=True, blank=True)

class Tiers(models.Model):
    user = models.ForeignKey(CustomUser, default=None, null=True, on_delete=models.CASCADE,)
    tier_name = models.CharField(max_length=128, blank=True) 
    tier_value = models.IntegerField() 
    slug = models.SlugField(unique=True, blank=True)

Я хочу использовать модель поста для формы, подобной приведенной ниже

class PostForm(forms.ModelForm):
    class Meta:
        model = models.Post
        fields = ('title', 'text', 'post_url', 'post_type')

Но для поля post_type я хочуотобразить как выпадающий список с опциями моделей Tiers tier_value . Например, если user1 имеет 3 записи в модели Tiers с значениями tier_values ​​10, 20 и 30. Я хочу отобразить 4 варианта 0, 10, 20 и 30. Кто-нибудь может мне помочь, как этого добиться?

1 Ответ

0 голосов
/ 22 декабря 2019

Теоретически, вы можете переопределить FormField, который генерирует django . В этом случае вы могли бы использовать Выбор виджета для поля post_type.

Однако я думаю, что с вашим моделированием можно улучшить / нормализовать, и если это будет сделано, ваша проблемаразрешу. Рассмотрим следующие модели:

class Tier(models.Model):
    name = models.CharField(max_length=128, blank=True) 
    value = models.IntegerField() 
    slug = models.SlugField(unique=True, blank=True)

class CustomUser(...):
    tiers = models.ManyToManyField(Tier, related_name='users')
    ...

class Post(models.Model):
    author = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
    tier = models.ForeignKeyField(Tier)
    title = models.CharField(max_length=200, null=True)
    text = models.TextField()
    url = models.URLField(max_length = 200, blank=True)
    slug = models.SlugField(unique=True, blank=True)

Таким образом, вы, разные пользователи, можете иметь один и тот же уровень (что, вероятно, то, что вам нужно?) Без дублирования значений имени и уровня.

Теперь,когда вы создаете ModelForm с Post, он автоматически предоставит вам поле выбора для всех существующих уровней. Однако вы просто хотите иметь возможность выбирать уровни, в которых находится пользователь, поэтому для этого поля вы должны установить пользовательский queryset:

class PostForm(forms.ModelForm):
    def __init__(self, user, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['tier'].queryset = Tier.objects.filter(users__in=[user])

    class Meta:
        model = models.Post
        fields = ('title', 'text', 'url', 'tier')

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

max_tier_value = user.tiers.aggregate(Max('value')).value__max
self.fields['tier'].queryset = Tier.objects.filter(value__lte=max_tier_value)

Однако вы, вероятно, захотите сделать один из этих двух, но не оба:

  • Каждый пользователь назначается с уровнем уровня и может создавать сообщения с любым уровнем более низкого уровня.
  • Каждый пользователь назначается с несколькими уровнями уровня и может создавать сообщения только с этими уровнями.

Так, если вы идете с этим набором запросов, вы должны переделать так, чтобы CustomUser.tier был models.ForeignKey(Tier, related_name='users')

...