I’m learning WebSockets [django channels] to use along with DRF. I have created simple HTML form to create Comment
. The form contains some User
data so everyone can post a comment and the data entered is being used to create a new User
(posting comment not requiring any authentication at all).
Everything works fine when sending POST request from DRF Browsable API. However doesn’t work when sending data from HTML form : returns error "user": ["This field is required."]
Models:
class Comment(MPTTModel):
""" The base model represents comment object in db. """
user = models.ForeignKey(CustomUser, related_name="comments", on_delete=models.CASCADE)
date_created = models.DateTimeField(
verbose_name="Created at",
auto_now_add=True,
blank=True,
null=True
)
text = models.TextField(max_length=500)
class CustomUser(AbstractBaseUser, PermissionsMixin):
"""Custom User model extends a pre-defined django AbstractUser model."""
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField(verbose_name="email address", max_length=255, unique=True)
username = models.CharField(max_length=64, unique=True)
avatar = ResizedImageField(
force_format="WEBP",
crop=["middle", "center"],
upload_to=profile_avatar_path,
blank=True,
null=True,
max_length=500,
storage=OverwriteStorage()
)
homepage = models.URLField(max_length=255, null=True, blank=True)
enter code here
ViewSet:
class CommentViewSet(ModelViewSet):
""" Comment Viewset to handle base model operations. """
queryset = Comment.objects.filter(level=0)
serializer_class = CommentSerializer
def create(self, request, *args, **kwargs):
user_data = {}
for field, value in request.data.items():
if field.startswith("user"):
user_data.update({field.split("-")[1]: value})
request.data._mutable = True
request.data["user"] = user_data
request.data._mutable = False
print(request.data)
return super().create(request, *args, **kwargs)
However the request.data
never goes to perform_create()
method as stuck (looks like) on serializer.is_valid(rise_exception=True)
and never goes to Serializer create()
.
Serializers.py
class CommentSerializer(serializers.ModelSerializer):
""" Serializes Comment model data. """
user = BaseCustomUserSerializer()
rate = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Comment
exclude = ('level', 'lft', 'rght', 'tree_id')
read_only_fields = ('date_created', )
def create(self, validated_data):
"""
Modified create method handle additional user creation
while creating new Comment by anonymous user.
"""
user_data = validated_data.pop('user')
try:
user = CustomUser.objects.get(pk=user_data.get('uuid'))
except ObjectDoesNotExist:
# performing atomic transaction to insure both instances created
with transaction.atomic():
new_user = CustomUser.objects.create(**user_data)
comment = Comment.objects.create(user=new_user, **validated_data)
return comment
else:
comment = Comment.objects.create(user=user, **validated_data)
return comment
Finally the FORM:
<form action="http://127.0.0.1:8000/api/v1/comments/" method="post" id="newCommentForm" enctype="multipart/form-data"> {% csrf_token %}
<div class="field">
<label for="username">Username:</label>
<input type="text" name="user-username" id="username" required />
</div>
<div class="field">
<label for="user-email">Email: </label>
<input type="email" name="user-email" id="user-email" required />
</div>
<div class="field">
<label for="homepage">Homepage: </label>
<input type="url" name="user-homepage" id="homepage"/>
</div>
<div class="field">
<label for="text">Text</label>
<input type="text" name="text" id="text" required/>
</div>
<div class="g-recaptcha" data-sitekey="6LfA6NcpAAAAALR-d4hJGFOVZNb3bF6N1Ib-nIPt"></div>
<button data-action='submit'>Submit</button>
</form>