Django CreateView not able to create model object - django

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.

Related

Cant upload Image with CreatView 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">

Django pass PK from post to next page

I currently have a blog post feature on my site. I want users to be able to create sub posts
(build log ) off of the main posts.
I created this model with a FK to the Post model
class BuildLog(models.Model):
title = models.CharField(max_length=100)
content = RichTextUploadingField(blank=True, null=True)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey('Post', on_delete=models.CASCADE)
I then added a button on the post page and created a form. Everything is working as expected but when I submit the form I get the error
null value in column "post_id" of relation "blog_buildlog" violates not-null constraint
If I understand the error correctly it is saying I am not passing the PK of the post into the form.
Views
def DetailPostView(request, pk):
model = Post
post = Post.objects.get(pk=pk)
form = CommentForm
comments = Comment.objects.filter(post=post)#.order_by('-create')
if request.method == 'POST':
# A comment was posted
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.author = request.user
new_comment.post = post
new_comment.save()
context = {
'post':post, 'form':form, 'comments':comments
}
return render(request, 'blog/post_detail.html', context)
class BuildLogView(LoginRequiredMixin, CreateView):
model = BuildLog
form_class = BuildLogForm
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def save(self, *args, **kwargs):
super(BuildLog,self).save(*args, **kwargs)
Url
path('build-log-form/', BuildLogView.as_view(), name='build-log-form'),
path('post/<int:pk>/', views.DetailPostView, name='post-detail')
How do I go about passing the post PK into the next view?
forms.py
class BuildLogForm(ModelForm):
class Meta:
model = BuildLog
fields = ['title' , 'content']
html
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="post" enctype="multipart/form-data" id="PostForm" novalidate>
<!--id="modelForm"-->
{% csrf_token %}
<fieldset class="django-ckeditor-widget">
<legend class="border-bottom mb-4">New Build Log</legend>
{{ form.title | as_crispy_field }}
{{ form.media }}
{{ form.content | as_crispy_field | safe}}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Post</button>
</div>
</form>
</div>
{% endblock content %}
Just incase their is any confusing It goes Post --> BuildLog(subpost)

Photos for each post in django

I have created a blog website and I want to display images for every post like YouTube thumbnails. I created an image field in my Post Class but it is not saving my image in the media folder when I create a post.
Post class in models.py:
class Post(models.Model):
name = models.CharField(default='Concert', max_length=100)
invite = models.ImageField(default='invite.jpg', upload_to='invite_pics')
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
This is my CreatePost class in views.py:
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
template_name = 'home_page/post_form.html'
fields = ['name', 'invite']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
I have set the MEDIA_ROOT and MEDIA_URL in settings.py:
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
post_form.html:
<div class="container">
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Create New Event</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Post</button>
</div>
</form>
</div>
</div>
So as I have said earlier, the image is not getting saved to media/invite_pics what should I do?
In order to submit data and files, you need to specify the enctype="…" parameter of the form:
<form enctype="multipart/form-data" method="POST">
…
</form>

Django forms how to display related data in an inner form

I am struggling with Django forms.
I have the following model.py:
class Property(models.Model):
portfolio = models.ForeignKey("portfolios.Portfolio", on_delete=models.CASCADE)
class PropertyImage(models.Model):
property = models.ForeignKey("Property", on_delete=models.CASCADE)
image = models.ImageField(upload_to = property_image_upload_to)
def __str__(self):
return self.image.url
class PropertyDocument(models.Model):
property = models.ForeignKey("Property", on_delete=models.CASCADE)
document = models.FileField()
class Address(models.Model):
property = models.OneToOneField("Property", on_delete=models.CASCADE)
line1 = models.CharField(max_length=100)
line2 = models.CharField(max_length=100, null=True, blank=True)
line3 = models.CharField(max_length=100, null=True, blank=True)
post_code = models.CharField(max_length=7)
town = models.CharField(max_length=100, null=True, blank=True)
city = models.CharField(max_length=100)
When adding/updating a property, I want the form to show the form for related objects like the address, documents/images instead of the select list's that appear in forms - I want to be able to add/edit the related data.
My view.py file
class PropertyCreate(CreateView):
model = Property
form_class=PropertyAddressFormSet
success_url = reverse_lazy('Property_list')
def get_context_data(self, **kwargs):
data = super(PropertyCreate, self).get_context_data(**kwargs)
return data
Property_form.html
{% extends 'base/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" class="btn btn-primary" />
<button class="btn btn-link" onclick="javascript:history.back();">Cancel</button>
</form>
{% endblock %}
urls.py
from . import views
app_name = 'properties'
urlpatterns = [
path('<int:portfolio_id>/<int:pk>/edit', views.PropertyUpdate.as_view(), name='property_edit'),
path('<int:portfolio_id>/create', views.PropertyCreate.as_view(), name='property_new'),
]
I've read about inlineformset_factories and inlineformset's etc, but is this the best choice for my scenario? If so, I can't figure out how to show the portfolio, address form
I;m currently using a inlineformset like so, which creates the Address form on the PropertyCreate view, but I want to also add in the PropertyImages and PropertyDocs to the ProertyCreate view.:
PropertyAddressFormSet = inlineformset_factory(
parent_model=Property,
model=Address,
form=AddressForm,
extra=0,
min_num=1
)
For anyone in the same boat as me, I managed to get this working with the following code:
Forms.py:
class PropertyForm(ModelForm):
""" Edit a property """
class Meta:
model = Property
exclude = ()
PropertyAddressFormSet = inlineformset_factory(
parent_model=Property,
model=Address,
form=AddressForm,
extra=0,
min_num=1
)
Views.py
class PropertyCreate(CreateView):
model = Property
form_class=PropertyForm
success_url = reverse_lazy('Property_list')
def get_context_data(self, **kwargs):
data = super(PropertyCreate, self).get_context_data(**kwargs)
if self.request.POST:
data['address'] = PropertyAddressFormSet (self.request.POST, instance=self.object)
else:
data['address'] = PropertyAddressFormSet ()
return data
template:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form |crispy }}
<fieldset class="border p-2">
<legend class="w-auto">Address</legend>
{{ address.management_form }}
{% for form in address.forms %}
<div >
{{ form.as_p }}
</div>
{% endfor %}
</fieldset>
</form>
Hope this helps someone.

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.