django models imagefield upload_to method not working - django

I am using create view to create a model instance (product).
Evey thing is working fine bt after doing some new migrations
i can't get the uploaded image, instead getting default image.
I think upload_to method of models isn't working.
i also used this in my urls
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
This is my settigs vars:
STATIC_URL = '/static/'
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
MEDIA_URL = '/media/'
This is my models.py:
class Product(models.Model):
TYPE = [
('Sell','Sell'),
('Rent','Rent'),
('Sell or Rent','Sell or Rent'),
]
owner = models.ForeignKey(Owner, on_delete=models.CASCADE)
title = models.CharField(max_length = 25)
type = models.CharField(max_length = 12, choices = TYPE, default = 'Sell')
price = models.IntegerField()
description = models.TextField(default="No Description Given")
image = models.ImageField(default='default.jpeg', upload_to='product')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('store')
and this is my views.py:
class ProductCreateView(LoginRequiredMixin, CreateView):
model = Product
fields = ['title','type', 'price','description', 'image']
def form_valid(self, form):
print(self.request.POST)
owner , created = Owner.objects.get_or_create(user=self.request.user)
form.instance.owner = self.request.user.owner
return super().form_valid(form)
I am getting default image for every new product created.
Thanks
P.S. when i am adding product from admin panel then every thing is working fine.

Related

How to create seperate POST request for imagefield in DRF

I need to make a separate API for the image file. How can I achieve this?
models.py
class Organization(models.Model):
code = models.CharField(max_length=25, null=False, unique=True)
name = models.CharField(max_length=100, null=False)
location = models.ForeignKey(Location, on_delete=models.RESTRICT)
description = models.TextField()
total_of_visas = models.IntegerField(null=False, default=0)
base_currency = models.ForeignKey(Currency, on_delete=models.RESTRICT)
logo_filename = models.ImageField(upload_to='uploads/')
serializers.py
class OrganizationSerializer(serializers.ModelSerializer):
location = serializers.CharField(read_only=True, source="location.name")
base_currency = serializers.CharField(read_only=True, source="base_currency.currency_master")
location_id = serializers.IntegerField(write_only=True, source="location.id")
base_currency_id = serializers.IntegerField(write_only=True, source="base_currency.id")
class Meta:
model = Organization
fields = ["id", "name", "location", "mol_number", "corporate_id", "corporate_name",
"routing_code", "iban", "description", "total_of_visas", "base_currency", "logo_filename",
"location_id", "base_currency_id"]
def validate(self, data):
content = data.get("content", None)
request = self.context['request']
if not request.FILES and not content:
raise serializers.ValidationError("Content or an Image must be provided")
return data
def create(self, validated_data):
....
def update(self, instance, validated_data):
....
views.py
class OrganizationViewSet(viewsets.ModelViewSet):
queryset = Organization.objects.all()
serializer_class = OrganizationSerializer
lookup_field = 'id'
urls.py
router = routers.DefaultRouter()
router.register('organization', OrganizationViewSet, basename='organization')
urlpatterns = [
path('', include(router.urls)),
]+static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
I don't have idea how to make POST request for image field from postman. I've been stuck here for a long time. Any help is appreciated.
if you want to update the image field separately you just have to create a separate serializer for it
class OrganizationImageSerializer(serializers.ModelSerializer):
logo_filename = serializers.ImageField()
class Meta:
model = Organization
fields = ["logo_filename"]
view.py
class OrganizationImageView(generics.UpdateAPIView):# or `generics.RetrieveUpdateAPIView` if you also want to retriev the current one before updating it
serializer_class = OrganizationImageSerializer
permission_classes = [IsAuthenticated, ]
def get_queryset(self):
queryset = Organization.objects.filter(id=self.kwargs['pk'])
return queryset
urls.py
from .views import OrganizationImageView
urlpatterns = [
...
path('update_org/<int:pk>', OrganizationImageView.as_view(), name='OrganizationImageUpdater'),
]

Django- how to render images in templates uploaded from admin?

