I have two models with two different forms. One has a ForeignKey for another model, making a 1-N relationship. The problem is when i try to add images , is not working. The form where i change the (name/TabletForm2) is working so , only when i try to add (image/TabletFormImagem) is not working.
The problem is that
My model's
def get_image(instance, filename):
return os.path.join('intervencao/fotografias', str(instance.intervencao), filename)
class Intervencao(models.Model):
name= models.CharField(verbose_name="Name", max_length=200, blank=True, null=True)
class Imagem(models.Model):
intervencao = models.ForeignKey(Intervencao, related_name='intervencaoObjectsImagem', on_delete=models.CASCADE)
imagem = models.ImageField(upload_to=get_image, blank=True, null=True, verbose_name="Fotografia")
def __str__(self, ):
return str(self.intervencao)
My View
def project_detail_chefe(request, pk):
form = TabletForm2(request.POST)
form2 = TabletFormImagem(request.POST, request.FILES)
if request.method == "POST":
if form.is_valid():
form.save()
return redirect('index')
else:
form = TabletForm2(request.POST)
if form2.is_valid():
//when i print something here to see if the form2 is valid , never enter here.
form2.save()
return redirect('index')
else:
form2 = TabletFormImagem()
context = {
'form':form,
'form2':form2,
}
return render(request, 'tablet/info_chefes.html', context)
tablet/info_chefes.html
<div class="col-md-12">
<div class='form-group'>
<label for="{{ form.subject.id_for_label }}" id="titulo">Name:</label>
<em>{{ form.name}}</em>
</div>
</div>
<div class="col-md-12">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form2.as_p }}
<button type="submit">Upload</button>
</form>
</div>
Forms
class TabletForm2(forms.ModelForm):
class Meta:
model=Intervencao
fields = ['data_intervencao_fim','ferramenta']
class TabletFormImagem(forms.ModelForm):
class Meta:
model=Imagem
fields = ['imagem']
def project_detail_chefe(request, pk):
form = TabletForm2()
form2 = TabletFormImagem()
if request.method == "POST":
form = TabletForm2(request.POST)
form2 = TabletFormImagem(request.POST, request.FILES)
if form.is_valid() and form2.is_valid():
instance_form1 = form.save()
instance_form2 = form2.save(commit=False)
instance_form2.intervencao = instance_form1
instance_form2.save()
return redirect('index')
else:
form = TabletForm2()
form2 = TabletFormImagem()
context = {
'form':form,
'form2':form2,
}
return render(request, 'tablet/info_chefes.html', context)
HTML
<form method="post" enctype="multipart/form-data">
<div class="col-md-12">
<div class='form-group'>
<label for="{{ form.subject.id_for_label }}" id="titulo">Name:</label>
<em>{{ form.name}}</em>
</div>
</div>
<div class="col-md-12">
{% csrf_token %}
{{ form2.as_p }}
<button type="submit">Upload</button>
</div>
</form>
Related
So i have been trying to add Tags using django-taggit, but for some reason tags are not saving to the database when i try to upload a post using website but it works perfectly with django admin(Tags are saving to the database).
Also when i go to my Post_edit view and try to update empty tags field then it works.
In other words, tags are only saving to the database when i try to edit it using Postedit view or upload it using admin. I want it to save to the database using PostUpload view only(like i have to use PostEdit view for every post to display tags).
I think there's something wrong either with my view or form.
Also i can see request.POST data is returning the list of Tags on the terminal and form returns no errors.
Everything else is saving to the database except Tags.
here's my code
Views.py
Uploading Posts( views.py )
#login_required(login_url="/login/")
def post_upload(request):
index1 = Blog.objects.all().order_by('-time')[0]
content = request.POST.get('content')
title = request.POST.get('title')
image = request.FILES.get('image')
if request.method == 'POST':
post_form = PostUpload(request.POST, request.FILES, instance=request.user)
if post_form.is_valid():
tags = post_form.cleaned_data['tags']
context = post_form.cleaned_data['context']
excerpt_type = post_form.cleaned_data['excerpt_type']
ins = Blog.objects.create(user=request.user, content=content, title=title, image=image, context=context,
tags=tags, excerpt_type=excerpt_type)
ins.save()
messages.success(request, 'Your Post has been successfully posted')
print(request.POST)
print(tags)
return HttpResponseRedirect(reverse('post_upload'))
else:
print(f'error in {request.POST}')
else:
post_form = PostUpload(instance=request.user)
context = {'post_form': post_form, 'index1': index1}
return render(request, 'post_upload.html', context)
For editing Posts( views.py )
#login_required(login_url="/login/")
def post_edit(request, pk):
index1 = Blog.objects.all().order_by('-time')[0]
post = get_object_or_404(Blog, pk=pk)
user = request.user
if request.method == 'POST':
edit_form = PostEdit(request.POST or None, request.FILES, instance=post)
if edit_form.is_valid():
edit_form.save()
print(request.POST)
messages.success(request, 'Your Post has been updated successfully')
return HttpResponseRedirect(post.get_absolute_url())
else:
edit_form = PostEdit(instance=post)
context = {'edit_form': edit_form, 'post': post, 'user': user, 'index1': index1}
return render(request, 'post_edit.html', context)
models.py
class Blog(models.Model):
sno = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
content = RichTextUploadingField()
views = models.PositiveIntegerField(default=0)
image = models.ImageField(upload_to='images/', blank=True, default="/static/img/900x300.png")
slug = AutoSlugField(populate_from='title', unique=True, unique_with='title')
time = models.DateTimeField(auto_now_add=True)
excerpt_type = models.ForeignKey(Excerpt, on_delete=models.CASCADE, null=True, blank=True)
context = models.CharField(max_length=20, null=True, blank=True)
tags = TaggableManager()
#property
def image_url(self):
if self.image and hasattr(self.image, 'url'):
return self.image.url
else:
return "/static/images/900x300.png"
#property
def get_month_name(self):
if self.time.month == 1:
return 'January'
elif self.time.month == 2:
return 'February'
elif self.time.month == 3:
return 'March'
elif self.time.month == 4:
return 'April'
elif self.time.month == 5:
return 'May'
elif self.time.month == 6:
return 'June'
elif self.time.month == 7:
return 'July'
elif self.time.month == 8:
return 'August'
elif self.time.month == 9:
return 'September'
elif self.time.month == 10:
return 'October'
elif self.time.month == 10:
return 'November'
elif self.time.month == 12:
return 'December'
def __str__(self):
return self.title + ' by ' + self.user.username
def get_absolute_url(self):
return reverse("posts:posts", args=[str(self.slug)])
forms.py
class PostUpload(forms.ModelForm):
class Meta:
model = Blog
exclude = ['slug', 'user', 'views']
class PostEdit(forms.ModelForm):
class Meta:
model = Blog
exclude = ['slug', 'user', 'views']
blogposts.html
{% if tag %}
<div class="sidebar-box ftco-animate">
<h3>Tag Cloud</h3>
<div class="tagcloud">
{% for tag in Blog.tags.all %}
{{ tag }}
{% endfor %}
</div>
</div>
{% endif %}
post_upload.html
{% block body %}
<div class="container rounded bg-white mt-5 mb-5">
<div class="col-md-8 mt-3">
<form class="form-group" action="./" method="post" enctype="multipart/form-data" >
{% csrf_token %}
<label for="validationDefaultUsername">Username</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroupPrepend2">#</span>
</div>
<input name="username" type="text" class="form-control" id="validationDefaultUsername"
value="{{ user.username }}" aria-describedby="inputGroupPrepend2" disabled>
</div>
{{ post_form.errors | as_crispy_errors }}
{{ post_form.media }}
{{ post_form | crispy }}
<input type="submit" value="Save changes" class="btn" style="color: blueviolet;">
</form>
</div>
</div>
</div>
{% endblock body %}
post_edit.html
{% block body %}
<div class="container rounded bg-white mt-5 mb-5">
<div class="col-md-8 mt-3 mb-3">
<form method="post" enctype="multipart/form-data" class="form-group">
{% csrf_token %}
<label for="validationDefaultUsername">Username</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroupPrepend2">#</span>
</div>
<input name="username" type="text" class="form-control" id="validationDefaultUsername"
value="{{ user.username }}" aria-describedby="inputGroupPrepend2" disabled>
</div>
{{ edit_form.errors }}
{{ edit_form.media }}
{{ edit_form | crispy }}
<input type="submit" value="Save changes" class="btn" style="color: blueviolet;">
</form>
</div>
</div>
{% endblock body %}
You have to save the object first then split the tag values by comma and then add the tags into the field of your object this way. I have added the comments for your understanding.
Views.py
Uploading Posts( views.py )
#login_required(login_url="/login/")
def post_upload(request):
index1 = Blog.objects.all().order_by('-time')[0]
content = request.POST.get('content')
title = request.POST.get('title')
image = request.FILES.get('image')
if request.method == 'POST':
post_form = PostUpload(request.POST, request.FILES, instance=request.user)
if post_form.is_valid():
tags = post_form.cleaned_data['tags']
context = post_form.cleaned_data['context']
excerpt_type = post_form.cleaned_data['excerpt_type']
# Removed tags=tags from the below line
# Also, if you want to use `save` then you don't want to use
# `create` as it will persist into your db right away.
# Simply create an instance of Blog
ins = Blog(user=request.user, content=content, title=title,
image=image, context=context,
excerpt_type=excerpt_type)
# Adding tags against the object field after the object creation
for tag in tags:
ins.tags.add(tag)
ins.save()
messages.success(request, 'Your Post has been successfully posted')
print(request.POST)
print(tags)
return HttpResponseRedirect(reverse('post_upload'))
else:
print(f'error in {request.POST}')
else:
post_form = PostUpload(instance=request.user)
context = {'post_form': post_form, 'index1': index1}
return render(request, 'post_upload.html', context)
You have to call form.save_m2m() to save tags when using django-taggit library like this:
post_form = PostUpload(request.POST, request.FILES, instance=request.user)
if post_form.is_valid():
obj = post_form.save(commit=False)
obj.save()
# Without this next line the tags won't be saved.
post_form.save_m2m()
messages.success(request, 'Your Post has been successfully posted')
print(request.POST)
print(tags)
return HttpResponseRedirect(reverse('post_upload'))
You can read more here.
Inside post_upload method, are you sure you need instance=request.user to create a post_form object?
I have an image upload function in django. However, images cannot be uploaded. The page is redirected to successURL. I don't understand the cause.
The view is current because it uses multiple forms.
#view
def UserEdit(request):
if request.method == 'POST':
form = forms.UserUpdateForm(request.POST, instance=request.user)
subform = forms.ProfileUpdateForm(request.POST, instance=request.user.profile)
if all([form.is_valid(), subform.is_valid()]):
user = form.save()
profile = subform.save()
return redirect('person:myaccount', username=request.user)
else:
form = forms.UserUpdateForm(instance=request.user)
subform = forms.ProfileUpdateForm(instance=request.user.profile)
return render(request, 'accounts/accounts_edit.html', {
'form': form,
'subform': subform,
})
#form
class UserUpdateForm(forms.ModelForm):
#...
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = profile
fields = ('first_name','last_name','birthday','image',)
#model
class profile(models.Model):
image = models.ImageField(upload_to='profile/',default='profile/default.jpg')
#html
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="text-center col-lg-6 col-md-6 col-sm-10 mx-auto">
<div class="form-group">
{{ form }}
</div>
<div class="form-group">
{{ subform }}
</div>
<button type="submit" class="fadeIn fourth btn btn-light">Submit</button>
</div>
</form>
I have a view where they are multiple posts and I want when the user like one of them, the form take the user_id and the post_id and save it into the DB. This is th Models.py:
class LikePost(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Posts, on_delete=models.CASCADE)
def __str__(self):
return '{} - {}'.format(self.user.username, self.post.name)
Forms.py:
class LikePostForm(forms.ModelForm):
class Meta:
model = LikedShops
fields = ['user', 'post']
widgets = {
'user': forms.HiddenInput(),
'post': forms.HiddenInput()
}
Views.py:
def posts(request):
if request.method == 'POST':
form = LikePostForm(request.POST)
if form.is_valid():
u = form.save(commit=False)
u.user = request.user
u.save()
return redirect('posts')
else:
form = LikePostForm()
context = {
'posts': Posts.objects.all(),
'form': form
}
return render(request, "posts.html", context)
and this the form in posts.html:
{% for post in posts %}
<div class="col-md-3">
<article class="card mb-4">
<header class="card-header">
<h4 class="card-title"><b>{{ post.name }}</b></h4>
</header>
<img style="width: 100%; height: 150px;" class="card-img" src="{{ post.image.url }}"/>
<div class="card-body">
<p class="card-text">{{ post.description }}</p>
</div>
{% if user.is_authenticated %}
<div class="card-footer">
<div class="row">
<div class="col">
<form action="/posts/" method="post">
{% csrf_token %}
{{ l_form|crispy }}
<button type="submit" class="btn btn-outline-success">Like</button>
</form>
</div>
</div>
</div>
{% endif %}
</article><!-- /.card -->
</div>
{% endfor %}
This is my edit, I did what you said, I made changes to:
forms.py:
class Meta:
model = Liked
fields = ['user', 'post']
widgets = {
'user': forms.HiddenInput(),
'post': forms.HiddenInput()
}
posts.html:
<form action="/posts/" method="post">
{% csrf_token %}
<input type="hidden" name="post" value="{{ post.pk }}">
{{ l_form|crispy }}
<button type="submit" class="btn btn-outline-success">Like</button>
</form>
views.py:
def posts(request):
if request.method == 'POST':
l_form = LikePostForm(request.POST, instance=request.user.profile)
if l_form.is_valid():
u = l_form.save(commit=False)
u.post = Posts.objects.filter(pk=l_form.cleaned_data.get('post')).first()
u.save()
messages.success(request, f"Form is valid!")
else:
messages.warning(request, f'Form is not valid! {request.POST}')
else:
l_form = LikePostForm(instance=request.user.profile)
context = {
'post': Posts.objects.all(),
'l_form': l_form
}
return render(request, "posts.html", context)
Now when I click the Like button, I got this message **Form is not valid! <QueryDict: {'csrfmiddlewaretoken': ['cNk9ZDS33Nj0l95TBfwtedL1jjAbzDSrH15VjMNZAcxjQuihWNZzOkVnIyRzsjwN'], 'post': ['1', ''], 'user': ['1']}>**
There are a couple of issues with your code.
First, the __str__() method should return a string and not a tuple
class LikePost(models.Model):
...
def __str__(self):
return '{} - {}'.format(self.user.username, self.post.name)
Second, there is a typo; change Pots to Posts:
context = {
'posts': Posts.objects.all(),
'form': form,
}
return render(request, "posts.html", context)
And third and last, the line u.post = request.post is throwing the error you mention, because the request object has no attribute post.
So change your form code to add the post in hidden state (I used fields instead of exclude):
class LikePostForm(forms.ModelForm):
class Meta:
model = LikePost
fields = ['post', ]
widgets = {
'post': forms.HiddenInput(),
}
and then change your view:
form = LikePostForm(request.POST)
if form.is_valid():
u = form.save(commit=False)
u.user = request.user
u.save()
After edit to the question:
Try adding post.pk as a hidden input in your form:
<form action="/posts/" method="post">
{% csrf_token %}
<input type="hidden" name="post" value="{{ post.pk }}">
{{ l_form|crispy }}
<button type="submit" class="btn btn-outline-success">Like</button>
</form>
or you can also do in your view:
u.post = Posts.objects.filter(pk=form.cleaned_data.get('post')).first()
I have main model Entertainment and related model EntertainmentCollage. Now i'm doing edditing page for my models in which I will need to transfer for editing both models.
I understand how to transfer one form to the form but with a related model I have difficulty.
class Entertainment(models.Model):
main_photo = models.ImageField(upload_to = 'where/')
place = models.CharField(max_length=200)
description = models.CharField(max_length=200)
event_date = models.DateTimeField(auto_now_add=False, blank=True, null = True)
class EntertainmentCollage(models.Model):
img = models.ImageField(upload_to = 'entertainment/portfolio', blank = True)
album = models.ForeignKey(Entertainment, blank = True, null = True)
forms.py
class WhereCreateForm(ModelForm):
class Meta:
model = Entertainment
fields = ['main_photo','place','description', 'event_date' ]
views.py
def edit_where(request, pk):
place = Entertainment.objects.get(id=pk)
form = WhereCreateForm(instance=place)
if request.user.is_authenticated():
if request.method == "POST":
form = WhereCreateForm(request.POST, request.FILES, instance=place)
if form.is_valid():
form.save()
return redirect('entertainment:where_list')
else:
form = WhereCreateForm()
return render(request, "entertainment/where_edit.html", {'form': form})
html
<form method = "post">
{% csrf_token %}
<p>{{ form.description }}</p>
<p>{{ form.place }}</p>
<p>{{ form.event_date }}</p>
</div>
<div class="col-md-9">
<section class="admin-section">
<div class="row">
<div class="col-md-4 admin__block" is-cover="false">
<div class="cover__wrapper edit__wrapper">
<a class="delete-button">Delete</a>
<a class="make-cover-button">Cover</a>
<img src="img/place-placeholder-1.jpg" alt="">
</div>
</div>
</div>
Add photo
</section>
<section>
<h4>Description</h4>
{{ form.description }}
Save
Cancel
</section>
</form>
As #art06 said in his comment you can use inline formsets.
You can do something like this:
from django.forms import inlineformset_factory
def edit_where(request, pk):
place = Entertainment.objects.get(id=pk)
FormSet2 = inlineformset_factory(Entertainment, EntertainmentCollage)
form = WhereCreateForm(instance=place)
form2 = FormSet2()
if request.user.is_authenticated():
if request.method == "POST":
form = WhereCreateForm(request.POST, request.FILES, instance=place)
form2 = FormSet2(request.POST or None, instance=place)
if form.is_valid():
if form2.is_valid():
form.save()
form2.save()
return redirect('entertainment:where_list')
else:
form = WhereCreateForm()
form2 = FormSet2()
return render(request, "entertainment/where_edit.html", {'form': form, 'form2': form2})
To add new form into template you can use:
{{ form2.management_form }}
{% for frm in form2 %}
{{ frm.as_table }}
{% endfor %}
I've made a profile model in models.py:
class Profile(models.Model):
user = models.OneToOneField(User)
title = models.CharField(max_length=20, default='title')
firstname = models.CharField(max_length=40, default='firstname')
lastname = models.CharField(max_length=40, default='lastname')
blurb = models.CharField(max_length=500, default='tell us about yourself')
#work out how to make filename equal the username
pic = models.ImageField(default="static/profile/blank.png", upload_to='static/profile/%d%m%y.jpg') #+ user.pk + '.jpg')
def __unicode__(self):
return self.user.username
and here is the view for a page to edit the profile of a logged in user:
def editprofile(request):
u_p = request.user.profile
template = loader.get_template('registration/editprofile.html')
if request.method == 'POST':
form = ProfileForm(request.POST, instance=u_p)
if form.is_valid():
form.save()
else:
# todo
None
else:
#todo
context = RequestContext(request, {'form': form})
return HttpResponse(template.render(context))
The template fragment reads:
<form method="POST" action=".">
{% csrf_token %}
<div class="regformout">
<div class="regform">
{% for field in form %}
<div class='cell'> {{ field.label_tag }} </div>
<div class='nogin'> {{ field.errors }} </div>
<div class='cell'> {{ field }} </div>
{% endfor %}
</div>
</div>
<input class="btn btn-large btn-primary" type="submit" value="Save Your Profile" ></input>
</form>
I want the form fields to automatically populate with the data for the current user on the corresponding page for editing the profile. However, no matter what I try I cannot make this happen. What am I doing wrong here?
Your main problem is you are only populating the form if the user hits the submit button, so when the view is requested initially, your form is empty.
from django.shortcuts import render, redirect
def editprofile(request):
u_p = request.user.profile
form = ProfileForm(request.POST or None, instance=u_p)
if request.method == 'POST':
if form.is_valid():
form.save()
return redirect('/')
return render(request,
'registration/editprofile.html', {'form': form})