简体   繁体   中英

Django ModelChoiceField get choice of connected user

I created a forms.ModelChoiceField that contains items on my database, but it show all the users' data. I only want to show data of the connected user! Thanks for helping.

PS: I don't need to create a models.Form because I don't want to edit or update the data.

views.py

def sms(request):
    form2 = ListDataForm()
    if request.method == 'POST':
        form2 = ListDataForm(request.POST)
        if form2.is_valid():
            message = form2.cleaned_data["message"]
            print(message)

    else:
        form2  = ListDataForm(request=request)
    return render(request, "data_list/sms.html", {"form2": form2})

models.py

class List(models.Model):
    item = models.CharField(max_length=100)
    content = models.TextField()
    site = models.CharField(max_length=11, choices=THE_SITE)
    content_list = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        return self.item

forms.py

class ListDataForm(forms.Form):

    message = forms.CharField(widget=forms.Textarea)
    listdata = forms.ModelChoiceField(queryset=List.objects.all())

Instead of forms.ModelChoiceField(queryset=List.objects.all()) I wrote forms.ModelChoiceField(queryset=List.objects.filter(author=request.user)) but it doesn't work.

  1. Use get_queryset

     class ListDataForm(forms.Form): message = forms.CharField(widget=forms.Textarea) listdata = forms.ModelChoiceField(queryset=get_queryset) def get_queryset(request): return List.objects.filter(author=request.user)
    1. Pass request as a argument when you will call Form.

       def your_view(request): ...YOUR LOGIC... form = ListDataForm(request) ...YOUR LOGIC...

The issue with your approach is that the queryset value is executed on class creation, that is, when you first fire up the Python interpreter and load all the Django stuff. The request object is not created here, but once you start getting requests from users.

As per the documentation , you can do it at class instantiation instead, setting the queryset parameter to None and writing

forms.py

class ListDataForm(forms.Form):
  ...
  listdata = forms.ModelChoiceField(queryset=None)
  ...

  def __init__(self, *args, **kwargs):
    request = kwargs.pop('request', None)
    super().__init__(*args, **kwargs)
    if request:
      user = request.user
      self.fields['listdata'].queryset = List.objects.filter(author=user)

Then, in your view, create this form as follows

views.py

def form_view(request):
  ...
  form = ListDataForm(request=request)
  ...

As per the documentation the correct way to restrict the queryset for ModelChoiceFields is as below.

# in your form
class ListDataForm(forms.Form):    
    message = forms.CharField(widget=forms.Textarea)
    listdata = forms.ModelChoiceField(queryset=List.objects.all())

def __init__(self, *args, user=None, **kwargs):
    super().__init__(*args, **kwargs)
    if user:
        listdata = self.fields['listdata']
        listdata.queryset = listdata.queryset.filter(author=user)


# in your view
...
form = ListDataForm(data, ..., user=request.user)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM