Django CBV 表单提交返回 JSON 显示为新页面

Posted

技术标签:

【中文标题】Django CBV 表单提交返回 JSON 显示为新页面【英文标题】:Django CBV form submission returned JSON is displayed as a new page 【发布时间】:2021-09-26 21:59:52 【问题描述】:

我正在使用 Django 3.2

我正在创建一个简单的时事通讯订阅表格。表单提交将 JSON 返回到前端,然后应该使用它来更新页面的某些部分 - 但是,当我发布表单时,JSON 字符串在新页面上显示为文本。

这里是调用视图的路由:

urlpatterns = [
               # ...
               path('subscription', BlogsubscriberCreateView.as_view(), name='subscription-post'),
               # ...
              ]

这是我的基于类的视图:

class BlogsubscriberCreateView(CreateView):
    model = BlogPostSubscriber
    form_class = BlogSubscriptionForm
    http_method_names = ['post']

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        content_type = "application/json"

        if not form.is_valid():
            return JsonResponse('ok': 0, 'msg': form.errors.get('email')[0], content_type=content_type, status=200)

        else:
            email = form.cleaned_data.get("email")
            subscriber = BlogPostSubscriber(email= email)
            subscriber.save()
            # send email to confirm opt-in
            email_message='Please confirm your subscription'
            message = f"A confirmation email has been sent to email. Please confirm within 7 days"
            return JsonResponse('ok': 1, 'msg': message, content_type=content_type, status=200)

这是包含表单的 html 的 sn-p:

<div class="col-lg-8 content">
                                <form id="blog-subscription" action="% url 'blog:subscription-post' %" method="post">
                                    % csrf_token %
                                    <br />
                                    <h3>Some title</h3>
                                    <br />
                                    
                                    <p>Lorem ipsum ...</p>
                                    
                                    <br />
                                    
                                    <h4 id='submit-response-h4'>SUBSCRIBE TO OUR BLOG</h4>
                                    <div id="submit-response" class="input-group">
                                        <span id="email-error"></span>
                                        <input type="email" id="blog-subscription-email" name="email" class="form-control" placeholder="Enter your email" required="true">
                                        <span class="input-group-btn">
                                            <button id="subscribe-btn" class="btn" type="submit">Subscribe Now</button>
                                        </span>
                                    </div>
                                </form>

这是负责更新页面的 javascript

  $().ready(function() 

        $('form#blog-subscription button#subscribe-btn.btn').on('click', function(e)
            let email = $('#blog-subscription-email').val().trim().toLowerCase();

            if (email.length && isValidEmail(email))
                
               e.preventDefault();

                $.post(
                    url: "% url 'blog:subscription-post' %",
                    dataType: 'json',
                    data: 
                        email: email,
                        csrfmiddlewaretoken: ' csrf_token '
                    ,   
                    success: function (data)  
                        let ok = data.ok;

                        if (ok)
                            if ($('#submit-response-h4').length)
                                $('#submit-response-h4').remove();
                            
                            $('#submit-response').text(data.msg);
                        
                        else
                            $('#email-error').text(data.msg);
                        

                    
                );      
            
        );
);

我在我的 Javascript 中放置了一个警告注释,并意识到它根本没有被调用。我不明白发生了什么——如果没有调用 Javascript——JQuery 怎么知道将 post 函数调用到正确的 URL? (表单没有动作属性!)。

http://example.com/path/to/subscription 中显示的典型响应示例(带有错误电子邮件):

"ok": 0, "msg": "请使用不同的电子邮件服务提供商"

是什么导致了这个问题 - 我该如何解决?

【问题讨论】:

