I'm writing a project where you can add photos to a website from a disk or other sites. In jquery I wrote a book marklet where I can add pictures from other site. But I have problem with uploading images from the disc. I wrote model, modelform, views and html file. When I choose a img file in the form all looks OK. I'm moved to image list web page, but there is not file what I whant to upload. Image file not saving. I don't know what I did wrong. Below is my code:
models.py
class Image(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
related_name='images_created')
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200,
blank=True)
url = models.URLField(blank=True)
image = models.ImageField(upload_to='images/%Y/%m/%d')
description = models.TextField(blank=True)
created = models.DateField(auto_now_add=True,
db_index=True)
users_like = models.ManyToManyField(settings.AUTH_USER_MODEL,
related_name='images_liked',
blank=True)
total_likes = models.PositiveIntegerField(db_index=True, default=0)
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Image, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('images:detail', args=[self.id, self.slug])
class Meta:
ordering = ["-image"]
forms.py
class ImageCreateForm(forms.ModelForm):
class Meta:
model = Image
fields = ('title', 'url', 'description')
widgets = {
'url': forms.HiddenInput,
}
def clean_url(self):
url = self.cleaned_data['url']
valid_extensions = ['jpg', 'jpeg']
extension = url.rsplit('.', 1)[1].lower()
if extension not in valid_extensions:
raise forms.ValidationError('Podany adres URL nie zawiera ' \
'obrazów w obsługiwanym formacie.')
return url
def save(self, force_insert=False,
force_update=False,
commit=True):
image = super(ImageCreateForm, self).save(commit=False)
image_url = self.cleaned_data['url']
image_name = '{}.{}'.format(slugify(image.title),
image_url.rsplit('.', 1)[1].lower())
# Pobranie pliku obrazu z podanego adresu URL.
response = request.urlopen(image_url)
image.image.save(image_name,
ContentFile(response.read()),
save=False)
if commit:
image.save()
return image
Upload from web page
class UploadImageForm(forms.ModelForm):
class Meta:
model = Image
fields = ('image', 'title', 'description')
def save(self, commit=True):
image = super(UploadImageForm, self).save(commit)
image_name = '{}.{}'.format(slugify(image.title),
image_url.rsplit('.', 1)[1].lower())
# Pobranie pliku obrazu z podanego adresu URL.
response = request.urlopen(image_title)
image.image.save(image_name,
ContentFile(response.read()),
save=False)
if commit:
image.save()
return image
Upload from dics
views.py
#login_required
def image_create(request):
if request.method == 'POST':
form = ImageCreateForm(data=request.POST)
if form.is_valid():
cd = form.cleaned_data
new_item = form.save(commit=False)
new_item.user = request.user
new_item.save()
create_action(request.user, 'Added Image', new_item)
messages.success(request, 'Obraz został dodany.')
return redirect(new_item.get_absolute_url())
else:
form = ImageCreateForm(data=request.GET)
return render(request,
'images/image/create.html',
{'section': 'images',
'form': form})
Upload from web page
#login_required
def image_upload(request):
if request.method == 'POST':
upload_form = UploadImageForm(request.POST, request.FILES)
if ulpoad_form.is_valid():
new_item=upload_form.save(commit=False)
new_item.image=request.FILES['image']
new_item.save()
messages.success(request, 'Obraz został dodany.')
return redirect('new_item.get_absolute_url()')
else:
upload_form=UploadImageForm()
return render(request, 'images/image/upload_image.html',
{'upload_form': upload_form, 'section': 'images' })
Upload from dics
And upload.html
{% block content %}
<h1>upload img</h1>
<form action="." method="post" enctype="multipart/form-data">
{{ upload_form.as_p }}
{% csrf_token %}
<input type="submit" value="Upload!!">
</form>
{% endblock %}
I would be grateful for help
Related
I started learning Django about a month ago and just finished Django for Beginners by William Vincent. The book ends with Ch.15: Comments and shows how the admin can add comments to posts.
Q: Can someone, please, show me or point me in the right direction as to how I can let registered users also add comments to posts? Is there perhaps a 3rd party app for that?
What I have so far:
Models:
class Article(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
image = models.ImageField(upload_to='images/', null=True, blank=True, height_field=None, width_field=None)
upload = models.FileField(upload_to='files/', null=True, blank=True)
author = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('article_detail', args=[str(self.id)])
class Comment(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='comment')
comment = models.CharField(max_length=140)
date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
get_user_model(), on_delete=models.CASCADE,
)
def __str__(self):
return self.comment
def get_absolute_url(self):
return reverse('article_list')
forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Article
fields = ('title', 'body', 'image', 'upload')
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('comment', 'author')
Views:
class ArticleListView(LoginRequiredMixin, ListView):
model = Article
template_name = 'article_list.html'
comment_form = CommentForm
login_url = 'login'
class ArticleDetailView(LoginRequiredMixin, DetailView):
model = Article
template_name = 'article_detail.html'
login_url = 'login'
class ArticleUpdateView(LoginRequiredMixin, UpdateView):
model = Article
fields = ('title', 'body', 'image', 'upload')
template_name = 'article_edit.html'
login_url = 'login'
def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
if obj.author != self.request.user:
raise PermissionDenied
return super().dispatch (request, *args, **kwargs)
class ArticleDeleteView(LoginRequiredMixin, DeleteView):
model = Article
template_name = 'article_delete.html'
success_url = reverse_lazy('article_list')
login_url = 'login'
def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
if obj.author != self.request.user:
raise PermissionDenied
return super().dispatch (request, *args, **kwargs)
class ArticleCreateView(LoginRequiredMixin, CreateView):
model = Article
form_class = PostForm
template_name = 'article_new.html'
login_url = 'login'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
URLs:
urlpatterns = [
path('<int:pk>/edit/', ArticleUpdateView.as_view(), name='article_edit'),
path('<int:pk>/', ArticleDetailView.as_view(), name='article_detail'),
path('<int:pk>/delete/', ArticleDeleteView.as_view(), name='article_delete'),
path('', ArticleListView.as_view(), name='article_list'),
path('new/', ArticleCreateView.as_view(), name='article_new'),]
Thank you for your attention.
Solved. In my views.py I added the following function:
def add_comment(request, pk):
article = get_object_or_404(Article, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.article = article
comment.save()
return redirect('article_detail', pk=article.pk)
else:
form = CommentForm()
return render(request, 'add_comment.html', {'form': form})
Then the following .html file was added to templates:
add_comment.html
{% extends 'base.html' %}
{% block content %}
<h4>Add a Comment</h4>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.as_p }}</p>
<button type="submit" class="btn btn-success">Submit</button>
</form>
{% endblock content %}
P.S.: Initially I was getting an ImportError: cannot import name 'add_comment' from 'articles.views'.
I thought it was a circular import problem and what worked for me was just getting the def add_comment indentation right.
I am creating an image upload function with django.
However, it is not uploaded.
I don't know the code mistake, so I want to tell you.
I tried variously, but if I specify default for imagefiled,
default will be applied.
#form
class RecordCreateForm(BaseModelForm):
class Meta:
model = URC
fields = ('image','UPRC','URN',)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(RecordCreateForm,self).__init__(*args, **kwargs)
self.fields['URN'].queryset = UPRM.objects.filter(user=user)
#view
class RecordCreate(CreateView):
model = URC
form_class = RecordCreateForm
template_name = 'records/urcform.html'
success_url = reverse_lazy('person:home')
def get_form_kwargs(self):
kwargs = super(RecordCreate, self).get_form_kwargs()
# get users, note: you can access request using: self.request
kwargs['user'] = self.request.user
return kwargs
def form_valid(self, form):
user = self.request.user
form.instance.user = user
form.instance.group = belong.objects.get(user=user).group
return super().form_valid(form)
#model
def get_upload_path(instance, filename):
n = datetime.now()
prefix = "records/"
ymd='/'.join([n.strftime('%Y'), n.strftime('%m'), n.strftime('%d'), ""]) + "/"
directory=str(instance.user.id) + "/"
name=str(uuid.uuid4()).replace("-", "")
extension=os.path.splitext(filename)[-1]
return ''.join([prefix, directory, ymd, name, extension])
class URC(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
group = models.ForeignKey(group, on_delete=models.CASCADE, null=True)
URN = models.ForeignKey(UPRM, on_delete=models.CASCADE)
UPRC = models.CharField(max_length=300)
image = models.ImageField(upload_to=get_upload_path)
def __str__(self):
return self.UPRC
#urls
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
I will post any other necessary code.
Sorry for the poor English.
Postscript
The page is redirected without any error display.
But admin screen was able to upload.
class BaseModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
kwargs.setdefault('label_suffix', '')
super(BaseModelForm, self).__init__(*args, **kwargs)
#template
<form method="post" action="">
{% csrf_token %}
{{form.image.label_tag}}
{{form.image}}
{{form.UPRC.label_tag}}
{{form.UPRC}}
{{form.URN.label_tag}}
{{form.URN}}
<input class="btn btn-primary" type="submit" value="submit">
</form>
Your <form> tag misses the enctype, as explained here:
<form method="post" enctype="multipart/form-data">
You can take a look at this example.
https://www.pythonsetup.com/simple-file-uploads-django-generic-createview/
def form_valid(self, form):
self.object = Author(photo=self.get_form_kwargs().get('files')['photo'])
self.object = form.save()
return HttpResponseRedirect(self.get_success_url())
I am working on a simple blog which has a model Post. I am trying to create a form for adding blog posts (or adding comments to posts for that matter) so that end users don't have to fill out a form box asking the end user for a username. I would like to be able to just ask for a title and body text for a blog post, and when hit post, it will be posted as the authenticated user.
I tried not including 'user' field in fields in forms, but it seems to be mandatory. Maybe I need to just make it hidden somehow using widgets? In templates, I could maybe write the following:
{% if user.is_authenticated %}
<p>Posting as {{request.user}}</p>
{% else %}
<p><a href={% url 'register' %}Please register to add a blog post</a></p>
{% endif %}
Though I am not sure, I think it would make more sense to have logic in my views.py file.
Here's my 'blog.models' file:
class Post(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
text = models.TextField()
published_date = models.DateTimeField(auto_now=True)
# pip install Pillow
image = models.ImageField(null=True, blank=True,
upload_to='photos/%Y/%m/%d/',)
def summary(self):
"""Return a summary for very long posts to
get a glimpse from admin panel"""
return self.text[:100]
def _get_unique_slug(self):
"""Assigns a number to the end of a given slug field to prevent
duplicated slug error. if title of a post is 'ayancik', and another
user creates another post with the same title, second posts' slug
is assigned a value: 'ayancik-2'"""
slug = slugify(self.title)
unique_slug = slug
num = 1
while Post.objects.filter(slug=unique_slug).exists():
unique_slug = '{}-{}'.format(slug, num)
num += 1
return unique_slug
def save(self, *args, **kwargs):
"""Automatically assign slug to objects
by overriding save method"""
self.slug = self._get_unique_slug()
super().save(*args, **kwargs)
def pub_date_pretty(self):
return self.published_date.strftime('%b %e, %Y')
def __str__(self):
"""String representation"""
return self.title
def get_absolute_url(self):
# what does kwargs={'slug':self.slug} really achieve here?
# where would we use 'key-value' pair?
"""Returns the url to access a detailed post"""
return reverse('post-detail', kwargs={"slug": self.slug})
class Meta:
ordering = ['-published_date',]
class Comment(models.Model):
post = models.ForeignKey('blog.Post', on_delete=models.CASCADE,
related_name='comments')
user = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
approved_comment = models.BooleanField(default=False)
def approve_comment(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.text
'blog.forms' file:
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['user', 'title', 'text', 'image']
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('user', 'text',)
and 'blog.views' file:
#login_required
def create_post(request):
if request.method == 'POST':
post_form = PostForm(request.POST)
if post_form.is_valid():
post = post_form.save(request)
post.save()
else:
print(post_form.errors)
else:
# when not POST request, display the empty form
# meaning -> if request.method=='GET':
post_form = PostForm()
context = {
'post_form': post_form,
}
return render(request, 'blog/addpost.html', context)
def add_comment_to_post(request, slug):
post = get_object_or_404(Post, slug=slug)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post-detail', slug=slug)
else:
form = CommentForm()
template_name = 'blog/add_comment_to_post.html'
return render(request, template_name , {'form': form })
You omit the user in the PostForm:
class PostForm(forms.ModelForm):
class Meta:
model = Post
# no user
fields = ['title', 'text', 'image']
or we can display all fields except 'user' like:
class PostForm(forms.ModelForm):
class Meta:
model = Post
exclude = ('user', )
and then you add the user to the instance in your view:
from django.shortcuts import redirect
#login_required
def create_post(request):
if request.method == 'POST':
post_form = PostForm(request.POST, request.FILES)
if post_form.is_valid():
post = post_form.save(commit=False)
post.user = request.user
post.save()
return redirect('some_view')
else:
post_form = PostForm()
context = {
'post_form': post_form,
}
return render(request, 'blog/addpost.html', context)
The commit=False thus prevents the from from saving the Post object to the database.
Since you want to upload an image, you should pass request.FILES [Django-doc] to the PostForm as well, otherwise you will not process uploaded files. You furthermore need to specify that you use enctype="multipart/form-data" in your form:
<form enctype="multipart/form-data" method="POST" action="{% url 'create_post' %}">
...
</form>
It is better to use a redirect [Django-doc] in case of a successful POST request, since this is the Post/Redirect/Get pattern [wiki]. By rendering a new form, if the user refreshes the page, he/she would create a second post, which is probably not what you want.
I'm trying to upload an image. This is an avatar image for the profile of the user.
Currently, the form return no error, but I have nothing written on my database or in my folder media/avatar/.
What's wrong ?
My view :
def view_avatar(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES, instance=request.user.profile)
if form.is_valid():
form.save()
else:
form = UploadFileForm(instance=request.user.profile)
return render(request, 'avatar.html', locals())
My form :
class UploadFileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('avatar',)
My model :
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
birthdate = models.DateField(null=True, blank=True)
avatar = models.ImageField(upload_to='media/avatar/', blank=True, null=True)
It's because the form which you are using is inherited from forms.Form , you need to use forms.ModelForm for saving the instance directly.
Change this line,
class UploadFileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('avatar', )
def save(self, *args, **kwargs):
profile, created = Profile.objects.get_or_create(user=self.user)
profile.avatar = self.cleaned_data['avatar']
profile.save()
return profile
Also, edit in your views like this,
if form.is_valid():
file = form.save(commit=False)
file.user = request.user
file.save()
For making a profile you can use signals.
This way whenever a new user been added, a profile will be generated for that user automatically
Your models.py:
from django.conf import settings
from django.db.models.signals import post_save
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
birthdate = models.DateField(null=True, blank=True)
avatar = models.ImageField(upload_to='media/avatar/%y/%m/%d', blank=True, null=True)
def post_save_profile(sender, instance, created, *args, **kwargs):
if created:
try:
Profile.objects.create(user=instance)
except:
pass
post_save.connect(post_save_profile, sender=settings.AUTH_USER_MODEL)
and for updating the information like birthday and avatar you can use ModelForm.
forms.py:
class UploadFileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('birthdate', 'avatar')
def __init__(self, *args, **kwargs):
super(UploadFileForm, self).__init__(*args, **kwargs)
self.fields['avatar'].required = False
your views.py:
def view_avatar(request):
user = request.user
if request.method == "POST":
form = UploadFileForm(request.POST, request.FILES, instance=user.profile)
if form.is_valid():
form.save()
for avatar in template you can use this:
<img src="{% if user.profile.avatar %}{{ user.profile.avatar.url }}{% else %}{% static 'no-avatar.jpg' %}{% endif %}"><i></i>
You can write custom Save method for this like this.
View:
def view_avatar(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES, user=request.user)
if form.is_valid():
form.save()
else:
form = UploadFileForm()
return render(request, 'avatar.html', locals())
Form:
class UploadFileForm(forms.Form):
class Meta:
model = Profile
fields = ('avatar', )
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super(UploadFileForm, self).__init__(*args, **kwargs)
self.fields['avatar'].required = False
avatar = forms.FileField()
def save(self, *args, **kwargs):
user_profile, created = Profile.objects.get_or_create(user=self.user)
user_profile.avatar = self.cleaned_data.get('avatar')
user_profile.save()
return user_profile
I forgot the enctype !
The solution was :
<form method="POST" action="" enctype="multipart/form-data">
I'm trying to use django's FormPreview but can't get it to work properly. Here's my code:
models.py
class jobpost(models.Model):
CONTENT_CHANNELS = (
('Full Time','Full Time'),
('Part Time','Part Time'),
('Contract','Contract'),
)
user = models.ForeignKey(User)
job_id = models.AutoField(primary_key=True)
#user = models.ForeignKey(User, editable = False)
job_type = models.CharField(max_length=255,null=True, choices=CONTENT_CHANNELS,default='Full Time')
job_location = models.CharField(max_length=255,null=True)
job_title = models.CharField(max_length=255,null=True)
job_description = models.TextField(null=True)
def __unicode__(self):
#return self.user
return self.job_location
return self.job_type
return self.job_title
return self.job_description
admin.site.register(jobpost)
class jobpostForm(ModelForm):
class Meta:
model = jobpost
fields = ('user','job_type','job_location','job_title','job_description')
widgets = {
'job_type':RadioSelect(),
'job_location':TextInput(attrs={'size':'70'}),
'job_description':Textarea(attrs={'cols':200, 'rows':10}),
}
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_class = 'horizontal-form'
self.helper.form_id = 'id-jobpostform'
self.helper.form_class = 'blueForms'
self.helper.form_method = 'post'
#self.helper.form_action = '/'
self.helper.add_input(Submit('submit_addcontent', 'Submit'))
super(jobpostForm, self).__init__(*args, **kwargs)
views.py
def main_page(request):
"""
If users are authenticated, direct them to the main page. Otherwise, take
them to the login page.
"""
if request.method == 'POST':
form = jobpostForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/thanks/')
else:
form = jobpostForm()
c = {}
c.update(csrf(request))
return render_to_response('portal/job_post.html',{'form':form},context_instance=RequestContext(request))
preview.py
class SomeModelFormPreview(FormPreview):
form_template = 'portal/job_post.html'
preview_template = 'portal/preview.html'
def done(self, request, cleaned_data):
f = self.form(request.POST)
f.save()
pdb.set_trace()
print "done"
# Do something with the cleaned_data, then redirect
# to a "success" page.
return HttpResponseRedirect('/form/success')
job_post.html
<form action = "" method = "POST" enctype="multipart/form-data" class="blueForms" id="id-jobpostform">
{% csrf_token %}
{% crispy form %}
<input name="submit" type="submit" value="Post" >
urls.py
(r'^$', main_page),
(r'^post/$', SomeModelFormPreview(jobpostForm)),
When i submit the form it goes to the / home page and submits the info. I want to first prview the form and then submit..plz tell me what i am missing or doing wrong.