I want to render images that I uploaded from my Django admin in my template views. Since I need to upload multiple images at a time, I declared a separate model, ShowPhoto, with a foreign key attached to my Problem model:
models.py
class Problem(models.Model):
slug = models.SlugField(null = False, unique = True, max_length = 255)
topic = models.ForeignKey(Topic, on_delete = models.CASCADE)
free = models.CharField(max_length = 1, choices = Free)
#problem when introducing UUID field
traceID = models.UUIDField(default=uuid.uuid4, editable = True)
#use meta tags to optimize SEO
metaTags = models.TextField(default = "")
questionToProblem = models.TextField()
class ShowPhoto(models.Model):
show = models.ForeignKey(Problem, on_delete = models.CASCADE, related_name = "photos")
photo = models.ImageField()
class Meta:
verbose_name = 'Solution Image'
verbose_name_plural = 'Solution Images'
Thus, in my admin.py, I also added:
class AdminImageWidget(AdminFileWidget):
def render(self, name, value, attrs=None, renderer = None):
output = []
if value and getattr(value, "url", None):
image_url = value.url
file_name = str(value)
output.append(u' <img src = "%s" alt="%s" width="600" height="600" style="object-fit: cover;"/> %s ' % \
(image_url, image_url, file_name, _('')))
output.append(super(AdminFileWidget, self).render(name, value, attrs))
return mark_safe(u''.join(output))
class ShowPhotoInline(admin.TabularInline):
model = ShowPhoto
formfield_overrides = {models.ImageField: {'widget': AdminImageWidget}}
#admin.register(Problem)
class ProblemModelAdmin(admin.ModelAdmin):
form = ProblemForm
list_display = ('questionToProblem', 'topic', 'free', 'traceID')
search_fields = ('questionToProblem', 'traceID')
readonly_fields = ('traceID',)
fields = ('slug', 'traceID', 'topic', 'free', 'metaTags', 'questionToProblem', 'solutionToProblem', 'photos') #'solution_on_webpage', 'photos')
inlines = [ShowPhotoInline]
def save_related(self, request, form, formsets, change):
super().save_related(request, form, formsets, change)
form.save_photos(form.instance)
How would I write a view to render the images that I upload in my admin? When I try to write a QuerySet using the filter command like this:
views.py
def displaySolution(request, topic_slug, problem_slug):
try:
solution = Problem.objects.get(topic__slug = topic_slug, slug = problem_slug)
image = ShowPhoto.objects.filter(show = solution)
except Exception as e:
raise e
return render(request, 'solution.html', {'solution' : solution, 'image' : image})
The QuerySet is called, but the rendering in the template is still blank. What do I need to do to fix it?
Have you tried to specify the local path you want your images to be uploaded, like this:
class ShowPhoto(models.Model):
show = models.ForeignKey(Problem, on_delete = models.CASCADE, related_name = "photos")
photo = models.ImageField(upload_to = 'static/img')
Don't forget to run python manage.py makemigrations and python manage.py migrate after changing models.py

How to construct url path with two detailview

I have following url patterns
urlpatterns = [
path('', CategoryListView.as_view(), name='forum'),
path('category/<int:pk>/', CategoryDetailView.as_view(), name='forum-detail'),
]
Inside the CategoryDetailView I will list the posts related to that category. So, when I click the any of the post I want the post detail view inside the category, because when I will create post with CreateView class I want category already predefined. I could also do the following
path('post/<int:pk>/', ForumPostDetailView.as_view(), name='forum-post-detail'),
path('post/new/', ForumPostCreateView.as_view(), name='forum-post-create'),
]
In this case user should choose the category by himself when he or she will try to create the post. But I want the category to be chosen already something like this ( I know this is wrong)
path('category/<int:pk>/post/<int:pk>/', ForumPostDetailView.as_view(), name='forum-post-detail'),
path('category/<int:pk>/post/new/', ForumPostCreateView.as_view(), name='forum-post-create'),
]
my view file and models are like this:
class ForumPostCreateView(CreateView):
model = PostForum
fields = ['title', 'content']
template_name = 'forum/forum_post_form.html'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class Category(models.Model):
image = models.ImageField(default='category.png', upload_to='category_pics')
title = models.CharField(max_length=100)
content = models.CharField(max_length=1200)
date_posted = models.DateTimeField(auto_now=True)
class PostForum(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
So how to do it? Now it shows
IntegrityError
null value in column "category_id" violates not-null constraint
Set the category.id in urls.py
path('category/<int:cat_id>/post/new/', ForumPostCreateView.as_view(), name='forum-post-create')
check if it exists in your view
class ForumPostCreateView(CreateView):
category = None
def despatch(self, *args, **kwargs):
super().despatch(*args, **kwargs)
if 'cat_id' in self.kwargs:
self.category = Category.objects.get(id=cat_id)
Now you can use it in your form when you initialise the form

Upload and Display Image in Django Rest Framework via FileField or ImageField

I want to upload an image to my Django Rest API and click the link I get and then see the actual image (like any other image on the internet), this is so I can then display the image in my mobile app.
This is my code:
class Assignment(models.Model):
name = models.CharField(max_length=100)
file = models.FileField(blank=False, null=False)
class Meta:
verbose_name_plural = 'Assignments'
def __str__(self):
return "{name}".format(name=self.name)
class AssignmentSerializer(serializers.ModelSerializer):
class Meta:
model = Assignment
fields = ('id', 'name', 'image')
class AssignmentView(viewsets.ModelViewSet):
queryset = Assignment.objects.all()
serializer_class = AssignmentSerializer
router = routers.DefaultRouter()
router.register('assignments', views.AssignmentView),
urlpatterns = [
path('', include(router.urls)),
]
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('example.urls')),
]
//Settings
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
When I click an image in the Rest API I get en error! {"detail":"Not found."}
You can edit your serializer, add a custom method that returns the URL from the file field
class AssignmentSerializer(serializers.ModelSerializer):
class Meta:
model = Assignment
fields = ('id', 'name', 'image', 'url')
url = serializers.SerializerMethodField(source='get_url')
def get_url(self, assignment):
return assignment.file.url
I have tried with your code in my local PC, there is only one error that I get, and it is:
Field name `image` is not valid for model `Assignment`.
which arose from your serializer. You declare the field name file in your model and tried to get a field named image. Though you can change the original field name in your serializer by following way:
image = serializers.FileField(source='file')
And thus your serializer class will be as following:
class AssignmentSerializer(serializers.ModelSerializer):
image = serializers.FileField(source='file')
class Meta:
model = Assignment
fields = ('id', 'name', 'image')
Otherwise, just keep the field name as same as the model.
I've tried with your code and I found both file and image in my directory and also can browse those files.
If you still face any problem, try with the following lines of code in your models.py
from django.conf import settings
from django.core.files.storage import FileSystemStorage
image_storage = FileSystemStorage(
# Physical file location ROOT
location='{0}/'.format(settings.MEDIA_ROOT),
# Url for file
base_url='{0}/'.format(settings.MEDIA_URL),
)
def file_directory_path(instance, filename):
return 'files/{0}'.format(filename)
class Assignment(models.Model):
name = models.CharField(max_length=100)
file = models.FileField(upload_to=file_directory_path, storage=image_storage, blank=False,null=False)
class Meta:
verbose_name_plural = 'Assignments'
def __str__(self):
return "{name}".format(name=self.name)