我认为action 默认为='.'。我假设您在最初将视图称为 GET 并显示表单时处于表单中。尝试删除 type="submit" 或其他一些方法来让 JS 运行 @HenryM 当我按照您的建议进行操作时,页面会重新加载,什么也不做(因为页面上没有显示任何消息) - 并且浏览器中的 URL 会使用本应更新的数据进行更新已发布 - 例如:https://127.0.0.1:8000/blog/subscribe/?csrfmiddlewaretoken=Fh8PxzWGW961UOn4TEHZey3Pxvz3qtMICFPfq7hgoAYuSEN8pUIiAXPXwwQP1gPp&amp;email=someone%40hotmail.com 但这意味着它正在执行GET?我将粘贴一些我使用的代码(但单击图像)对我有用 @HenryM 是的,这是一个 GET 请求。我根本不明白发生了什么——因为它至少对我来说没有意义ATALL(除非有一个未记录的 Django 陷阱)。实际上,我已经更新了我的 HTML sn-p。只有当我提供 actionmethod 属性时,我才能让它“工作”——即使它返回 JSON 作为页面中显示的字符串(这个问题)。真让人抓狂。 嗨,检查您的浏览器控制台,您的语法错误是否正确。此外,您的 json 会显示在新页面上,因为 ajax 调用永远不会执行您的表单正在提交。 【参考方案1】:

此代码使用相关图像填充模式。它与您的问题不完全相同,但这确实有效,因此应该可以通过修改进行转移。

js

function modal_form(form_url)
    var modal_id = 'modal-form';
    $.ajax(
        type: 'GET',
        url: form_url,
        cache: false,
        success: function (data, status) 
            $('#carouselModal').html(data);
            $('#carouselModal').modal('show');
        
    );

html

                                <img class="d-block w-100" src="% thumbnail image.file 'carousel_main' subject_location=image.file.subject_location %"  itemprop="image" onclick="modal_form('% url "providers:carousel-modal" organisation.id "carousel_photos" %')">

网址

path('carousel-modal/<int:pk>/<str:gallery>/', views.CarouselModal.as_view(), name="carousel-modal"),

观看次数

类 CarouselModal(DetailView): 模型 = 模型。组织 template_name = "providers/extras/gallery_modal.html"

def get_context_data(self, **kwargs):
    ctx = super().get_context_data(**kwargs)
    gallery = self.kwargs['gallery']
    if gallery == 'carousel_photos':
        ctx['images'] = self.object.carousel_photos
    elif gallery == 'propertyimages':
        ctx['images'] = self.object.propertyimages_set.all()
    
    if self.request.user_agent.is_mobile:
        ctx['image_size'] = 'mobile_modal_carousel_slide'
    elif self.request.user_agent.is_tablet:
        ctx['image_size'] = 'tablet_modal_carousel_slide'
    else: ctx['image_size'] = 'modal_carousel_slide'
    try: ctx['show_all'] = self.object.is_premium
    except: ctx['show_all'] = False
    return ctx

gallery_modal.html

% load static thumbnail %
<div class="modal-dialog carousel-modal" role="document">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                <span aria-hidden="true">&times;</span>
            </button>
        </div>
        <div class="modal-body">    
            <div id="mainCarousel" class="carousel slide thumbnail-carousel" data-ride="carousel">
                <div class="thumbnail-carousel__main">
                    <div class="carousel-inner">
                        % for image in images %
                            % if show_all or forloop.first %
                            <div class="carousel-item% if forloop.first % active% endif %">
                                <img class="d-block w-100"  src="% thumbnail image.file image_size subject_location=image.file.subject_location %"  itemprop="image" >
                            </div>
                            % endif %
                        % empty %
                            % include 'providers/detail/stock_carousel.html' %
                        % endfor %
                    </div>
                    % if show_all and images.count > 1 %
                        <a class="carousel-control-prev" href="#mainCarousel" role="button" data-slide="prev">
                            <span class="carousel-control-prev-icon" aria-hidden="true"></span>
                            <span class="sr-only">Previous</span>
                        </a>
                        <a class="carousel-control-next" href="#mainCarousel" role="button" data-slide="next">
                            <span class="carousel-control-next-icon" aria-hidden="true"></span>
                            <span class="sr-only">Next</span>
                        </a>
                    % endif %
                </div>

            </div>
        </div>
    </div>
</div>

我刚刚意识到在这个例子中我没有返回一个 JSONResponse,但是我再次认为这个原则是好的

【讨论】:

以上是关于Django CBV 表单提交返回 JSON 显示为新页面的主要内容,如果未能解决你的问题,请参考以下文章

Django 以 JSON 格式返回单个记录

django form表单组建使用及CBV模式

django form表单组建使用及CBV模式

使用 CBV 在 Django 中的一个视图/模板中的两个模型表单

django 怎么将查询到的数据以json形式返回

POST表单提交后django显示消息