I try to link django API-REST with a form that has an associated model. Everything works well until I do the:
return response.Response (serializer.data, status = status.HTTP_201_CREATED)
JavaScript
// To Save the Suggestion
let ajax_suggestion_save = function (type, url, data, context) {
let name_dm = $('#name-db-saved').val();
$.ajax({
type: type,
url: url,
data: data,
context: context,
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
},
success: function (response) {
$.niftyNoty({
type: "success",
container: 'floating',
title: 'Your information was saved successfully.',
message: 'We much appreciate your interest of contact us, part of the growth of this platform it is base on your collaboration through your ideas.',
closeBtn: true,
timer: 4000
});
},
error: function (response) {
if (Object.keys(response.responseJSON).length >= 1) {
$.each(response.responseJSON, function (key, value) {
$.niftyNoty({
type: 'danger',
container: 'floating',
title: 'Ups, apparently we have problems saving your information.',
message: 'Please check the following ' +
'Error in <strong> ' + key + ' </strong>, with the following error <strong> ' + value + ' </strong>.',
closeBtn: true,
timer: 4000
});
});
} else {
$.niftyNoty({
type: 'danger',
container: 'floating',
title: 'Ups, apparently we have problems saving your information.',
message: 'Ups, apparently we have problems saving your suggestion. ' +
'If the problem persists, notify the system administrator in the help section.' +
'You suggestion <strong> ' + name_dm + ' </strong> not will be saved.',
closeBtn: true,
timer: 4000
});
}
}
});
};
$('#contactus').on('click', function (type, url, data, context) {
ajax_suggestion_save('POST', '/miscellaneous/api/contactus/create/', $("#contactus_form").serializeArray(), this);
});
Model
class DimContactUs(Model):
class Meta:
order_with_respect_to = 'email'
verbose_name = 'Contact'
verbose_name_plural = 'Contact'
id_contact_us = UUIDField(primary_key=True, default=uuid.uuid4, editable=False,
help_text='Universally unique identifier of a Contact')
name = CharField(max_length=100, help_text='Name of the Contact')
email = EmailField(max_length=70, help_text='Email of these Contact')
# id_user = ForeignKey(User, on_delete=CASCADE, help_text='Foreign Key of the User that made this Contact')
title = CharField(max_length=100, help_text='Title of the Contact')
message = TextField(
help_text='Short description of this Contact, e.g. : We want to include ...!')
url = URLField(null=True, blank=True,
help_text='Please copy the url associated to this Contact')
active = BooleanField(default=True, help_text='Do you want to make public this Contact?')
time_create = DateTimeField(auto_now=True, auto_now_add=False, editable=False, help_text='Time it was created')
time_stamp = DateField(auto_now=True, auto_now_add=False, help_text='Time of last modification')
def __str__(self):
return self.title
Serializers
class DimContactUsSer(serializers.ModelSerializer):
class Meta:
model = DimContactUs
fields = '__all__'
View
class ContactUsCreate(CreateAPIView):
queryset = DimContactUs.objects.all()
serializer_class = DimContactUsSer
#csrf_exempt
def post(self, request, *args, **kwargs):
try:
if request.method == 'POST':
form = DimContactUsForm(request.POST, request.FILES)
serializer = DimSuggestionSer(data=request.data)
if form.is_valid() and serializer.is_valid():
serializer.save()
return response.Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return response.Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except Exception as exception:
return response.Response(exception.args, status=status.HTTP_400_BAD_REQUEST)
Here, the response sends me to the REST API page instead of staying in the current one.
I would expect your missing the import statement for the module, I cannot see your import statements.
from rest_framework import status
Related
I'm trying to make a marketplace web project, Whenever I try to delete a Cart Product from cart, it redirects to an API view that shows that the GET method is not allowed. The delete function does not have a separate page, therefore it links to the api itself when the button is clicked.
I have double checked the urls of the api and they all are labelled correctly in the api side and in the ajax side when calling its function, yet it still shows said error.
Cart Viewset:
from rest_framework.response import Response
from rest_framework import status, viewsets
from cart.models import Cart
from cart.serializers import CartSerializer, CartUpdateSerializer
from rest_framework.parsers import MultiPartParser, FormParser
class CartViewSet(viewsets.ViewSet):
parser_classes = (MultiPartParser, FormParser)
# Function for adding products to user cart
def addto_cart(self, request, *args, **kwargs):
import pdb; pdb.set_trace()
cartProduct = Cart.objects.filter(buyer = request.user.id)
filtered = cartProduct.filter(product = self.kwargs.get("product_id")).first()
print(filtered.cart_quantity)
# Check if added cart product is a duplicate
if cartProduct.filter(product = self.kwargs.get("product_id")).exists():
print("Cart Product is a Duplicate!")
serializerUpdate = CartUpdateSerializer(filtered, data=request.data, partial=True)
#Only updates cart quantity
if serializerUpdate.is_valid():
addedQty = serializerUpdate.validated_data['cart_quantity']
total = filtered.cart_quantity + addedQty
serializerUpdate.save(cart_quantity = total)
return Response(serializerUpdate.data, status = status.HTTP_200_OK)
else:
serializer = CartSerializer(data=request.data)
if serializer.is_valid():
serializer.save(buyer=request.user)
return Response(serializer.data, status = status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#Gets cart products
def get_cart_products(self, request, *args, **kwargs):
cartProduct = Cart.objects.all()
if cartProduct:
cartSerializer = CartSerializer(cartProduct, many=True)
return Response(cartSerializer.data, status=status.HTTP_200_OK)
else:
return Response(cartSerializer.errors, status=status.HTTP_400_BAD_REQUEST)
#Deletes selected cart product if it exists
def delete_cart_product(self, request, *args, **kwargs):
import pdb; pdb.set_trace()
print('delete cart product accessed')
cart_instance = Cart.objects.filter(buyer_id = request.user.id)
cartProduct_instance = cart_instance.filter(product = self.kwargs.get("product_id")).first()
if cart_instance.buyer_id != request.user.id:
return Response(
{"res": "You are not the owner of the cart!"},
status = status.HTTP_400_BAD_REQUEST
)
cartProduct_instance.delete()
return Response(
{"res": "Cart Product Deleted!"},
status = status.HTTP_200_OK
)
urls.py:
urlpatterns = [
#API urls
path('api/addto_cart/<int:product_id>/', apis.CartViewSet.as_view({'post':'addto_cart'})),
path('api/get_cart_products/<int:user_id>/', apis.CartViewSet.as_view({'get':'get_cart_products'})),
path('api/delete_cart_product/<int:product_id>/', apis.CartViewSet.as_view({'delete':'delete_cart_product'})),
#Views urls
path('cart/<int:user_id>/', views.CartView.as_view(), name="cart"),
]
Serializers.py
from rest_framework import serializers
from .models import Product, Cart
class CartSerializer(serializers.ModelSerializer):
class Meta:
model = Cart
fields = '__all__'
class CartUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Cart
fields = ['cart_quantity']
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
class ProductSellerSerializer(serializers.ModelSerializer):
seller = serializers.CharField(source = 'seller.get_full_name')
class Meta:
model = Product
fields = '__all__'
cart.js (AJAX)
$(document).ready(function() {
var base_url = window.location.origin
console.log('get cart test')
console.log(base_url)
var urlid = window.location.pathname
var id = urlid.split("/")[3]
$.ajax({
method: 'GET',
url: base_url + '/cart/api/get_cart_products/'+id+ '/',
beforeSend: function() {
console.log('before cart send');
},
success: function(data) {
console.log('cart get successful');
console.log(data)
$.each(data, function(index, cart) {
console.log(cart.buyer)
console.log(cart.product)
if(cart.buyer == id) {
$.ajax({
method: 'GET',
url : base_url + '/market/api/get_productDetails/'+cart.product+ '/',
beforeSend: function() {
console.log('before send');
},
success: function(product) {
displayCart(product.data,cart);
console.log(product.data.name);
},
error: function(error) {
console.log('sum ting wong get product detail', error);
}
});
}
})
},
error: function() {
console.log('sum ting wong get cart');
}
});
});
// Delete Cart Product
$("#deleteCartProduct").click(function(event){
event.preventDefault();
console.log('Delete Cart Product test')
var base_url = window.location.origin
var urlid = window.location.pathname
var id = urlid.split("/")[3]
$.ajax({
method: 'DELETE',
beforeSend: function(xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
},
url : base_url + '/cart/api/delete_cart_product/'+id+ '/',
success: function(response) {
window.location = base_url + '/users/home/'
console.log('cart product deleted!')
console.log(response);
},
error: function() {
console.log('sum ting wong delete cart product');
}
});
});
//append cart products to html
function displayCart(data,cart) {
console.log(data)
productID = data.id
var base_url = window.location.origin
let template = "";
template +=
"<div class='card mb-3' style='max-width: 540px;'>" +
"<div class='row no-gutters'>" +
"<div class='col-md-4'>" +
"<img src= "+ data.picture +" class='card-img'>" +
"</div>" +
"<div class='col-md-8'>" +
"<div class='card-body'>" +
"<h5 class='card-title'>"+ data.name +"</h5>" +
"<p class='card-text'><small class='text-muted'>"+ data.seller +"</small></p>" +
"<p class='card-text'>"+ data.description +"</p>" +
"<p class='card-text'>₱"+ data.price +"</p>" +
"<p class='card-text'>Quantity: "+ cart.cart_quantity +"</p>" +
"<p class='card-text'>Total Price: ₱"+ data.price * cart.cart_quantity +"</p>" +
"<a class='btn btn-primary' href="+base_url+"/market/productDetails/"+data.id+" role='button'>View</a>" +
//CONTAINS THE DELETE BUTTON
"<a class='btn btn-danger' id='deleteCartProduct' href="+base_url+"/cart/api/delete_cart_product/"+data.id+" role='button'>Delete</a>" +
"</div>" +
"</div>" +
"</div>" +
"</div>"
$('#cartProductDisplay').append(template)
}
I have also tried renaming the api, its url links and it still produces the same error. The api itself works when I test it on Postman.
You made a simple mistake. Replace type: 'DELETE' to method: 'DELETE' in your #deleteCartProduct function
Actually, the proper way to change the request method in JQuery Ajax is to pass "DELETE" to the type parameter. It should work. If it is not check the request headers in your network tab on your browser and see if the request method is DELETE or not. This is how you can find out if it is a problem with your client-side or server-side app. If the problem persists on the client side consider using "Axios". It is more efficient and modern than JQuery Ajax.
I want to create Aviz entry using AJAX form.
In the form the input material has a jquery ui function autocomplete, that gets all the material names from the Material Model.
When I submit the form I get this error in the console : ValueError: Cannot assign "'ADEZIV LIPIRE VATA MINERALA, CT 180, 25 KG CERESIT'": "Aviz.material" must be a "Material" instance.
I know that I need to get the input from the form, and turn it in a Material instance...but do not know how/did not find any info about this.
models.py:
class Material(models.Model):
name = models.CharField(max_length=255,default=None,verbose_name='Nume material')
class Aviz(models.Model):
material = models.ForeignKey(Material, on_delete=models.CASCADE,related_name="aviz")
quantity = models.FloatField(default=0,verbose_name="Cantitate")
views.py:
class AvizCreate(LoginRequiredMixin, AjaxCreateView):
model = Aviz
form_class = AvizForm
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['pk'] = self.kwargs.get('centrudecost')
return kwargs
#login_required
def autocomplete(request):
if 'term' in request.GET:
qs = Material.objects.filter(name__icontains=request.GET.get('term'))
name = list()
id = list()
cod_nexus = list()
name = [prod.name for prod in qs]
id = [prod.pk for prod in qs]
cod_nexus = [prod.cod_nexus for prod in qs]
return JsonResponse({"name": name, "id":id, "cod_nexus":cod_nexus}, safe=False)
templates.html
$('#id_material').autocomplete({
source: function(request, response) {
$.ajax({
url: "{% url 'materiale:autocomplete' %}",
dataType: "json",
data: {
term: request.term
},
success: function(data) {
response($.map(data.name, function(value, key) {
return {
label: data.name[key],
value: data.name[key],
id:data.id[key],
cod_nexus:data.cod_nexus[key]
}
}));
}
});
},
select: async function(event, ui) {
let resp = await fetch("{% url 'materiale:get_um' 1 %}".replace('1',ui.item.id));
let json = await resp.json()
$('#id_um').val(json);
}
})
}
forms.py:
class AvizForm(BootstrapHelperForm, forms.ModelForm):
material = forms.CharField()
um = forms.CharField()
class Meta:
model = Aviz
fields = ('centrudecost','data','aviz', 'material','um','quantity',)
widgets = {
'data': DateInput(),
'centrudecost': forms.HiddenInput(),
# 'material': forms.Select(attrs={'class': 'form-control'})
}
def __init__(self, *args, **kwargs):
pk = kwargs.pop('pk', None)
super(AvizForm, self).__init__(*args, **kwargs)
self.fields['um'].widget.attrs['readonly'] = True
I know that by deleting this material = forms.CharField() from the forms.py, the form works, and a Aviz instance is created referencing the material model, but i need to use the autocomplete function in the form
When I try to send data via the frontend to the serializer I get a HTTP 400 error. If I do it directly via the DRF browsable API it works though:
model:
class Shipment(models.Model):
name = models.CharField("name", max_length = 128)
date = models.DateField()
class Product(models.Model):
serial = models.CharField("serial", max_length = 31, unique = True)
shipment = models.ForeignKey(Shipment, on_delete = models.CASCADE, blank = True, null = True)
serializer:
class ShipmentSerializer(serializers.ModelSerializer):
class Meta:
model = Shipment
fields = ["id", "name",]
class ProductSerializer(serializers.ModelSerializer):
shipment = ShipmentSerializer()
def update(self, instance, request):
product = Product.objects.get(serial = instance)
product.shipment = Shipment.objects.get(id = request["shipment"]["id"])
product.save()
return instance
class Meta:
model = Product
fields = ["serial", "shipment",]
lookup_field = "serial"
read_only_fields = ["serial",]
ViewSet:
class ProductViewSet(ModelViewSet):
serializer_class = ProductSerializer
lookup_field = "serial"
http_method_names = ["get", "patch", "put"]
def get_queryset(self):
return Product.objects.all()
AJAX call:
$.ajax({url: `api/products/${serial}/`,
dataType: "json",
contentType: "application/json",
type: "PUT",
data: {"shipment": shipment[0]},
headers: {"X-CSRFTOKEN": csrf_token },
success: function () {window.location = "?msg=ok";},
error: function () {window.location = "?msg=error";}
});
Browser output:
PUT
http://127.0.0.1:8000/api/products/d39f281f/
Status400
Bad Request
VersionHTTP/1.1
Transferred400 B (111 B size)
Referrer Policysame-origin
Request payload:
shipment=4
Response:
{"shipment":["This field is required."]}
or after some playing:
JSON parse error - Expecting value: line 1 column 1 (char 0)
why is the response field is required when there is a payload.
One way to approach this problem is to define two fields for shipment, one for writing and one for reading:
class ProductSerializer(serializers.ModelSerializer):
shipment_id = serializers.PrimaryKeyRelatedField(queryset=Shipment.objects.all(), write_only=True)
shipment = ShipmentSerializer(read_only=True)
class Meta:
model = Product
fields = ["serial", "shipment", "shipment_id"]
When you are updating, you can specify the id of the shipment using shipment_id:
{
"shipment_id": 10,
}
When you are retrieving or listing, the shipment details will come under shipment:
{
"serial": "",
"shipment": {
... # shipment details
}
}
I can't seem to upload an image to my project.
I always get this error when I try to submit the form from the frontend :
["The submitted data was not a file. Check the encoding type on the form."]
I've found some answers regarding the base64 encoding of the image but I can't seem to get it to work.
Any help would be much appreciated!!
thanks
here is the source code:
Models:
class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField(default=0)
dob = models.CharField(max_length=10)
image = models.ImageField(upload_to='images/', null=True)
def __str__(self):
return self.name
class Details(models.Model):
party = models.ForeignKey(Person,on_delete=models.CASCADE,
related_name='party_details',null=True,blank=True)
adress = models.CharField(max_length=50)
date = models.CharField(max_length=20)
arrival= models.CharField(max_length=20)
def __str__(self):
return self.adress
Serializers:
class DetailsSerializer(serializers.ModelSerializer):
class Meta:
model = Details
# fields='__all__'
fields = ('id','party','adress','date','arrival')
class PersonSerializer(serializers.ModelSerializer):
party_details =DetailsSerializer(many=True)
class Meta:
model = Person
# fields='__all__'
fields = ('id','name','age','dob','image','party_details')
def create(self, validated_data):
named_details = validated_data.pop('party_details')
details = Person.objects.create(**validated_data)
for named_detail in named_details:
Details.objects.create(party=details, ** named_detail)
return details
def update(self,instance, validated_data):
named_details = validated_data.pop('party_details')
details = (instance.party_details).all()
details = list(details)
instance.name = validated_data.get('name', instance.name)
instance.age = validated_data.get('age', instance.age)
instance.dob = validated_data.get('dob', instance.dob)
instance.image = validated_data.get('image', instance.image)
instance.save()
for named_detail in named_details:
detail = details.pop(0)
detail.adress = named_detail.get('adress',detail.adress)
detail.date = named_detail.get('date',detail.date)
detail.arrival = named_detail.get('arrival', detail.arrival)
detail.save()
return instance
views:
class ListAllPerson (generics.ListCreateAPIView):
queryset=Person.objects.all()
serializer_class = PersonSerializer
class ListPerson (generics.RetrieveUpdateDestroyAPIView):
serializer_class = PersonSerializer
queryset= Person.objects.all()
class ListAllDetails(generics.ListCreateAPIView):
queryset=Details.objects.all()
serializer_class = DetailsSerializer
class ListDetail(generics.RetrieveUpdateDestroyAPIView):
serializer_class = DetailsSerializer
queryset=Details.objects.all()
class CreateDetail(generics.ListCreateAPIView):
queryset=Details.objects.all()
serializer_class = DetailsSerializer
HTML FORM and Axios:
const profileImage = async ()=>{
let formField = new FormData()
formField.append('image',addImages)
await axios({
method: 'patch',
url: url,
data: formField
}).then((response) => {
history.push('/')
}).catch((error) => {
console.log(error);
})
}
<div className="add-image-input">
<form action="" className="add-image-form">
<input className="image-input" value={addImages}
onChange={(e)=>{setAddImages(e.target.value)}} type="file"/>
<button className="" type="button" onClick={profileImage} >add</button>
</form>
</div>
Hopefully you are using React js, this should help. At the point of
saving and submitting your form data, your function should look like this:
const onSubmit = (data) => {
console.log(data)
let form_data = new FormData();
form_data.append('upload_image_photo', data.cover_image, data.cover_image.name);
form_data.append('title', data.title);
form_data.append('category', data.category);
form_data.append('price_per_night', data.price_per_night);
form_data.append('room_slug', data.room_slug);
form_data.append('capacity', data.capacity);
form_data.append('room_size', data.room_size);
let url = '/url to the end point you are saving with the expected image field / ';
const config = {
headers: {
"Content-Type": "multipart/form-data",
Authorization: `Bearer ${token}`,
},
};
axios.post(url, form_data, config)
.then(res => {
console.log(res.request.status);
console.log(res.data);
})
.catch(err => console.log(err))
};
I don't understand what I'm doing wrong. I am trying to do an autocomplete with the data from the Product table, I don't know what the reason is since I mention the name of the product but toa it as "name". I've done it but I keep getting this error:
Cannot resolve keyword 'name' into field. Choices are: categoria, categoria_id, detalle_compra, ...
Models
class Producto(models.Model):
id_producto = models.AutoField(primary_key=True)
categoria = models.ForeignKey(Categoria, on_delete=models.CASCADE)
def __str__(self):
return self.nombre
def toJSON(self):
item = model_to_dict(self)
return item
class Meta:
verbose_name = 'Producto'
Views
def post(self, request, *args, **kwargs):
data = {}
try:
action = request.POST['action']
if action == 'autocomplete':
productos = Producto.objects.filter(name__icontains=request.POST['term'])
for i in productos:
data = []
item = i.toJSON()
item['value'] = i.nombre
data.append(item)
else:
JS
$("#search").autocomplete({
source: function (request, response) {
$.ajax({
url: window.location.pathname,
type: 'POST',
data: {
'action': 'autocomplete',
'term': request.term
},
dataType: 'json',
}).done(function (data) {
response(data);
}).fail(function (data) {
alert("Error");
}).always(function (jqXHR, textStatus, errorThrown) {
})
},
I have verified that it is not "name" however in none of the files I have made that equivalent. I hope you can help me
You are trying to pass name_contains in views.py which is not in model Producto.
Try to use this :-
productos = Producto.objects.filter(id_producto__icontains=request.POST['term'])