TypeError:create()获得了关键字参数“ user”的多个值

时间:2019-03-08 08:00:04

标签: html django python-3.x reactjs django-rest-framework

我正在从reactJS向Django rest发送发布请求以创建发布,但是出现此错误。

TypeError:create()为关键字参数“ user”获得了多个值

一切正常,除非我将用户发送到项目序列化程序。我将用户保存在localstorage中以获取userId。 请有人帮我解决这个问题。

编辑: 我注意到,由于某种原因,当我从存储中获取userId并将其存储为setState方法时,状态仍然为null,并且序列化程序在用户字段中接收到null值。

这是我的数据伙伴 enter image description here

post.js

class PostProject extends Component {

    state = {
        controls: {
            title: {
                elementType: 'input',
                elementConfig: {
                    type: 'text',
                    placeholder: 'Cafe Management System'
                },
                value: ''
            },
            price: {
                elementType: 'input',
                elementConfig: {
                    type: 'text',
                    placeholder: '100'
                },
                value: ''
            },
            description: {
                elementType: 'input',
                elementConfig: {
                    type: 'text',
                    placeholder: 'Description about your project'
                },
                value: ''
            },
        },
        user: null,
        modules: [],
        technologies: [],
        requirements: [],
        tags: []
    };

    submitHandler = (event) => {
        event.preventDefault();
        const user = localStorage.getItem('userId');
        this.setState({ user: user })
        //Get data from state
        for (let el = 0; el < this.props.modules.length; el++) {
            const obj = { project: this.state.controls.title.value, name: this.props.modules[el] }
            this.setState({
                modules: this.state.modules.push(obj)
            })
        }
        for (let el = 0; el < this.props.technologies.length; el++) {
            const obj = { project: this.state.controls.title.value, name: this.props.technologies[el] }
            this.setState({
                technologies: this.state.technologies.push(obj)
            })
        }
        for (let el = 0; el < this.props.requirements.length; el++) {
            const obj = { project: this.state.controls.title.value, name: this.props.requirements[el] }
            this.setState({
                requirements: this.state.requirements.push(obj)
            })
        }
        for (let el = 0; el < this.props.tags.length; el++) {
            const obj = { project: this.state.controls.title.value, title: this.props.tags[el] }
            this.setState({
                tags: this.state.tags.push(obj)
            })
        }
        const formData = {};
        for (let el in this.state.controls) {
            formData[el] = this.state.controls[el].value;
            formData['user'] = this.state.user;
            formData['modules'] = this.state.modules;
            formData['technologies'] = this.state.technologies;
            formData['requirements'] = this.state.requirements;
            formData['tags'] = this.state.tags;
        }
        console.log(formData);
        axios.post('http://127.0.0.1:8000/api/projects/', formData)
            .then(response => {
                console.log(response);
                alert('posted successfully');
            })
            .catch(error => {
                console.log(error)
            })
    };

    inputChangedHandler = (event, controlName) => {
        const updateControls = {
            ...this.state.controls,
            [controlName]: {
                ...this.state.controls[controlName],
                value: event.target.value,
            }
        };
        this.setState({ controls: updateControls });
    };

