I have been trying to design a rest API using Django Rest Framework for creating mobile application. I could design an API for Store list which shows store owner(merchant) information, store information, category of store and Product but product image is not displayed. Why my code is not showing product image? Could anyone please provide me an idea or advice why it is not working?
My code
my models.py
class Store(models.Model):
merchant = models.ForeignKey(Merchant)
name_of_store = models.CharField(max_length=100)
store_off_day = MultiSelectField(choices=DAY, max_length=7, default='Sat')
store_categories = models.ManyToManyField('StoreCategory',blank=True)
class Meta:
verbose_name = 'Store'
class Product(models.Model):
store = models.ForeignKey(Store)
name_of_product = models.CharField(max_length=120)
description = models.TextField(blank=True, null=True)
price = models.DecimalField(decimal_places=2, max_digits=20)
# categories = models.ManyToManyField('Category',blank=True)
class ProductImage(models.Model):
product = models.ForeignKey(Product)
image = models.ImageField(upload_to='products/images/')
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
class StoreCategory(models.Model):
product = models.ForeignKey(Product,null=True, on_delete=models.CASCADE,related_name="store_category")
store_category = models.CharField(choices=STORE_CATEGORIES, default='GROCERY', max_length=10)
Serializers.py
class ProductImageSerializer(ModelSerializer):
class Meta:
model = ProductImage
fields = ('id','image', )
class ProductSerializers(ModelSerializer):
image = ProductImageSerializer(many=True,read_only=True)
class Meta:
model = Product
fields=('id','image','name_of_product','description','price','active',)
class StoreCategorySerializer(ModelSerializer):
product = ProductSerializers(read_only=True)
class Meta:
model = StoreCategory
class StoreSerializer(ModelSerializer):
# url = HyperlinkedIdentityField(view_name='stores_detail_api')
store_categories = StoreCategorySerializer(many=True)
merchant = MerchantSerializer(read_only=True)
class Meta:
model = Store
fields=("id",
# "url",
"merchant",
"store_categories",
"name_of_store",
"store_contact_number",
"store_off_day",
)
My API
In your models.py create:
import os
Remove Product foreign key from your ProductImage model:
class ProductImage(models.Model):
image = models.ImageField(upload_to='products/images/')
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
#property
def imagename(self):
return str(os.path.basename(self.image.name))
Add image foreign key to your Product instead
class Product(models.Model):
image = models.ForeignKey(ProductImage,blank=True,null=True)
store = models.ForeignKey(Store)
name_of_product = models.CharField(max_length=120)
description = models.TextField(blank=True, null=True)
price = models.DecimalField(decimal_places=2, max_digits=20)
# categories = models.ManyToManyField('Category',blank=True)
and then in your serializers.py
class ProductImageSerializer(ModelSerializer):
class Meta:
model = ProductImage
fields = ('id','imagename', )
class ProductSerializers(ModelSerializer):
image = ProductImageSerializer(many=False,read_only=True) #only one image used
class Meta:
model = Product
fields=('id','image','name_of_product','description','price','active',)
So this way you'll get the actual image name and location.
Related
In models.py:
ingredient_name = models.CharField(primary_key=True, max_length=50)
category = models.CharField(max_length=50)
stock = models.IntegerField()
unit = models.CharField(max_length=10)
def __str__(this):
return this.ingredient_name
class Recipe(models.Model):
recipe_name = models.CharField(primary_key=True, max_length=50)
ingredients = models.ManyToManyField(Ingredient, through='RecipeIngredient')
sales_price = models.IntegerField()
def __str__(this):
return this.recipe_name
class RecipeIngredient(models.Model):
recipe_name = models.ForeignKey('Recipe', models.CASCADE)
ingredient_name = models.ForeignKey('Ingredient', models.CASCADE)
quantity = models.IntegerField()
In forms.py:
class RecipeFormCreate(ModelForm):
class Meta:
model = Recipe
fields = ('recipe_name', 'ingredients', 'sales_price')
The created form looks like this:
Form generated by RecipeFormCreate, with the "Ingredients" field having a list of items that can be selected
Is there a way to allow the end user of this product to set the ingredient's quantity (a field added by the RecipeIngredient model) within the RecipeFormCreate form?
I have a model Product with a User and ProductImages as foreign key.
models.py
class User(AbstractBaseUser):
...
class ProductImages(models.Model):
image_type = models.CharField(max_length=33,default='image_type')
image_file = models.ImageField(
upload_to='images/',
null=True,
blank=True,
default='magickhat-profile.jpg'
)
class Product(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
productimages = models.ForeignKey(ProductImages, on_delete=models.CASCADE)
product_title = models.CharField(max_length=255, default='product_title')
product_description = models.CharField(max_length=255, default='product_description')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
product_view = models.IntegerField(default=0)
def __str__(self):
return self.product_title
def get_absolute_url(self):
return reverse('product_change', kwargs={'pk': self.pk})
forms.py
class ProductForm(ModelForm):
productimages = forms.ImageField()
CHOICES_STATUS = (('Pronto', 'Pronto'),('Em obras', 'Em obras'),('Lançamento', 'Lançamento'),)
product_status = forms.ChoiceField(choices=CHOICES_STATUS)
product_title = forms.CharField()
product_description = forms.CharField()
class Meta:
model = Product
fields = '__all__'
admin.py
class AdminProductModel(admin.ModelAdmin):
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.filter(user_id=request.user)
kadmin.register(User, UserAdmin)
kadmin.register(Product, AdminProductModel)
But in the admin Product model the field for image is redering as select field no ImageField
My purpose is add a upload image field on django model administration.
If i use ImageField direct on Product model the field is redering ok, but i need a external table to store that image becouse is a multimage upload, so i need a foreing key.
How is the right way to that purpose.
I see other questions about that, but the majority is old versions, and is not for custom AdminSite, like me.
Django 3.2 version Class View Based
As suggested in comments i change the relationship between models like:
uptade
models.py
class Product(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
product_title = models.CharField(max_length=255, default='product_title')
product_description = models.CharField(max_length=255, default='product_description')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
product_view = models.IntegerField(default=0)
def __str__(self):
return self.product_title
def get_absolute_url(self):
return reverse('product_change', kwargs={'pk': self.pk})
class ProductImages(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
image_type = models.CharField(max_length=33,default='image_type')
image_file = models.ImageField(
upload_to='images/',
null=True,
blank=True,
default='magickhat-profile.jpg'
)
forms.py
class ProductForm(ModelForm):
image_file = forms.ImageField()
CHOICES_STATUS = (('Pronto', 'Pronto'),('Em obras', 'Em obras'),('Lançamento', 'Lançamento'),)
product_status = forms.ChoiceField(choices=CHOICES_STATUS)
product_title = forms.CharField()
product_description = forms.CharField()
class Meta:
model = Product
fields = '__all__'
My question now is, how bring that field image_file from ProducImages to ProductForm?
Am guessing you want to be able to post multiple images to your database in that case you should use StackedInline to merge the two models together then you can have multiple fields in the database to upload more images. You do that through the admin.py like so:
class ProductImagesAdmin(admin.StackedInline):
model = ProductImages
class ProductAdmin(admin.ModelAdmin):
# The field your want to display
list_display = ['','']
# Here you link the models together
inlines = [ ProductImagesAdmin]
To upload multiple images from the frontend you will need a form to handle
class ProductImagesForm(forms.ModelForm):
class Meta:
model = ProductImages
fields = ['image_file']
widget = forms.ClearableFileInput(attrs={'multiple':True})
View to handle multiple images
def upload_product_images(request):
form = ProductImagesForm(request.POST, request.FILES)
files = requests.FILES.getlist['image_file']
title = request.POST['product_title']
description = request.POST['descritpion']
product = Product(product_title=title,product_description=description)
product.save()
# You would have to make some iterations through the list images in order topost
# them to your database
if form.is_valid:
for file in files:
prod_image_data = ProductImages(product=product, image=file)
prod_image_data.save()
return redirect(# redirect to anywhere you)
My models:
class Ingredient(models.Model):
BASE_UNIT_CHOICES = [("g", "Grams"), ("ml", "Mililiters")]
CURRENCY_CHOICES = [("USD", "US Dollars"), ("EUR", "Euro")]
ingredient_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=200)
base_unit = models.CharField(max_length=2, choices=BASE_UNIT_CHOICES)
cost_per_base_unit = models.FloatField()
currency = models.CharField(
max_length=3, choices=CURRENCY_CHOICES, default="EUR")
def __str__(self):
return self.name
class RecipeIngredient(models.Model):
quantity = models.FloatField()
ingredient_id = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
def __str__(self):
return f"{self.quantity} / {self.ingredient_id}"
class Recipe(models.Model):
recipe_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=200)
ingredients = models.ManyToManyField(RecipeIngredient)
date_created = models.DateTimeField('Date Created')
def __str__(self):
return f"{self.name}, {self.ingredients}"
When I use the admin page, it has this + button that allows me to create new ingredient/quantity combinations
like this
But when I try to use it from a form in my code it looks like
this
Here is my form code:
class AddRecipeForm(forms.ModelForm):
class Meta:
model = Recipe
fields = ['name', 'ingredients', 'date_created']
You should write the 'widgets' for each field in you Form that need configuration.
Check the documentation 'Widgets in forms', or even, you can define your own Widgets.
I have multiple models and i want to display them all on one page in django admin.
Some of these have no relationship(fk,onetoone,mm).
how i can achieve that?
class Category(models.Model):
name = models.CharField(max_length=100)
class Industry(models.Model):
name = models.CharField(max_length=100)
class SampleImages(models.Model):
image = models.ImageField(upload_to='images/tile_images')
category = models.ManyToManyField(Category)
industry = models.ManyToManyField(Industry)
class SampleColor(models.Model):
image = models.ImageField(upload_to='images/tile_color')
name = models.CharField(max_length=25)
class OrderDetail(models.Model):
name_in_logo = models.CharField( max_length=150)
slogan = models.CharField(max_length=20)
describe_website_and_audience = models.TextField()
I get an error while trying to post store, product, category and merchant data. The error is ValueError at /api/stores/create/
save() prohibited to prevent data loss due to unsaved related object 'product'.
The code
class Store(models.Model):
merchant = models.ForeignKey(User)
name_of_legal_entity = models.CharField(max_length=250)
pan_number = models.CharField(max_length=20)
registered_office_address = models.CharField(max_length=200)
name_of_store = models.CharField(max_length=100)
store_off_day = MultiSelectField(choices=DAY, max_length=7, default='Sat')
store_categories = models.ManyToManyField('StoreCategory',blank=True)
class Product(models.Model):
store = models.ForeignKey(Store)
image = models.ForeignKey('ProductImage',blank=True,null=True)
name_of_product = models.CharField(max_length=120)
description = models.TextField(blank=True, null=True)
price = models.DecimalField(decimal_places=2, max_digits=20)
active = models.BooleanField(default=True)
class ProductImage(models.Model):
image = models.ImageField(upload_to='products/images/')
#property
def imageName(self):
return str(os.path.basename(self.image.name))
class StoreCategory(models.Model):
product = models.ForeignKey(Product,null=True, on_delete=models.CASCADE,related_name="store_category")
store_category = models.CharField(choices=STORE_CATEGORIES, default='GROCERY', max_length=10)
Serializers.py
class ProductSerializers(ModelSerializer):
image = ProductImageSerializer()
class Meta:
model = Product
fields=('id','image','name_of_product','description','price','active',)
class StoreCategorySerializer(ModelSerializer):
product = ProductSerializers()
class Meta:
model = StoreCategory
class StoreCreateSerializer(ModelSerializer):
store_categories = StoreCategorySerializer()
merchant = UserSerializer()
class Meta:
model = Store
fields=("id",
"merchant",
"store_categories",
"name_of_legal_entity",
"pan_number",
"registered_office_address",
"name_of_store",
"store_contact_number",
"store_long",
"store_lat",
"store_start_time",
"store_end_time",
"store_off_day",
)
def create(self,validated_data):
store_categories_data = validated_data.pop('store_categories')
merchant_data = validated_data.pop('merchant')
for merchantKey, merchantVal in merchant_data.items():
try:
merchant,created = User.objects.get_or_create(username=merchantVal)
print('merchant',merchant)
print(type(merchant))
validated_data['merchant']=merchant
store = Store.objects.create(**validated_data)
image = store_categories_data["product"].pop("image")
image_instance = ProductImage(**image)
product = store_categories_data["product"]
product_instance = Product(
image=image_instance,
name_of_product=product['name_of_product'],
description=product['description'],
price=product['price'],
active=product['active']
)
store_category = store_categories_data['store_category']
print('store_category',store_category)
store_category = StoreCategory(product=product_instance, store_category=store_category)
store_category.product.store = store
store_category.save()
return store
except User.DoesNotExist:
raise NotFound('not found')
Use object.save(commit=False) thing.
https://docs.djangoproject.com/en/1.9/topics/forms/modelforms/#the-save-method this documentation will help it.