【问题标题】:Angular post data is not going to Django REST APIAngular 发布数据不会发送到 Django REST API
【发布时间】:2019-01-22 15:01:23
【问题描述】:

我正在使用Angular 6Django REST Framework

DRF的观点是

class AmountGivenViewSet(viewsets.ModelViewSet):
    serializer_class = AmountGivenSerializer
    permission_classes = (IsAuthenticated, AdminAuthenticationPermission,)

    def get_queryset(self):
        return AmountGiven.objects.filter(
            contact__user=self.request.user
        )

    def perform_create(self, serializer):
        save_data = {}

        print(self.request.POST)
        # validate user and to save_data dictionary
        contact_pk = self.request.POST.get('contact', None)
        print(contact_pk)
        if not contact_pk:
            raise ValidationError({'contact': ['Contact is required']})

        contact = Contact.objects.filter(
            user=self.request.user,
            pk=contact_pk
        ).first()

        if not contact:
            raise ValidationError({'contact': ['Contact does not exists']})

        # add contact to save_data dictionary
        save_data['contact'] = contact

        # process mode_of_payment is in request
        mode_of_payment_pk = self.request.POST.get('mode_of_payment', None)

        if mode_of_payment_pk:
            mode_of_payment = ModeOfPayment.objects.get(pk=mode_of_payment_pk)
            if not mode_of_payment:
                raise ValidationError({'mode_of_payment': ['Not a valid mode of payment']})

            # add mode_of_payment to save_data dictionary
            save_data['mode_of_payment'] = mode_of_payment

        # pass save_data dictionary to save()
        serializer.save(**save_data)
serializers.py 中的

AmountGivenSerializer

class AmountGivenSerializer(serializers.ModelSerializer):
    class Meta:
        model = AmountGiven
        depth = 1
        fields = (
            'id', 'contact', 'amount', 'interest_rate', 'duration', 'given_date', 'promised_return_date',
            'mode_of_payment', 'transaction_number', 'interest_to_pay', 'total_payable', 'amount_due',
            'total_returned', 'comment', 'modified', 'created'
        )

Angular 组件中

import { Component, OnInit } from '@angular/core';
import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms';
import {AmountGiven} from '../amount-given.model';
import {AmountGivenService} from '../amount-given.service';
import {ActivatedRoute} from '@angular/router';

@Component({
  selector: 'app-amount-given-add',
  templateUrl: './amount-given-add.component.html',
  styleUrls: ['./amount-given-add.component.css']
})
export class AmountGivenAddComponent implements OnInit {

  addMoneyForm: FormGroup;
  submitted = false;
  contact_id: string;

  amountGiven: AmountGiven;

  constructor(
    private formBuilder: FormBuilder,
    private amountGivenService: AmountGivenService,
    private route: ActivatedRoute
  ) { }

  ngOnInit(): void {

    this.route.params.subscribe(
      param => {
        this.contact_id = param['contact_id'];
      }
    );

    this.addMoneyForm = this.formBuilder.group({
      amount: new FormControl('', [
        Validators.required
      ]),
      interest_rate: new FormControl(),
      duration: new FormControl(),
      given_date: new FormControl(),
      promised_return_date: new FormControl(),
      transaction_number: new FormControl(),
      mode_of_payment: new FormControl(),
      comment: new FormControl()
    });
  }

  get f() {
    return this.addMoneyForm.controls;
  }

  onSubmit() {
    this.submitted = true;

    // stop here if form is invalid
    if (this.addMoneyForm.invalid) {
      console.log('invalid');
      return;
    }

    const data = this.addMoneyForm.value;
    data.contact = this.contact_id;

    this.amountGivenService.add(data).subscribe(res => {
      console.log('req completed', res);
    });
  }

}

但是当提交表单时,它会从服务器返回 contact 字段的验证错误。

{"contact":["Contact is required"]}

请求头有contact参数

Postman 发送相同的请求工作正常。 Postman 请求的 Javascript XHR 代码是

var data = new FormData();
data.append("amount", "5000");
data.append("contact", "65827a1f-003e-4bb3-8a90-6c4321c533e6");

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://koober-production.herokuapp.com/api/amount-given/");
xhr.setRequestHeader("Authorization", "Bearer ATjIuQ6hLzc55wHaXIzHmcKafEzk1B");
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.setRequestHeader("Postman-Token", "28d9d33a-f0a6-431c-8936-da4f6565ece4");