    render() {

        const fomElementArray = [];
        for (let key in this.state.controls) {
            fomElementArray.push({
                id: key,
                config: this.state.controls[key]
            });
        }

        let form = fomElementArray.map(formElemet => (
            <Input elementType={formElemet.config.elementType}
                elementConfig={formElemet.config.elementConfig}
                value={formElemet.config.value}
                key={formElemet.id}
                changed={(event) => this.inputChangedHandler(event, formElemet.id)} label={formElemet.config.elementConfig.placeholder} />
        ));
        return (
            <section className='container'>
                <div className="container">
                    <div className="row">
                        <div className="col-md-8 col-md-offset-2 ">
                            <SecondaryHeading>Upload your project</SecondaryHeading><br />
                            <div className='border bg-white d-inline-block px-4 py-2 mb-5'>
                                <TertiaryHeading>Before you upload, make sure to read our terms.</TertiaryHeading>
                                <ul>
                                    <li>Read the standards and requirements for item(s) you want to sell.</li>
                                    <li>Make sure your files are well organized.</li>
                                    <li>Always provide complete details about your project.</li>
                                </ul>
                            </div>
                            <form >
                                <div className="form-group">
                                    <TertiaryHeading>Name and Description</TertiaryHeading><br />
                                    <input type="text"
                                        className="form-control"
                                        name="title"
                                        placeholder="Name"
                                        onChange={(event) => this.inputChangedHandler(event, 'title')} />
                                </div>
                                <div className="form-group">
                                    <textarea rows="8"
                                        className="form-control"
                                        name="description"
                                        placeholder="Write overview of your project..."
                                        onChange={(event) => this.inputChangedHandler(event, 'description')} ></textarea>

                                </div>
                            </form>
                            <hr />
                            <div className='mt-5'>
                                <TertiaryHeading>Features and Requirements</TertiaryHeading><br />
                                <div className="">
                                    <label htmlFor="description">Modules</label>
                                    <DynamicFieldSet btnLabel='Module' />
                                </div>
                                <div className="">
                                    <label htmlFor="description">Technologies</label>
                                    <DynamicFieldSet btnLabel='Technology' />
                                </div>
                                <div className="">
                                    <label htmlFor="description">Requirements</label>
                                    <DynamicFieldSet btnLabel='Requirement' />
                                </div>
                            </div>
                            <hr />

                            <div className='mt-5'>
                                <TertiaryHeading>Upload source files</TertiaryHeading><br />
                                <FileUpload />
                            </div>
                            <hr />

                            <div className='mt-5'>
                                <TertiaryHeading>Pricing</TertiaryHeading><br />
                                <input type="text"
                                    className="form-control col-md-2"
                                    name="title"
                                    placeholder="$5.00"
                                    onChange={(event) => this.inputChangedHandler(event, 'price')} />
                            </div>
                            <hr />
                            <div className='mt-5'>
                                <TertiaryHeading>Tags</TertiaryHeading><br />
                                <TagGroup />
                            </div>

                        </div>
                        <div className='col-md-4 mt-5'>
                            <TertiaryHeading>Choose Snapshots</TertiaryHeading><br />
                            <PicturesWall />
                        </div>

                    </div>
                    <div className="mt-5">
                        <p><span className="require">*</span> - required fields</p>
                    </div>
                    <form onSubmit={(event) => this.submitHandler(event)}>
                        <div className="form-group">
                            <Button btnType="Btn-primary Btn-md ">Submit</Button>
                        </div>
                    </form>
                </div>
            </section>
        )
    }
}

const mapStateToProps = (state) => {
    return {
        modules: state.dynamicFormItemReducer.modules,
        technologies: state.dynamicFormItemReducer.technologies,
        requirements: state.dynamicFormItemReducer.requirements,
        tags: state.tagReducer.tags
    };
}

export default connect(mapStateToProps, null)(PostProject);

models.py

from django.db import models
from django.conf import settings
from django.db.models.signals import pre_save, post_save
from softforest.utils import unique_slug_generator

# Create your models here.

user = settings.AUTH_USER_MODEL


class Project(models.Model):
    user = models.ForeignKey(user, null=True, blank=True, on_delete=models.CASCADE)
    title = models.CharField(max_length=255)
    slug = models.SlugField(blank=True, unique=True)
    description = models.TextField()
    price = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
    ratings = models.DecimalField(default=0.0, max_digits=50, decimal_places=2, blank=True, null=True)
    updated = models.DateTimeField(auto_now=True)
    timestamp = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

    @property
    def modules(self):
        return self.module_set.all()


class Module(models.Model):
    project = models.ForeignKey(Project, related_name='modules', on_delete=models.CASCADE)
    name = models.CharField(max_length=120)

    def __str__(self):
        return self.name


class Technology(models.Model):
    project = models.ForeignKey(Project, related_name='technologies', on_delete=models.CASCADE)
    name = models.CharField(max_length=120)

    def __str__(self):
        return self.name


class Requirement(models.Model):
    project = models.ForeignKey(Project, related_name='requirements', on_delete=models.CASCADE)
    name = models.CharField(max_length=120)

    def __str__(self):
        return self.name


def project_pre_receiver(sender, instance, *args, **kwargs):
    if not instance.slug:
        instance.slug = unique_slug_generator(instance)


pre_save.connect(project_pre_receiver, sender=Project)

serializers.py

from rest_framework import serializers

from .models import Project, Module, Technology, Requirement
from tags.models import Tag
from accounts.models import User


