django upload view fails - django

This is my Product model
class Product(models.Model):
name = models.CharField(max_length=255, blank=False)
category = models.ManyToManyField(ProductCategory)
thumbnail_image = models.ImageField(null=True, blank=True)
description = models.TextField(null=False, blank=False)
price = models.DecimalField(max_digits=20, decimal_places=2, null=False, blank=False)
stock = models.IntegerField(default=0)
tag = models.CharField(max_length=255, null=True, blank=True)
date = models.DateTimeField(auto_now=True)
enable = models.BooleanField(default=True)
as you can see category is many to many.
so I declared 'product.category.add(product_category)' in ProductUpload view
#api_view(['POST'])
def ProductUpload(request):
img = request.FILES.get('thumbnamil_image')
data = request.data
product_category = request.POST.getlist('category')
product = Product(name = data['name'],
thumbnail_image = img,
description = data['description'],
price = data['price'],
stock = data['stock'],
tag = data['tag'],
enable = data['enable']
)
product.save()
product.category.add(product_category)
return Response('success')
I thought this is it to implement upload function. However,
it does not work..
if I declare POST method view in ProductList view, it works though..
if I erase the POST part of the ProductList, it is not working..
How I can integrate two seperated upload logics in ProductUpload view?
#api_view(['GET','POST'])
def ProductList(request):
if request.method == 'GET':
products = Product.objects.all()
serializer = ProductSerializer(products, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = ProductSerializer(data=request.data, many=False)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors)

Related

How to filter in Django Rest Framework function based view?