xhr.send(data);

无法理解此问题与 AngularDjango 有关,因为 Postman 请求与 Djano 一起工作正常,而 Angular 正在发送请求参数。

编辑 2:AmountGivenService

import { Injectable } from '@angular/core';
import {ResourceProviderService} from '../../resource-provider.service';
import {AuthService} from '../../auth/auth.service';
import {Observable, of} from 'rxjs';
import {AmountGiven} from './amount-given.model';
import {AppHttpClient} from '../../app-http-client';

@Injectable({
  providedIn: 'root'
})
export class AmountGivenService {

  private url = 'amount-given/';

  constructor(
    private http: AppHttpClient
  ) { }

  add(data): Observable<AmountGiven> {

    return this.http.Post<AmountGiven>(this.url, data);
  }

}

进一步使用 AppHttpClient

import { Injectable } from '@angular/core';
import {HttpClient, HttpHeaders, HttpParams} from '@angular/common/http';
import {Observable, of} from 'rxjs';
import {catchError} from 'rxjs/operators';
import {ResourceProviderService} from './resource-provider.service';

export interface IRequestOptions {
  headers?: HttpHeaders;
  observe?: 'body';
  params?: HttpParams;
  reportProgress?: boolean;
  responseType?: 'json';
  withCredentials?: boolean;
  body?: any;
}

export function appHttpClientCreator(http: HttpClient, resource: ResourceProviderService) {
  return new AppHttpClient(http, resource);
}

@Injectable({
  providedIn: 'root'
})

export class AppHttpClient {

  private api_url = this.resource.url + '/api/';

  constructor(
    public http: HttpClient,
    private resource: ResourceProviderService
  ) {
  }

  public Post<T>(endPoint: string, params: Object, options?: IRequestOptions): Observable<T> {
    return this.http.post<T>(this.api_url + endPoint, params, options)
      .pipe(
        catchError(this.handleError('post', endPoint, null))
      );
  }

  private handleError<T> (operation = 'operation', endpoint = '', result?: T) {
    return (error: any): Observable<T> => {
      console.error(error);
      console.log(error.message);
      console.log(operation);
      console.log(endpoint);

      return of(result as T);
    };
  }
}

【问题讨论】:

  • 我们能看到AmountGivenService的代码吗?
  • 嗨 Anuj,您可能需要将以下内容添加到您的表单元素中(我不确定 Angular 的做法),但我知道 Django 需要 x-www-form-urlencoded,所以取决于如何Angular 处理这个你需要一些可以复制的东西:&lt;form method="POST" action="url/to/your-DRF-endpoint" enctype="application/x-www-form-urlencoded"&gt;
  • @R.Richards 用请求的代码更新问题。

标签: django angular django-rest-framework angular6


【解决方案1】:

问题是您正在尝试访问:

self.request.POST.get('contact', None)

在 DRF 中你需要做的:

self.request.data.get('contact', None)

它适用于邮递员,因为您正在构建一个 FormData 对象,该对象与角度将发送的 JSON 主体完全不同,这是 DRF 等 RESTful API 所期望的。

从更一般的角度来看,在 DRF 中,序列化程序应使用内置验证器执行请求验证,而不是在视图中手动验证。

【讨论】:

  • 虽然通过改造将 android 连接到 drf request.POST 工作正常,但为什么它不适用于 angular 为什么我们必须使用 request.data 代替??
【解决方案2】:

我还犹豫着要不要添加这个作为答案,但感觉你需要添加以下内容:

<form method="POST" action="url/to/your-DRF-endpoint" enctype="application/x-www-form-urlencoded">
 ....
</form>

无论是在您的模板中还是在您的 Angular POST 请求代码中,您都需要确保将数据发布为 application/x-www-form-urlencoded。

本质上,Django 需要application/x-www-form-urlencoded,如果没有它,您的self.request.POST 对象将为空,因此self.request.POST.get('contact', None) 将为空并默认为None

【讨论】:

  • Django 需要一个标准形式,DRF 需要一个 JSON 主体,因为 Angular 将发送,问题是他如何尝试访问视图中的数据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-07
  • 2017-08-08
  • 2021-06-11
  • 2015-04-17
  • 1970-01-01
相关资源
最近更新 更多