class TagSerializer(serializers.ModelSerializer):
    """Serializer for Project Tags"""

    class Meta:
        model = Tag
        fields = ('title',)


class RequirementSerializer(serializers.ModelSerializer):
    """Serializer for Project requirements"""

    class Meta:
        model = Requirement
        fields = ('name',)


class TechnologySerializer(serializers.ModelSerializer):
    """Serializer for Project technologies"""

    class Meta:
        model = Technology
        fields = ('name',)


class ModuleSerializer(serializers.ModelSerializer):
    """Serializer for Project Modules"""
    print("MODULES SERIALIZER")

    class Meta:
        model = Module
        fields = ('name',)


class ProjectSerializer(serializers.ModelSerializer):
    """Serializer for Project"""
    modules = ModuleSerializer(many=True)
    technologies = TechnologySerializer(many=True)
    requirements = RequirementSerializer(many=True)
    tags = TagSerializer(many=True)

    class Meta:
        model = Project
        fields = [
            'id',
            'slug',
            'user',
            'title',
            'description',
            'price',
            'ratings',
            'modules',
            'technologies',
            'requirements',
            'tags'
            ]

    def create(self, validated_data):
        user = validated_data['user']
        modules = validated_data.pop('modules')
        technologies = validated_data.pop('technologies')
        requirements = validated_data.pop('requirements')
        tags = validated_data.pop('tags')
        user_key = User.objects.filter(id__iexact=user)
        project = Project.objects.create(**validated_data, user=user_key)
        for module in modules:
            Module.objects.create(**module, project=project)
        for technology in technologies:
            Technology.objects.create(**technology, project=project)
        for requirement in requirements:
            Requirement.objects.create(**requirement, project=project)
        for tag in tags:
            Tag.objects.create(**tag, project=project)

        return project

views.py

from rest_framework import viewsets
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.decorators import action
from .models import Project, Module
from drf_multiple_model.viewsets import ObjectMultipleModelAPIViewSet
from .serializers import ProjectSerializer, ModuleSerializer, TechnologySerializer, RequirementSerializer
from .models import *
from tags.models import Tag

# Create your views here.


class ProjectViewSet(viewsets.ModelViewSet):
    """A viewset for viewing and manipulating user instances"""

    print("PROJECT VIEWSET")
    serializer_class = ProjectSerializer
    queryset = Project.objects.all()
    lookup_field = 'slug'
    filter_backends = (DjangoFilterBackend, )

    @action(detail=True, methods=["GET"])
    def modules(self, request, id=None):
        project = self.get_object()
        modules = Module.objects.filter(project=project)
        serializer = ModuleSerializer(modules, many=True)

        return Response(serializer.data, status=200)

    @action(detail=True, methods=["GET"])
    def technologies(self, request, id=None):
        project = self.get_object()
        technologies = Technology.objects.filter(project=project)
        serializer = TechnologySerializer(technologies, many=True)

        return Response(serializer.data, status=200)

    @action(detail=True, methods=["GET"])
    def requirements(self, request, id=None):
        project = self.get_object()
        requirements = Requirement.objects.filter(project=project)
        serializer = RequirementSerializer(requirements, many=True)

        return Response(serializer.data, status=200)

    @action(detail=True, methods="POST")
    def project(self, request, id=None):
        print('POST')
        user = self.get_object()
        data = request.data
        print(data)
        data["user"] = user.id
        serializer = ProjectSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=201)
        return Response(serializer.errors, status=400)

1 个答案:

答案 0 :(得分:1)

setState是异步的,但是您对待它的方式却并非如此。您需要将自己的SubmitHandler()方法更改为更多类似的内容。 setState()的第二个参数是您应该进行所有操作的位置,因为您依赖this.state.user的存在,而只是调用setState({user});。不是在等待它真正发生...

this.setState({ user: user },
  () => {
    for (let el = 0; e...
  }
);

在此之前,我可能会在setState()调用其自己的函数之后将所有这些多余的代码移走:

this.setState({ user }, () => doExtraWork());

然后将所有for循环和其他setState()调用整齐地放入doExtraWork()中。这应该确保this.state.user存在并且您的代码可以正常工作。

您遇到的第二个问题是您在四个地方执行了此操作:

this.setState({
  tags: this.state.tags.push(obj)
})

这行不通。将标签取出到变量中,添加所需内容,然后正确使用setState(),即this.setState({标签})。