Home > OS >  How to use queryset with distinct to avoid duplication value in label_from_instance?
How to use queryset with distinct to avoid duplication value in label_from_instance?

Time:02-15

I want to use queryset with distinct() to avoid duplication value in label_from_instance.

But then I have an error like below.

'str' object has no attribute 'name'

How could I use queryset with distinct() in label_from_instance?


Here are the code in forms.py:

from django.forms import ModelChoiceField


class NameChoiceField(ModelChoiceField):

    def label_from_instance(self, obj):
        return f'{obj.name}'
        

class MyModelForm(forms.ModelForm):
    code = NameChoiceField(queryset=MyModel.objects.all().values_list('name',flat=True).order_by('name').distinct())

python 3.8

Django 3.2

Mysql 5.7

CodePudding user response:

How could I use queryset with distinct() in label_from_instance?

You don't. Imagine that you use .distinct() and thus got unique names and a person selects an option "foo", if there are multiple MyModels with "foo" as name, then which one should be selected: by making a distinct, you thus "destroy" the way to backlink to the original item. The label should be sufficient to canonically specify what model item to use.

You should fix the problem at the other end: preventing that one can use multiple MyModels with the same name, you can mark the name field as unique and thus work with:

class MyModel(models.Model):
    name = models.CharField(max_length=128, unique=True)
    # …

It is also possible that items should be unique per user for example. In that case you construct a UniqueConstraint [Django-doc] with:

from django.conf import settings

class MyModel(models.Model):
    name = models.CharField(max_length=128)
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE
    )
    
    class Meta:
        constraints = [
            models.UniqueConstraint(fields=('name', 'user'), name='unique_name_per_user')
        ]

In that case you filter the queryset in the form with the user with:

class MyModelForm(forms.ModelForm):
    code = NameChoiceField(queryset=MyModel.objects.order_by('name'))

    def __init__(self, *args, user=None, **kwargs):
        super().__init__(*args, **kwargs)
        if user is not None:
            self.field['code'].queryset = MyModel.objects.filter(
                user=user
            ).order_by('name')

where you then construct the MyModelForm with MyModelForm(user=request.user) for example.

  • Related