在Django的视图中定义时,如何使用表单的Select字段的选项?

lnlaulya  于 2023-05-23  发布在  Go
关注(0)|答案(1)|浏览(117)

我在使用Select输入的表单时遇到问题。此输入用于选择列表中的用户。列表应仅包含当前使用的组中的用户。
我找到了一个解决方案,但是我不完全确定我在表单定义中做了什么(我不完全理解def __init__部分是如何工作的)。当然,我的代码不起作用:我获得了正确的表单,并提供了所需的选项,但如果提交数据,则不会保存在数据库中。
我已经能够检查表格是否有效(它不是),错误如下:
类别-选择有效选项。该选项不是可用选项之一。
(我在用户字段中也有同样的错误)。我找不到我的方式在这一点上,所以如果你能帮助,将不胜感激!
我的模特:

class Group(models.Model):
    name = models.CharField(max_length=100)
    def __str__(self):
        return self.name   
    
class User(AbstractUser):
    groups = models.ManyToManyField(Group)
    current_group = models.ForeignKey(Group, on_delete=models.SET_NULL,blank = True , null = True, related_name="current_group")

class Category(models.Model):
    name = models.CharField(max_length=100)
    groups = models.ManyToManyField(Group)

    def __str__(self):
        return self.name

class Expanses(models.Model):
    date = models.DateTimeField()
    amount = models.DecimalField(decimal_places=2, max_digits=12)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    comment = models.CharField(max_length=500)
    
    def __str__(self):
        return self.amount

我的表格:

class CreateExpanseForm(forms.ModelForm):
    class Meta:
        model = Expanses
        fields = ['date', 'amount', 'category', 'user','comment']
        widgets={'date':DateInput(attrs={'placeholder':'Date', 'class':'form-input', 'type':'date'}),
                 'amount':TextInput(attrs={'placeholder':'Amount', 'class':'form-input', 'type':'text'}),
                 'category':Select(attrs={'placeholder':'Category', 'class':'form-select', 'type':'text'}),
                 'user':Select(attrs={'placeholder':'user', 'class':'form-select', 'type':'text'}),
                 'comment':TextInput(attrs={'placeholder':'comment', 'class':'form-input', 'type':'text'}),}
    
    def __init__(self, *args, **kwargs):
        user_choices = kwargs.pop('user_choices', None)
        category_choices = kwargs.pop('category_choices', None)
        
        super().__init__(*args, **kwargs)
        if user_choices:
            self.fields['user'].choices = user_choices
        if category_choices:
            self.fields['category'].choices = category_choices

我的看法:

def SummaryView(request):
    createExpanseForm = CreateExpanseForm(user_choices = [(user.username, user.username) for user in request.user.current_group.user_set.all()],
                                          category_choices = [(category.name, category.name) for category in request.user.current_group.category_set.all()])
    if request.method == "POST":
        if 'createExpanse' in request.POST:
            createExpanseForm = CreateExpanseForm(user_choices = [(user.username, user.username) for user in request.user.current_group.user_set.all()],
                                                  category_choices = [(category.name, category.name) for category in request.user.current_group.category_set.all()],
                                                  data=request.POST)
            if createExpanseForm.is_valid():
                expanse = createExpanseForm.save()
                if expanse is not None:
                    expanse.group = request.user.current_group
                    expanse.save()
                else:
                    messages.success(request, "Error!")
            
    context = {'createExpanseForm':createExpanseForm}
    return render(request, 'app/summary.html', context)
uoifb46i

uoifb46i1#

ForeignKey的表单字段是**ModelChoiceField**[Django-doc],这需要使用项目的主键,而不是类别的名称。因此,您尝试自己做太多的事情,从而使表单字段的数据无效。
我建议让表单来处理它,并在必要时指定查询集:

class CreateExpanseForm(forms.ModelForm):
    def __init__(self, *args, user=None, **kwargs):
        super().__init__(*args, **kwargs)
        if user is not None:
            self.fields['user'].queryset = user.current_group.user_set.all()
            self.fields[
                'category'
            ].queryset = user.current_group.category_set.all()

    class Meta:
        model = Expanses
        fields = ['date', 'amount', 'category', 'user', 'comment']
        widgets = {
            'date': DateInput(
                attrs={
                    'placeholder': 'Date',
                    'class': 'form-input',
                    'type': 'date',
                }
            ),
            'amount': TextInput(
                attrs={
                    'placeholder': 'Amount',
                    'class': 'form-input',
                    'type': 'text',
                }
            ),
            'category': Select(
                attrs={
                    'placeholder': 'Category',
                    'class': 'form-select',
                    'type': 'text',
                }
            ),
            'user': Select(
                attrs={
                    'placeholder': 'user',
                    'class': 'form-select',
                    'type': 'text',
                }
            ),
            'comment': TextInput(
                attrs={
                    'placeholder': 'comment',
                    'class': 'form-input',
                    'type': 'text',
                }
            ),
        }

在视图中,您可以只传递已登录的用户:

from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect

@login_required
def summary_view(request):
    form = CreateExpanseForm(user=request.user)
    if request.method == 'POST':
        if 'createExpanse' in request.POST:
            form = CreateExpanseForm(
                request.POST, request.FILES, user=request.user
            )
            if form.is_valid():
                form.instance.group = request.user.current_group
                expanse = createExpanseForm.save()
                return redirect('name-of-some-view')

    context = {'createExpanseForm': form}
    return render(request, 'app/summary.html', context)

注意:函数一般用 snake_case 编写,而不是 PascalCase,因此建议将函数重命名为summary_view,而不是SummaryView
注意:您可以通过**@login_requireddecorator [Django-doc]将视图限制为仅限认证用户的视图。
注意:如果POST请求成功,需要创建
redirect**[Django-doc]来实现Post/Redirect/Get pattern [wiki]。这样可以避免在用户刷新浏览器时发出相同的POST请求。

相关问题