我正在从reactJS向Django rest发送发布请求以创建发布,但是出现此错误。
TypeError:create()为关键字参数“ user”获得了多个值
一切正常,除非我将用户发送到项目序列化程序。我将用户保存在localstorage中以获取userId。 请有人帮我解决这个问题。
编辑: 我注意到,由于某种原因,当我从存储中获取userId并将其存储为setState方法时,状态仍然为null,并且序列化程序在用户字段中接收到null值。
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)
答案 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({标签})。