Cant upload Image with CreatView Django - django

views.py
class PostCreatView(LoginRequiredMixin, CreateView):
model = Posts
fields = ['image', 'caption']
template_name = 'home/creat-post.html'
success_url = '/home/'
def form_valid(self,form):
form.instance.user = self.request.user
return super().form_valid(form)
models.py
class Posts(models.Model):
caption = models.CharField(max_length=2200)
date_posted = models.DateTimeField(default=timezone.now())
image = models.ImageField( upload_to='PostsImages')
user = ForeignKey(User, on_delete=models.CASCADE ,related_name='UserPosts')
def __str__(self):
return f"Post {self.id} ({self.user.username})'s"
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
img = Image.open(self.image.path)
#img = make_square(img, 1080, 1080)
img.save(self.image.path)
class Meta:
ordering = ['-date_posted']
creat-post.html
{% extends "home/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div>
<form method="POST">
<fieldset>
<legend >Creat Post</legend>
{% csrf_token %}
{{ form|crispy }}
</fieldset>
<button class="btn btn-primary" type="submit">Post</button>
</form>
</div>
{% endblock %}
So I created a creatview to add create new post. However when I go to the link and add photo then hit submit, it gives me as I haven't uploaded an image.
However, I am able to add images to a new Post from the admin normally.

Try to add enctype in your template:
<form method="post" enctype="multipart/form-data">

Related

Django how to add a form to a DetailView with FormMixin

I am attempting to add a form for comments to a DetailView. The DetailView displays notes for specific projects. So the comments have a foreign key that is the specific note and the note has a foreign key for the specific project.
I am attempting to use FormMixin with DetailView. So far I have not bee successful. Currently I can get the form to display but it does not save and in the terminal I see the following error Method Not Allowed (POST): /projects/project/1/note/1/
I can get these to work separately but not with the form in the DetailView.
Here are my models:
class ProjectNotes(models.Model):
title = models.CharField(max_length=200)
body = tinymce_models.HTMLField()
date = models.DateField(auto_now_add=True)
project = models.ForeignKey(Project, default=0, blank=True, on_delete=models.CASCADE, related_name='notes')
def __str__(self):
return self.title
class ProjectNoteComments(models.Model):
body = tinymce_models.HTMLField()
date = models.DateField(auto_now_add=True)
projectnote = models.ForeignKey(ProjectNotes, default=0, blank=True, on_delete=models.CASCADE, related_name='comments')
The View:
class ProjectNotesDetailView(DetailView, FormMixin):
model = ProjectNotes
id = ProjectNotes.objects.only('id')
template_name = 'company_accounts/project_note_detail.html'
comments = ProjectNotes.comments
form_class = NoteCommentForm
def form_valid(self, form):
projectnote = get_object_or_404(ProjectNotes, id=self.kwargs.get('pk'))
comment = form.save(commit=False)
comment.projectnote = projectnote
comment.save()
return super().form_valid(form)
def get_success_url(self):
return reverse('project_detail', args=[self.kwargs.get('pk')])
The form:
class NoteCommentForm(forms.ModelForm):
class Meta:
model = ProjectNoteComments
fields =['body',]
widgets = {
'body': forms.TextInput(attrs={'class': 'form-control'})
}
The template:
% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="section-container container">
<div class="project-entry">
<h2>{{ projectnotes.title }}</h2>
<p>{{ projectnotes.body | safe }}</p>
</div>
<div><b>Comments on {{projectnotes.title}}</b></div>
{% if projectnotes.comments.all %}
{% for comment in projectnotes.comments.all %}
<div class="notecomments" style="padding: 10px;">
{{ comment.body | safe }}
</div>
{% endfor %}
{% else %}
<p>No comments have been have been added yet.</p>
{% endif %}
<h2>add note</h2>
<h1>Add Comment</h1>
<form action="" method="post">
{% csrf_token %}
{{ form.media }}
{{ form|crispy }}
<input type="submit" value="save">
</form>
{% endblock content %}
Try to change the order between DetailView and FormMixin in ProjectNotesDetailView then implement the post method (enabled by the `FormMixin):
class ProjectNotesDetailView(FormMixin, DetailView):
model = ProjectNotes
id = ProjectNotes.objects.only('id')
template_name = 'company_accounts/project_note_detail.html'
comments = ProjectNotes.comments
form_class = NoteCommentForm
def form_valid(self, form):
projectnote = get_object_or_404(ProjectNotes, id=self.kwargs.get('pk'))
comment = form.save(commit=False)
comment.projectnote = projectnote
comment.save()
return super().form_valid(form)
def get_success_url(self):
return reverse('project_detail', args=[self.kwargs.get('pk')])
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
Check how to use formmixin with detailview (documentation).

Blog post with image Django3

Hi i'm trying to add some funcionality to my blog post app, i'd like to paste image into post content so i figured is this waw that ive created new model just for images and set it as OneToOne with my Post model
i wonder if ther is any way to set this image to content field in the post model
models.py
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
class PostImage(models.Model):
post = models.OneToOneField(Post, on_delete=models.CASCADE)
image = models.ImageField(default=None, upload_to='post_pics', blank=True)
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
img = Image.open(self.image.path)
if img.height > 500 or img.width > 500:
output_size = (500, 500)
img.thumbnail(output_size)
img.save(self.image.path)
vievs.py
def home(request):
context = {
'posts': Post.objects.all(),
'user_posts': "active",
}
return render(request, 'blog/home.html', context)
class PostListView(ListView):
model = Post
template_name = 'blog/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 5
post_template.html
{% extends "blog/base.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Blog Post</legend>
{{form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Post</button>
</div>
</form>
</div>
{% endblock content %}
settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
Well i've found another solution i've used CKEditor and now everything works fine
pip install pillow
& in static/post_pics (see the img.jpg ...png ) it's save ?

Modelset Factory displays a choice fields instead of an input field

Models.py
class Post(models.Model):
title = models.CharField(max_length=100)
conent = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to="post_pics")
def __str__(self):
return self.title
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
img = Image.open(self.image.path)
if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.image.path)
class Tag(models.Model):
name = models.CharField(max_length=30)
members = models.ManyToManyField(Post, through='PostTag')
def __str__(self):
return self.name
class PostTag(models.Model):
article = models.ForeignKey(Post, on_delete=models.CASCADE)
tag = models.ForeignKey(Tag, on_delete=models.CASCADE)
Forms.py
class PostUpdateForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'conent', 'image']
class TagUpdateForm(forms.ModelForm):
class Meta:
model = PostTag
fields = ['tag']
TagUpdateFormSet = modelformset_factory(PostTag, form=TagUpdateForm)
Views.py
#login_required
def updateView(request, pk):
template_name = 'project/post_update.html'
heading_message = 'Tags'
if request.method == 'GET':
form1 = PostUpdateForm(instance=Post.objects.filter(id=pk).first())
form2 = TagUpdateFormSet(queryset=PostTag.objects.filter(article=Post.objects.filter(id=pk).first()))
elif request.method == 'POST':
form1 = PostUpdateForm(request.POST, request.FILES, instance=Post.objects.filter(id=pk).first())
form2 = TagUpdateFormSet(request.POST, queryset=PostTag.objects.filter(article=Post.objects.filter(id=pk).first()))
if form1.is_valid():
invalid = True
for formz in form2:
if formz.is_valid() == False:
invalid = False
break
if invalid:
postform = form1.save(commit=False)
postform.author = request.user
postform.save()
for forms in form2:
data = forms.cleaned_data.get('tag')
if data:
returnedTag, created1 = Tag.objects.get_or_create(name = data)
link, created2 = PostTag.objects.get_or_create(article = postform, tag = returnedTag)
return HttpResponseRedirect('/forum/post/%s/' %(postform.id))
return render(request, 'project/post_update.html', {'form': form1, 'form2': form2})
template
{% extends "template/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
{% load static %}
<div class="container form-section s-yellow section">
<form method="POST" action="" enctype='multipart/form-data'>
{% csrf_token %}
<fieldset class="form-container">
<legend class="form-top"></legend>
<div class="form1">
{{ form|crispy }}
</div>
<div class="form2 form-group">
{{ form2.management_form }}
{% for formz in form2 %}
<div>
<div class="form-row">
<div class="input-group">
{{formz }}
<div class="">
<button type="button" class="add-form-row">+</button>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Post</button>
</div>
</fieldset>
</form>
</div>
{% endblock content %}
I want to let the user be able to edit all tags in a post, however when i display the tags they show up as choice field that lets the user choose from already existing tags and they can't type a new one.
Is there a way to change the choice field to an input field where the original value is the tag originaly entered.
I tried edditing the 'tag' field to a charfield above the meta tag in the form, but then i was getting an input field with the choice field value (eg 4, 6, 10,) instead of the actual text.
I know the saving part doesnt work, but i need to figure out a way to get the fields dispalyed properly
Btw are there any tutorials for a database structure like this? It's hard to find examples where one table links to 2 others.

I cannot add song to specific album using CreateView

I am following buckys django tutorial, he explained how to add albums but not song, i want to try adding songs to specific album but it is not working.
I have added a SongCreate view to my views.py, i also created a song_form.html template for inputting song details.I have also tried the form_valid method, but it doesnt just work.
My views.py
class AlbumCreate(CreateView):
model=Albums
fields=['alb_title','alb_genre','alb_logo','alb_artist']
class SongCreate(CreateView):
model = Song
fields = ['song_title', 'song_format']
def form_valid(self, form):
album = get_object_or_404(Albums, pk=self.kwargs['pk'])
form.instance.album = album
return super(SongCreate, self).form_valid(form)
#My urls.py
app_name ='music'
urlpatterns = [
path('',views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
path('album/add/', views.AlbumCreate.as_view(), name='album-add'),
path('album/<int:pk>/songadd/', views.SongCreate.as_view(),
name='song-add'),
path('album/<int:pk>/', views.AlbumUpdate.as_view(), name='album-
update'),
path('album/<int:pk>/delete/', views.AlbumDelete.as_view(),
name='album-delete'),
]
#My song_form.html template
{% extends 'music/base.html' %}
{% block title %}Add New Song{% endblock %}
{% block body %}
<div class="container-fluid">
<h4>Add the details of the Song in the given fields.</h4>
<div class="row">
<div class="col-sm-12 col-md-7">
<div class="panel panel-default">
<div class="panel-body">
<form class='form-horizontal' action=""
method="post"
enctype="multipart/form-data">
{% csrf_token %}
{% include 'music/form-template.html' %}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-
success">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
#Models.py
class Albums(models.Model):
alb_title = models.CharField(max_length = 250)
alb_genre = models.CharField(max_length = 250)
alb_logo = models.FileField()
alb_artist = models.CharField(max_length = 250)
def get_absolute_url(self):
return reverse("music:detail", kwargs={"pk": self.pk})
def __str__(self):
return self.alb_title + '-' + self.alb_artist
class Song(models.Model):
song = models.ForeignKey(Albums, on_delete = models.CASCADE)
song_title = models.CharField(max_length = 250)
song_format = models.CharField(max_length = 10)
is_favourite = models.BooleanField(default=False)
def __str__(self):
return self.song_title
def get_absolute_url(self):
return reverse('music:detail', kwargs={'pk': self.song.pk})
When add song is clicked it directs me to a form to fill song detail, but when i tried it i got:
IntegrityError at /music/album/song/add/
NOT NULL constraint failed: music_song.song_id
you must :
def create_song(request):
if request.method == "POST":
form.save()
I give you the way I use form_valid()
def form_valid(self, form):
album = get_object_or_404(Albums, pk=self.kwargs['pk'])
form = form.save(commit=False)
form.album = album
form.save()
return super().form_valid(form)
If it doesn't work, it means you have changes not reflected in your database. Run ./manage.py makemigrations and ./manage.py migrate. It might be necessary, if possible, to drop and recreate the whole db.

Django CreateView not able to create model object

I am using Django CreateView on model object. The form gets rendered but on submitting Post button, nothing happens. In console I am receiving code 200 (Success) but object is not created. Also, I am using same HTML template and same code for Update View and it is working perfectly. Please help.
class EventCreateView(LoginRequiredMixin, CreateView):
model = Event
fields = ['name', 'event_attendees']
def form_valid(self, form):
form.instance.creator = self.request.user
return super().form_valid(form)
Model
name = models.CharField(max_length=100)
date = models.DateTimeField(default=timezone.now)
location = models.CharField(max_length=16, choices=EVENT_VENUES, default='sec-1, noida')
event_attendees = models.FileField(upload_to='documents/', default='')
creator = models.ForeignKey(User, on_delete=models.CASCADE)
form_rollout_time = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('event-detail', kwargs={'pk': self.pk})
Html template
{% extends "events/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">New Event</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Post</button>
</div>
</form>
</div>
{% endblock content %}
Urls
urlpatterns = [
path('', EventListView.as_view(), name='event-home'),
path('user/<str:username>', UserEventListView.as_view(), name='user-events'),
path('event/<int:pk>/', EventDetailView.as_view(), name='event-detail'),
path('event/new/', EventCreateView.as_view(), name='event-create'),
path('event/<int:pk>/update/', EventUpdateView.as_view(), name='event-update'),
path('event/<int:pk>/delete/', EventDeleteView.as_view(), name='event-delete')
]
update code like this
def form_valid(self, form):
obj = form.save(commit=False)
obj.creator = self.request.user
obj.save()
try this
Solved the issue by overriding method form_invalid(). Apparently, the issue was in the implementation with FileField but was suppressed with the default implementation of form_invalid. On overriding the method, the actual issue arose.