【问题标题】:Pass user's primary key (pk) from previous page to current page将用户的主键 (pk) 从上一页传递到当前页
【发布时间】:2017-11-10 18:36:17
【问题描述】:

我正在构建一个评论页面,一个讨厌的用户在用户页面上留下评论(我的用户称为代理)。 Review 模型有一个 agent 字段,指定与 Agent 的 ForeignKey 关系。

网址

url(r'^(?P<pk>\d+)/review/$', views.leave_review, name='leave_review'),

进入 leave_review 页面的 HTML 代码:

<form action="{% url 'leave_review' pk=agent.pk %}" method="post">
    {% csrf_token %}
    <button class="button3"><span>Leave review</span></button>
</form>

留下评论views.py

def leave_review(request, pk):
    if request.method == 'POST':

        form = ReviewForm(request.POST)

        if form.is_valid():
            form.agent = Agent.objects.get(pk=pk)
            form.save()
            return redirect('review_success.html')
    else:
        form = ReviewForm()

    return render(request, 'leave_review.html', {'form': form})

models.py

class Review(models.Model):
    # ... Other fields

    agent = models.ForeignKey(Agent, on_delete=models.CASCADE)

    def save(self, *args, **kwargs):
        if self.agent is None:  # Set default reference
            self.agent = Agent.objects.get(id=1)
        super(Review, self).save(*args, **kwargs)

我目前收到一个 ValueError,Cannot assign "''": "Review.agent" must be a "Agent" instance. 我相信在这种情况下我正确指定了“pk”,但它没有被拾取。这里有什么问题?

完整引用

Environment:


Request Method: POST
Request URL: http://localhost:8000/agents/2/review/?csrfmiddlewaretoken=CIxNqtEaFjFIfVwmB6SyV2SAF1VuiDgEf3Di7qZoucG4thIn9ixCbe7GO2UuuW85

Django Version: 1.11.5
Python Version: 3.6.2
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.sites',
 'bungol.accounts',
 'bungol.databases',
 'bungol.coresite',
 'bungol.listings',
 'django_extensions',
 'djstripe']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback:

File "C:\Python 3.6.2 (32bit)\lib\site-packages\django\core\handlers\exception.py" in inner
  41.             response = get_response(request)

File "C:\Python 3.6.2 (32bit)\lib\site-packages\django\core\handlers\base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "C:\Python 3.6.2 (32bit)\lib\site-packages\django\core\handlers\base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Users\Valachio\Google Drive\Bungol\bungolv4\bungol\databases\views.py" in leave_review
  69.         if form.is_valid():

File "C:\Python 3.6.2 (32bit)\lib\site-packages\django\forms\forms.py" in is_valid
  183.         return self.is_bound and not self.errors

File "C:\Python 3.6.2 (32bit)\lib\site-packages\django\forms\forms.py" in errors
  175.             self.full_clean()

File "C:\Python 3.6.2 (32bit)\lib\site-packages\django\forms\forms.py" in full_clean
  386.         self._post_clean()

File "C:\Python 3.6.2 (32bit)\lib\site-packages\django\forms\models.py" in _post_clean
  408.             self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude)

File "C:\Python 3.6.2 (32bit)\lib\site-packages\django\forms\models.py" in construct_instance
  65.             f.save_form_data(instance, cleaned_data[f.name])

File "C:\Python 3.6.2 (32bit)\lib\site-packages\django\db\models\fields\__init__.py" in save_form_data
  853.         setattr(instance, self.name, data)

File "C:\Python 3.6.2 (32bit)\lib\site-packages\django\db\models\fields\related_descriptors.py" in __set__
  216.                     self.field.remote_field.model._meta.object_name,

Exception Type: ValueError at /agents/2/review/
Exception Value: Cannot assign "''": "Review.agent" must be a "Agent" instance.

class ReviewForm(forms.ModelForm):

    REVIEWER_TYPE = (
        # ... some choices
    )

    LOCATION = (
        # ... some choices
    )

    STARS = (
        # ... some choices
    )

    reviewer_type = forms.ChoiceField(widget=forms.RadioSelect, choices=REVIEWER_TYPE)
    property_type = forms.ChoiceField(widget=forms.RadioSelect, choices=BuyerListing.PROPERTY_TYPE)
    number_of_bedrooms = forms.ChoiceField(choices=BuyerListing.BEDS_OPTION)
    location = forms.ChoiceField(choices=LOCATION)
    stars = forms.ChoiceField(widget=forms.RadioSelect, choices=STARS)
    agent = forms.ChoiceField(widget = forms.HiddenInput(), required=False)

    class Meta:
        model = Review
        fields = ['agent', 'reviewer_first_name', 'reviewer_last_name', 'reviewer_email', 'reviewer_type', 'transaction_id', 'location', 'property_type', 'number_of_bedrooms', 'stars', 'content']

【问题讨论】:

  • 此代码不应给出该错误。请显示完整的回溯。
  • @DanielRoseman 添加到原帖
  • 对不起,这真的不可能是实际代码。 HTML 表单不包含任何字段,因此 Django 表单永远不会有效,甚至无法到达 form.save()
  • @DanielRoseman 我的错。表单的方法是post,所以它会自动跳转到视图的后期处理部分。我把它改成了get,这样我就可以填写表格了。填写表格后,我仍然遇到同样的错误。我更新了回溯。
  • 能否把ReviewForm的代码也加进去?

标签: django


【解决方案1】:

视图中的这一行没有用:

form.agent = Agent.objects.get(pk=pk)

表单实例不像 django 模型,你不能像这样设置字段属性。为此,您有两个解决方案:

  1. 您可以先从表单中获取对象,然后设置代理并保存对象。因此,从表单中删除 agent 字段,并在视图中制作您的代码,如下所示:

    def leave_review(request, pk):
        if request.method == 'POST':
    
            form = ReviewForm(request.POST)
    
            if form.is_valid():
                review = form.save(commit=False)  # Getting the unsaved `Review` instance from the form
                review.agent = Agent.objects.get(pk=pk)  # Set the agent on the `Review` instance
                review.save()  # Finally save the `Review` instance
    
                return redirect('review_success.html')
            else:
                form = ReviewForm()
    
        return render(request, 'leave_review.html', {'form': form})
    

    Documentation about the save method in the Django forms

  2. 如果您确实需要在表单中包含此 agent 字段(但由于它是隐藏字段,我假设您不需要?)您可以从表单 initial 关键字中传递值,如中所述this answer (Documentation):

    def leave_review(request, pk):
        if request.method == 'POST':
    
            # Passing initial data to the form so our `agent` field will be populated
            data = {'agent': Agent.objects.get(pk=pk)}
            form = ReviewForm(request.POST, initial=data)
    
            if form.is_valid():
                review.save()
    
                return redirect('review_success.html')
            else:
                form = ReviewForm()
    
        return render(request, 'leave_review.html', {'form': form})
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-19
    • 1970-01-01
    • 2020-08-26
    • 2021-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多