Why am I seeing the following error in Django?

So, I have a user form in my Django project. After Submitting the form I want to redirect the user to another form (for additional details). But I am seeing the following error
NoReverseMatch at /incubators/add-incuabtor/
Reverse for 'details' with keyword arguments '{'pk': 15}' not found. 1 pattern(s) tried: ['incubators/(?P<incubator_id>[0-9]+)']
Request Method: POST
Request URL: http://127.0.0.1:8000/incubators/add-incuabtor/
I have the following url pattern:
app_name = 'main'
urlpatterns = [
url(r'^home/', views.home, name='home'), # Home page
url(r'incubators/$', views.incubators, name='incubators'), # Incubator list page
url(r'about/', views.about, name='about'), # Websie about page
url(r'results', views.result, name = 'result'), # For search function
url(r'incubators/(?P<incubator_id>[0-9]+)', views.details, name = 'details'), # shows details of incubators
url(r'incubators/add-incuabtor/$', views.AddIncubator.as_view(), name = 'add-incubator'), # Adding Inc
url(r'/add-details/', views.AddDetails.as_view(), name = 'add-details'), #for additional details
]
Following is my models.py
class Incubators(models.Model): # These are our database files for
the Incubator Portal
incubator_name = models.CharField(max_length=30)
owner = models.CharField(max_length=30)
city_location = models.CharField(max_length=30)
description = models.TextField(max_length=100)
logo = models.FileField()
verify = models.BooleanField(default = False)
def get_absolute_url(self):
return reverse('main:details', kwargs={'pk': self.pk})
def __str__(self): # Displays the following stuff when a query is made
return self.incubator_name + '-' + self.owner
class Details(models.Model):
incubator = models.ForeignKey(Incubators, on_delete = models.CASCADE, related_name='banana_pudding')
inc_name = models.CharField(max_length = 30)
inc_img = models.FileField()
inc_contact = models.CharField(max_length = 600, default = "Enter all available means of contacting")
inc_details = models.TextField(max_length= 2500)
inc_address = models.TextField(max_length = 600, default = "Address")
inc_doc = models.FileField()
inc_policy = models.FileField()
def __str__(self):
return self.inc_name
And I have the following views.py
class AddIncubator(CreateView):
model = Incubators
fields = ['incubator_name', 'owner', 'city_location', 'description', 'logo']
class AddDetails(CreateView):
model = Details
field = ['incubator', 'inc_name']
Problem is with you url.
In urls.py, you detail url is
url(r'incubators/(?P<incubator_id>[0-9]+)', views.details, name = 'details'),
Change it to
url(r'incubators/(?P<pk>[0-9]+)', views.details, name = 'details'),
or you can change reverse url in you models as:
def get_absolute_url(self):
return reverse('main:details', kwargs={'incubator_id': self.pk})