Filter queryset with multiple checks, including value_is_in array in a Django view

[亡魂溺海] 提交于 2021-02-08 07:37:22

问题


I need to check if a user exists before saving a form. The fields are name, surname, and a role which can have one or many values. How can I do that?

def save(self, commit=True):
        profile = super(ProfileForm, self).save(commit=False)
        first_name = self.cleaned_data['first_name']
        surname = self.cleaned_data['surname']
        role = self.cleaned_data['role']

        if Profile.objects.filter(first_name=self.cleaned_data['first_name'], surname=self.cleaned_data['surname']).exists()
            raise forms.ValidationError("This profile already exists")

        elif commit:
            profile.save()

Profile.objects.filter(first_name=self.cleaned_data['first_name'], surname=self.cleaned_data['surname'], role__in[role]).exists() gives me invalid syntax error. Of course I want to check if name & surname & role are all present within the same profile.

My models

class Role(models.Model):
    type= models.CharField(max_length=30)
    def __str__(self):
        return self.type

class Profile(models.Model):
    first_name = models.CharField(max_length=120, null=True, blank=True)
    surname = models.CharField(max_length=120, null=True, blank=True)
    role = models.ManyToManyField(Role, blank=True)

回答1:


Pleasde do not check this in the form, you can check this in the model. Indeed, you can implement this with a UniqueConstraint [Django-doc]:

class Profile(models.Model):
    first_name = models.CharField(max_length=128)
    surname = models.CharField(max_length=128)
    role = models.CharField(max_length=128)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                field=['first_name', 'last_name', 'role'],
                name='unique_name_and_role'
            )
        ]

The validation is done automatically in the ModelForm, so no need to worry about that, and this will also be enforced at the database level (if your database supports that).

Prior to django-2.2, you can specify unique_together [Djanog-doc]:

class Profile(models.Model):
    first_name = models.CharField(max_length=128)
    surname = models.CharField(max_length=128)
    role = models.CharField(max_length=128)

    class Meta:
        unique_together = [['first_name', 'last_name', 'role']]

In case it is a ManyToManyField, you better enforce this at the .clean(..) method of the Profile model:

class ProfileForm(forms.ModelForm):

    # …

    def clean(self):
        cleaned_data = super().clean()
        first_name = self.cleaned_data['first_name']
        surname = self.cleaned_data['surname']
        role = self.cleaned_data['role']
        if Profile.objects.exclude(pk=self.instance.pk).filter(
            first_name=first_name,
            surname=surname,
            role__in=role
        ).exists():
            raise ValidationError('A profile already exists.')
        return cleaned_data

In the view, you can then for example handle this with:

def my_view(request):
    if request.method == 'POST':
        form = ProfileForm(request.POST, request.FILES)
        if form.is_valid():
            # …
        else:
            return HttpResponseBadRequest('invalid data')
    # …



回答2:


invalid syntax is because of missing '=' sign after __in. It should be something like below

Profile.objects.filter(first_name=self.cleaned_data['first_name'], surname=self.cleaned_data['surname'], role__in=self.cleaned_data[role]).exists()


来源:https://stackoverflow.com/questions/61826009/filter-queryset-with-multiple-checks-including-value-is-in-array-in-a-django-vi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!