So many documentation for filtering in Django rest framework but all the examples are in class based view. but I am trying to do the same in DRF function based view. I wanted to do multiple filter for my items queryset.
I tried one way and it is working perfectly. Here first I am trying to search by item name or restaurant name in one request. then I take another keyword and try to filter restaurant name or item name based on restaurant city. It is working perfectly like if I hit this url
http://localhost:8000/api/items/?keyword=lasagne&keyword1=paris
then it gives me the perfect response.
But What I am asking for is that now my code looks for this specific part is messy and I want to add more fields for multiple filtering. Which procedure to follow? Should I follow this one and multiple requests and trying to filter from this.
Suppose now I want to filter the queryset based on dish_type, price, item_type, location and then search for items by name or restaurants by name
#this is my models
class Restaurant(models.Model):
user = models.OneToOneField(CustomUser, related_name='restaurant', on_delete=models.CASCADE, null=False)
name = models.CharField(max_length=200, blank=True, null=True)
profile_picture = models.ImageField(null=True, blank=True)
address = models.TextField(max_length=2000, blank=True, null=True)
city = models.CharField(max_length=200)
latitude = models.DecimalField(max_digits = 13, decimal_places = 7, blank=True, null=True)
longitude = models.DecimalField(max_digits = 13, decimal_places = 7, blank=True, null=True)
is_verified = models.BooleanField(default=False)
createdAt = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.name)
class Item(models.Model):
user = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
name = models.CharField(max_length=220)
image = models.ImageField(null=True, blank=True)
dish_type = models.ForeignKey(Dishtype, on_delete=models.CASCADE)
item_type = models.ForeignKey(Itemtype, on_delete=models.CASCADE)
description = models.TextField(max_length=10000)
rating = models.DecimalField(max_digits=7, decimal_places=2, blank=True, null=True)
numReviews = models.IntegerField(null=True, blank=True, default=0)
old_price = models.DecimalField(max_digits=11, decimal_places=2)
discount = models.IntegerField(blank=True, null=True)
price = models.DecimalField(max_digits=12, decimal_places=2, blank=True, null=True)
countInStock = models.IntegerField(blank=True, null=True, default=0)
createdAt = models.DateTimeField(auto_now_add=True)
_id = models.AutoField(primary_key=True, editable=False)
def save(self, *args, **kwargs):
self.price = Decimal(self.old_price * (100 - self.discount) / 100)
return super(Item, self).save(*args, **kwargs)
class Meta:
ordering = ['-createdAt']
def __str__(self):
return self.name
#serializer
class RestaurantSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Restaurant
fields = '__all__'
def get_user(self, obj):
user = obj.user
serializer = UserSerializer(user, many=False)
return serializer.data
class ItemSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField(read_only=True)
dish_type = serializers.SerializerMethodField(read_only=True)
item_type = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Item
fields = '__all__'
def get_user(self, obj):
user = obj.user
serializer = RestaurantSerializer(user, many=False)
return serializer.data
def get_dish_type(self, obj):
dish_type = obj.dish_type
serializer = DishtypeSerializer(dish_type, many=False)
return serializer.data
def get_item_type(self, obj):
item_type = obj.item_type
serializer = ItemtypeSerializer(item_type, many=False)
return serializer.data
#views.py
#api_view(['GET'])
#permission_classes([IsAuthenticated])
def getItems(request):
user = request.user
query = request.query_params.get('keyword')
if query == None:
query = ''
cuery = request.query_params.get('keyword1')
if cuery == None:
cuery = ''
items = Item.objects.select_related('user').select_related('dish_type').select_related('item_type').all().filter(
Q(name__icontains = query) | Q(user__name__icontains = query))
else:
restaurant_city = Item.objects.select_related('user').select_related('dish_type').select_related('item_type').all(
).filter(Q(user__city__iexact = cuery))
items = restaurant_city.filter(Q(name__icontains = query) | Q(user__name__icontains = query))
serializer = ItemSerializer(items, many=True)
return Response(serializer.data)
######Updated solved the problem
#filters.py
class ItemFilter(django_filters.FilterSet):
numReviews = django_filters.NumberFilter()
numReviews__gt = django_filters.NumberFilter(field_name='numReviews', lookup_expr='gt')
numReviews__lt = django_filters.NumberFilter(field_name='numReviews', lookup_expr='lt')
name = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = Item
fields = ['_id', 'dish_type__id']
#views
#api_view(['GET'])
#permission_classes([IsAuthenticated])
def getItems(request):
user = request.user
queryset = Item.objects.all()
filterset = ItemFilter(request.GET, queryset=queryset)
if filterset.is_valid():
queryset = filterset.qs
serializer = ItemSerializer(queryset, many=True)
return Response(serializer.data)
now data are passing like this
http://localhost:8000/api/items/?numReviews__gt=20&numReviews__lt=22
You can use queryset and override get_queryset function.
class FooViewSet(GenericViewSet, mixins.ListModelMixin):
authentication_classes = [JSONWebTokenAuthentication]
permission_classes = [IsAuthenticated]
serializer_class = ItemSerializer
def get_queryset(self):
query = self.request.query_params.get('keyword', '')
if not self.request.query_params.get('keyword1'):
items = Item.objects.select_related('user').select_related('dish_type').select_related(
'item_type').all().filter(
Q(name__icontains=query) | Q(user__name__icontains=query))
else:
restaurant_city = Item.objects.select_related('user').select_related('dish_type').select_related(
'item_type').all(
).filter(Q(user__city__iexact=self.request.query_params.get('keyword1', '')))
items = restaurant_city.filter(Q(name__icontains=query) | Q(user__name__icontains=query))
return items

foreign key in django

I have a model for musics and a model for comment of musics:
class music(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
STATUS_CHOICES = (('draft', 'Draft'), ('published', 'Published'),)
music = models.FileField()
music_image = models.ImageField(upload_to="images/")
singer_name = models.CharField(max_length=100)
music_name = models.CharField(max_length=100)
text_of_music = models.TextField()
create = models.DateField(auto_now_add=True, blank=True, null=True)
update = models.DateField(auto_now=True, blank=True, null=True)
publish = models.DateField(default=timezone.now, blank=True, null=True)
slug = models.CharField(max_length=250, unique_for_date='publish')
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
objects = models.Manager()
published = PublishedManager()
class Meta:
ordering = ('-publish',)
def get_absolute_url(self):
return reverse('music:music_detail',
kwargs={"id":self.id})
class comment(models.Model):
# Foreignkey for each music
For = models.ForeignKey(music, on_delete=models.CASCADE, related_name='post')
body = models.CharField(max_length=500)
created_on = models.DateTimeField(auto_now_add=True)
active = models.BooleanField(default=True)
commented_by = models.ForeignKey(User, on_delete=models.CASCADE)
and this is my view:
def music_Detail(request, id=None):
user = request.user
template_name = 'music/music_detail.html'
Music = music.objects.all().filter(id=id)
new_comment = None
Comment = comment.objects.all().filter(active=True)
form = comment_form(data=request.POST)
if request.method == 'POST':
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.For = Music
new_comment.save()
form = comment_form()
return render(request, template_name, {'Music': Music, 'Comment': Comment, 'form': form})
Well, I get this error when I comment:
Cannot assign "<QuerySet [<music: m, majid kharatha>]>": "comment.For" must be a "music" instance.
How can I solve this problem and how can I display the information of the user who left this comment?
As the error says, you'll have to assign a single Music, not a queryset.
Instead of filter()ing to get a new queryset containing a single music,
Music = music.objects.all().filter(id=id)
you want to get() a single one:
Music = music.objects.get(id=id)

Saving data once (to be able to load to images to server) then updating the same instance after some changes

I'm saving the data from the post request a first time because I need the images to be uploaded to the server like the "upload_image" function suggests.
At the same time I have a couple of fields that are null and need to have some values via some external functions.
And then I need to save the whole object in the database.
The problem that I'm facing is that it saves the data twice in the database.
And the first saved object has all attributes null except for passengerPhoto, passengerPassport and agent. ( No errors shown btw)
Any ideas, please?
Thanks a lot!
#VIEW
class IdentityCheckView(CreateAPIView, generics.ListAPIView):
serializer_class = IdentityCheckSerializer
permission_classes = [permissions.AllowAny]
def get_queryset(self):
request = self.request
qs = IdentityCheck.objects.all()
query = self.request.GET.get('q')
if query is not None:
qs = qs.filter(name__icontains=query)
return qs
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
if(serializer.is_valid()):
res = self.create(request, *args, **kwargs)
image = FaceRecognition.imageMatch(res.data['passengerPhoto'], res.data['passengerPassport'])
wanted = WantedPro.criminalMatch(res.data['passengerPhoto'])
passport_json = OCR.passportMatch(res.data['passengerPassport'])
image_json = json.loads(image)
firstName = passport_json['names']
lastName = passport_json['surname']
nationality = passport_json['country']
birthDate = passport_json['date_of_birth']
gender = passport_json['sex']
ableToBoard = bool(wanted) & bool(image_json['match']) & bool(passport_json['valid_expiration_date'])
serializer.update(
id=res.data['id'],
firstName=firstName,
lastName=lastName,
nationality=nationality,
birthDate=birthDate,
gender=gender,
ableToBoard=ableToBoard)
return Response({"image": image_json, "passport": passport_json, "wanted": wanted}, status=200)
def perform_create(self, serializer):
res = serializer.save(agent=self.request.user)
#SERIALIZER
class IdentityCheckSerializer(serializers.ModelSerializer):
class Meta:
model = IdentityCheck
fields = '__all__'
read_only_fields = ['agent', 'id']
#MODEL
def upload_image(instance, filename):
return "media/check/{agent}/{date}/{filename}".format(agent=instance.agent,date=datetime.datetime.today().strftime('%d-%m-%Y'), filename=filename)
class IdentityCheckQuerySet(models.QuerySet):
pass
class IdentityCheckManager(models.Manager):
def get_queryset(self):
return IdentityCheckQuerySet(self.model,using=self._db)
class IdentityCheck(models.Model):
agent = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
passengerPhoto = models.ImageField(upload_to=upload_image, null=False, blank=False)
passengerPassport = models.ImageField(upload_to=upload_image, null=False, blank=False)
lastName = models.CharField(max_length=255, null=True, blank=True)
firstName = models.CharField(max_length=255, null=True, blank=True)
birthDate = models.DateField(null=True, blank=True)
nationality = models.CharField(max_length=255, null=True, blank=True)
gender = models.CharField(max_length=1, null=True, blank=True)
ableToBoard = models.BooleanField(null=False, blank=False, default=False)
timestamp = models.DateTimeField(auto_now_add=True)
objects = IdentityCheckManager()

How to upload multiple images for my product model in django?

I want to upload multiple images of the product so how can I do that? Django version is 2.1 and how to store the multiple files as well.
Using python3
My model
class Product(models.Model):
owner = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
name = models.CharField(max_length=33, blank=True)
description = models.TextField()
postdate = models.DateTimeField(auto_now_add=True, blank=False)
duration = models.IntegerField(null=True, blank=True)
image = models.FileField(upload_to=product_directory_path, blank=False, default='default.jpg')
My View
def addProduct(request):
if request.method == 'GET':
if request.user.is_authenticated:
return render(request, 'postAd.html')
if request.method == 'POST' and request.FILES.get('image'):
if request.user.is_authenticated:
user = User.objects.get(id=request.user.id)
owner = UserProfile.objects.get(email=user.email)
image = request.FILES.get('image')
name = request.POST['name']
description = request.POST['desc']
pr = Product(owner=owner, name=name, image=image, description=description, category=category, price=price, ptype=ptype)
pr.save()
return HttpResponseRedirect(reverse('ors:dashboard'))
you can try this in models:
class Product(models.Model):
owner = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
name = models.CharField(max_length=33, blank=True)
description = models.TextField()
postdate = models.DateTimeField(auto_now_add=True, blank=False)
duration = models.IntegerField(null=True, blank=True)
image = models.FileField(upload_to='/image/, blank=False,
default='default.jpg')
class ImageProduct(models.Model):
Product=models.ForeignKey(Product,on_delete=models.CASCADE)
image=models.imageField(upload_to='/image/')
ref:
https://medium.com/ibisdev/upload-multiple-images-to-a-model-with-django-fd00d8551a1c
forms.py
from django import forms
class UploadFileForm(forms.Form):
file_1 = forms.FileField()
file_2 = forms.FileField()
....
....
file_n = forms.FileField()
add below code in your html file in order to get file attribute from forms.py.
{{ form.file1 }} #for 1st file
{{ form.file2 }} #for 2nd file
add below code in views.py and
No need to check user authentication in GET method (request).
def addProduct(request):
if request.method == 'GET':
return render(request, 'postAd.html')
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
file = request.FILES['file1']
file1 = request.FILES['file2']
#convert byte code to string
file_str = file.read().decode("utf-8")
file_str1 = file1.read().decode("utf-8")
return render(request, "postAd.html")
You can explore this project for more detail on uploading more than one file.click here

KeyError at /partners/create/ 'name'

I have a model Partner that is related to Product by a one to many relationships. I am using inlineformsets for the Product and I am gettig the following error which I don't understand:"KeyError at /partners/create/ 'name'"
my views are as follows:
def partner_create(request):
if not request.user.is_staff or not request.user.is_superuser:
raise Http404
ProductFormSet = inlineformset_factory(Partner, Product, form=ProductForm, extra=3, min_num=1)
if request.method == 'POST':
partnerForm = PartnerForm(request.POST or None, request.FILES or None)
formset = ProductFormSet(request.POST, request.FILES, queryset=Product.objects.none())
if partnerForm.is_valid() and formset.is_valid():
instance = partnerForm.save(commit=False)
instance.save()
for form in formset.cleaned_data:
name = form["name"]
description = form["description"]
price = form["price"]
image = form["image"]
product = Product(partner=instance, name=name, description=description, price=price, product_image=image)
product.save()
messages.success(request, "Partner Successfully Created")
else:
print partnerForm.errors, formset.errors
else:
partnerForm = PartnerForm()
formset = ProductFormSet(queryset=Product.objects.none())
return render(request, "partner_form.html", {"partnerForm": partnerForm, "formset": formset})
my forms.py are as follows:
class PartnerForm(forms.ModelForm):
mission = forms.CharField(widget=PagedownWidget(show_preview=False))
vision = forms.CharField(widget=PagedownWidget(show_preview=False))
# publish = forms.DateField(widget=forms.SelectDateWidget)
class Meta:
model = Partner
fields = [
"name",
"logo",
"banner_image",
"mission",
"vision",
"website_link",
"fb_link",
"twitter_link",
"ig_link",
]
class ProductForm(forms.ModelForm):
image = forms.ImageField(label='Image')
class Meta:
model = Product
fields = [
"partner",
"name",
"description",
"price",
"image",
]
My models.py are as follows:
def upload_location(instance, filename):
#filebase, extension = filename.split(".")
# return "%s/%s" %(instance.name, instance.id)
PartnerModel = instance.__class__
exists = PartnerModel.objects.exists()
if exists:
new_id = PartnerModel.objects.order_by("id").last().id + 1
else:
new_id = 1
file_name, file_extension = filename.split('.')
return "%s/%s/%s-%s.%s" %('partner',instance.name, file_name, new_id, file_extension)
class Partner(models.Model):
name = models.CharField(max_length=120)
logo = models.ImageField(upload_to=upload_location,
null=True,
blank=True,
width_field="width_field",
height_field="height_field")
banner_image = models.ImageField(upload_to=upload_location,
null=True,
blank=True,
width_field="width_field",
height_field="height_field")
mission = models.TextField()
vision = models.TextField()
height_field = models.IntegerField(default=0)
width_field = models.IntegerField(default=0)
# text = models.TextField()
website_link = models.CharField(max_length=120)
fb_link = models.CharField(max_length=120)
twitter_link = models.CharField(max_length=120)
ig_link = models.CharField(max_length=120)
slug = models.SlugField(unique=True)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
def __unicode__(self):
return self.name
def get_absolute_url(self):
return reverse("partners:detail", kwargs={"slug": self.slug})
# return "/partner/%s/" %(self.id)
def get_markdown(self):
mission = self.mission
markdown_text = markdown(mission)
return mark_safe(markdown_text)
#Creating a many to one relationship so that one can upload many Products
class Product(models.Model):
partner = models.ForeignKey(Partner, default=None)
name = models.CharField(max_length=120)
product_image = models.ImageField(upload_to=upload_location,
# product_image = models.ImageField(upload_to= (upload_location + '/' + name), Something like this need to append actual product name so these dont just get dumped in the media for partners
null=True,
blank=True,
width_field="width_field",
height_field="height_field",
verbose_name='Image',)
description = models.TextField()
price = models.DecimalField(max_digits=6, decimal_places=2, null=True)
height_field = models.IntegerField(default=0)
width_field = models.IntegerField(default=0)
def __unicode__(self): # __unicode__ on Python 2
return self.name
I would really like to understand what is going on as well as how to fix it or a hint in the right direction. Thank you in advance for your help!
To find out why you're getting the error, you should add some printing or logging to your code. What is the value of formset.cleaned_data? Is it what you think it should be?
There's a simpler approach that looping through the formset's cleaned_data. The docs show how to save a formset. You can save with commit=False, then set the partner field before saving to the database.
products = formset.save(commit=False)
for product in products:
product.partner=instance
product.save()
Note that if you do this, you should probably switch to a modelformset_factory instead of inlineformset_factory, and remove partner from the list of the fields of the ProductForm.
The formset form save method seems incorrect, use something like
for form in formset.cleaned_data:
if form.is_valid():
name = form.cleaned_data.get("name")
description = form.cleaned_data.get("description")
price = form.cleaned_data.get("price")
image = form.cleaned_data.get("image")
Please lemme know if this works :)