After displaying my posts, I don't manage to Edit any of them.
When I print the instance variable which is in views.py in my terminal, it displays only the title and the author like this title - author, which is the method defined in models.py.
Help please!
Views.py
#login_required(login_url='login_view')
def update_post_view(request, post_id, slug=None):
instance = Article.objects.get(id = post_id)
if request.method == 'POST':
form = UpdatePostForm(request.POST, request.FILES, instance=instance)
if form.is_valid():
form.save()
return redirect('posts_view')
else:
form = UpdatePostForm(instance=instance)
return render(request,'update_post.html', {'form':form})
forms.py
class UpdatePostForm(forms.ModelForm):
class Meta:
model = Article
fields = ('author',)
title = forms.CharField(max_length=255, label='username',
widget= forms.TextInput(attrs= {'placeholder':'Title...', 'class': 'title'}))
body = forms.CharField(max_length=255, label='body', required=True, widget=forms.Textarea(attrs={'placeholder':'Start writing your post...'}))
urls.py
path('update_post/<int:post_id>/<slug:slug>', views.update_post_view, name='update_post_view')
update_post.html
{% extends 'base.html' %}
{% block title %}Update Post{% endblock %}
{% block content %}
<h2>Update Posts...</h2>
<form action="" method="POST">
{% csrf_token %}
<div>
<h3>{{form.title}}</h3>
<small>{{form.author}}</small>
<p>{{form.body}}</p>
</div>
<button class="btn btn-secondary">Update</button>
</form>
{% endblock %}
Related
I have the following models, and as you can see they are related to each other
class Leads(models.Model):
project_id = models.BigAutoField(primary_key=True, serialize=False)
created_at = models.DateTimeField(auto_now_add=True)
expected_revenue = MoneyField(decimal_places=2,max_digits=14, default_currency='USD')
expected_licenses = models.IntegerField()
country = CountryField(blank_label='(select_country)')
status = models.CharField(choices=[('Open', 'Open'), ('Closed', 'Closed'), ('Canceled', 'Canceled'),
('Idle', 'Idle')
], max_length=10)
estimated_closing_date = models.DateField()
services = models.CharField(choices=[('Illumination Studies', 'Illumination Studies'),
('Training', 'Training'),('Survey Design Consultancy', 'Survey Design Consultancy'),
('Software License', 'Software License'),
('Software Development','Software Development')], max_length=40)
agent = models.ForeignKey(Profile, default='agent',on_delete=models.CASCADE)
company = models.ForeignKey(Company,on_delete=models.CASCADE)
point_of_contact = models.ForeignKey(Client, default='agent',on_delete=models.CASCADE)
updated_at = models.DateTimeField(auto_now=True)
application = models.CharField(choices=[('O&G','O&G'),('Renewables','Renewables'),('Mining','Mining'),
('Other','Other'),('CSS','CSS')],
default='O&G',max_length=20)
sub_category = models.CharField(choices=[('Wind','Wind'),('Geo-Thermal','Geo-Thermal'),('Solar','Solar'),
('Tidal','Tidal')], max_length=20, blank=True)
#property
def age_in_days(self):
today = date.today()
result = self.estimated_closing_date - today
return result.days
def __str__(self):
return f'{self.project_id}'
class LeadEntry(models.Model):
revenue = MoneyField(decimal_places=2,max_digits=14, default_currency='USD',blank=True)
date = models.DateField()
lead_id = models.ForeignKey(Leads,on_delete=models.CASCADE)
id = models.BigAutoField(primary_key=True, serialize=False)
probability = models.DecimalField(max_digits=2, decimal_places=2, default=0, blank=True)
#property
def est_revenue(self):
result = self.revenue * probabiity
return result
Essentially a lead entry is related to the lead, and I'm using HTMX to essentially add data to LeadEntry database using a form.
Form
class LeadEntryForm(forms.ModelForm):
class Meta:
model = LeadEntry
fields = ('lead_id','date','revenue','probability')
widgets = {'date': DateInput()}
I have 2 views, one that will simply pass an HTML with a button for the user to add entries to the database, and another view with the actual form
views
#login_required
def add_to_forecast(request):
id = request.GET.get('project_id')
request.session['lead_id'] = id
return render(request, 'account/lead_forecast.html')
#login_required
def forecast_form(request):
if request.method=='POST':
form = LeadEntryForm(data=request.POST or None)
if form.is_valid():
form.save(commit=False)
messages.success(request,"Successful Submission")
return redirect('add_to_forecast')
lead_id = request.session['lead_id']
data = {'lead_id':lead_id}
context = {
"form":LeadEntryForm(initial=data)
}
return render(request, 'account/lead_entry_forecast.html', context)
Lastly, there are 2 HTML pages, the first one is associated with add_to_forecast and renders a simple page, this is where the HTMX happens and this adds the form from the next HTML page
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% load static %}
{% block title %}Client Information {% endblock %}
{% block content %}
<h1> Add Lead to Sales Forecast </h1>
<p>Click the Button below to add a Payment Date</p>
<button type="button" hx-get="{% url 'lead_entry_forecast' %}" hx-target="#leadform" hx-swap="beforeend" >
Add Lead </button>
<div id="leadform">
<br>
</div>
{% endblock %}
The form that is added by the user as many times they want to do so
{% load crispy_forms_tags %}
{% load static %}
{% block content %}
<div class="container-fluid">
<form method="post" enctype="multipart/form-data" action=".">
{% csrf_token %}
<div class="row justify-content-center">
<div class="col-sm-1">
{{ form.lead_id|as_crispy_field }}
</div>
<div class="col-sm-2">
{{ form.date|as_crispy_field }}
</div>
<div class="col-sm-2">
{{ form.revenue|as_crispy_field }}
</div>
<div class="col-sm-1">
{{ form.probability|as_crispy_field }}
</div>
<div class="col-sm">
<input type="submit" value="Submit" >
</div>
</div>
</form>
</div>
<hr>
{% endblock %}
The problem I have is that after submitting the form, everything seems to be working, obviously, at the moment you can only submit one lead, as I still have to add more logic, but at the moment the form is not sending data to the DB, after some debugging, I was not able to pass the POST, it seems like is just not submitting anything.
Any help will be highly appreciated
Update - 12/4/2021
I have tried to submit data using the form and it actually works, so there is nothing wrong with the form submitted the POST.request, if I go directly to the URL, it works fine, so the form is submitted correctly and the database is updated.
I still don't understand why is not working when the form is rendered by the htmx, so it has something to do with that.
When you are designing an HTMX page, you have to be careful with the post request, so I was processing the form in the wrong view, please see below the views:
#login_required
def add_to_forecast(request):
form = LeadEntryForm(data=request.POST or None)
if request.method == 'POST':
if form.is_valid():
form.save()
return HttpResponse("Success")
else:
return render(request, 'account/lead_entry_forecast.html', {"form": form})
id = request.GET.get('project_id')
request.session['lead_id'] = id
return render(request, 'account/lead_forecast.html')
#login_required
def forecast_form(request):
lead_id = request.session['lead_id']
data = {'lead_id':lead_id}
context = {
"form":LeadEntryForm(initial=data)
}
return render(request, 'account/lead_entry_forecast.html', context)
Now it works as it should
I am trying to add a comment section to add a comment section to my blog detail using django but when i run my server i get no error in the development server and the comments are not being displayed. I added the comments from my admin site.
The snippet of my code is below.
views.py
from .models import Post
from django.utils import timezone
from .forms import PostForm, CommentsForm
from django.contrib.auth.decorators import user_passes_test
# Create your views here.
def home(request):
return render (request, 'blogapp/home.html')
def blog_list(request):
post = Post.objects.order_by('-published_date')
context = {
'posts':post
}
return render(request, 'blogapp/blog_list.html', context)
def blog_detail(request, pk=None):
detail = Post.objects.get(pk=pk)
context = {
'detail': detail
}
return render(request, 'blogapp/blog_detail.html', context)
def add_post(request, pk=None):
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid:
body = form.save(commit=False)
body.published_date = timezone.now()
body.save()
return redirect('blog_list')
form = PostForm()
else:
form = PostForm()
context = {
'form': form
}
return render(request, 'blogapp/add_post.html', context)
def add_comments(request, pk=None):
if request.method == "POST":
form = CommentsForm(request.POST)
if form.is_valid:
comment = form.save(commit=False)
comment.date_added = timezone.now()
comment.save()
return redirect('blog_detail')
form = CommentsForm()
else:
form = CommentsForm()
context = {
'form': form
}
return render(request, 'blogapp/add_comments.html', context)
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name="homepage"),
path('blog/', views.blog_list, name="blog_list"),
path('blog/post/<int:pk>/', views.blog_detail, name="blog_detail"),
path('blog/add_post/', views.add_post, name="add_post"),
path('blog/add_comments/', views.add_comments, name="add_comments"),
]
forms.py
from django import forms
from .models import Post, Comments
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('author', 'title', 'post_description', 'image', 'image_description', 'body',)
class CommentsForm(forms.ModelForm):
class Meta:
model = Comments
fields = ('post', 'name', 'body',)
models.py
from django.db import models
from django.utils import timezone
# Create your models here.
class Post(models.Model):
author = models.ForeignKey('auth.user', on_delete=models.CASCADE)
title = models.CharField(max_length=300)
body = models.TextField()
post_description = models.CharField(max_length=500, blank=True, null=True)
image = models.ImageField(blank=True, null=True, upload_to="image/")
image_description = models.CharField(max_length=500, blank=True, null=True)
published_date = models.DateTimeField(default=timezone.now, blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
class Comments(models.Model):
post = models.ForeignKey('Post', related_name="comments", on_delete=models.CASCADE)
body = models.TextField()
name = models.CharField(max_length=300)
date_added = models.DateTimeField(default=timezone.now, blank=True, null=True)
def __str__(self):
return '%s - %s' % (self.post.title, self.name)
blog_detail.html
{% extends 'base.html' %}
{% load static %}
{% block content %}
<article>
<strong>
<h1><b>{{ detail.title }}</b></h1>
</strong>
<h3>POST AUTHOR: {{ detail.author }}</h3>
<h4><i>{{ detail.post_description }}</i></h4>
<h4>PUBLISHED:{{ detail.published_date }}</h4>
<p>
<hr>
{% if detail.image %}
<center>
<br>
<img src="{{ detail.image.url }}" width="1000" height="700">
<br><br>
<i>IMAGE DESCRIPTION: {{ detail.image_description }}</i>
</center>
{% endif %}
<hr>
<br><br><br>
{{ detail.body|linebreaksbr }}
</p>
<hr class="solid">
<h2>COMMENTS ...</h2>Add One
{% for comment in post.comments.all %}
<strong>
{{ comment.name }}-{{ comment.date_added }}
</strong>
{{ comment.body }}
{% endfor %}
</article>
{% endblock %}
add_comments.html
{% extends 'base.html' %}
{% block content %}
<article>
{% if user.is_authenticated %}
<h1>CREATE NEW BLOG POST.</h1>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">ADD COMMENT</button>
<input type="hidden" name="next" value="{% url 'blog_detail' pk=post.pk %}"/>
</form>
{% else %}
<h2>Login HERE to add comments.</h2>
{% endif %}
</article>
{% endblock %}
in your template you use
{% for comment in post.comments.all %}
but in template context there is no post variable
you should use {% for comment in detail.comments.all %}
I am working on a Hybrid of Quora and StackOverflow clone. I have made an "add_answer" view for letting me add answers to the questions but for some reasons it is showing the integrity error:
Here's the error image
But when I add through admin panel then it adds answer in the database. What is wrong?
The code is as follows:
models.py:
class Answer(models.Model):
content = models.TextField()
user = models.ForeignKey(User,on_delete=models.CASCADE)
question = models.ForeignKey(Question,on_delete=models.CASCADE,blank=False)
created = models.DateTimeField(auto_now_add=True)
upvotes = models.PositiveIntegerField(default=0)
is_active = models.BooleanField(default=True)
def __str__(self):
return '{}\'s Answer'.format(self.user.username)
class Meta:
ordering = ('-upvotes','-created')
forms.py:
class AnswerForm(forms.ModelForm):
content = forms.CharField(widget=forms.Textarea,help_text='Your Answer in Detail. Note: MarkDown is enabled.')
class Meta:
model = Answer
fields = ['content']
def __init__(self,author,question,*args,**kwargs):
super().__init__(*args,**kwargs)
self.user = author
self.question = question
"add_answer" view (views.py):
#login_required
def add_answer(request, pk):
ques = get_object_or_404(Question, pk = pk)
if request.method == 'POST':
form = AnswerForm(request.user,ques,request.POST)
if form.is_valid():
cd = form.cleaned_data
answer = form.save(commit=False)
answer.content = cd['content']
answer.save()
messages.success(request,'Success! Your Answer has been added!')
return redirect('forum')
else:
messages.error(request,form.errors)
else:
form = AnswerForm(request.user,ques)
return render(request,'discussion/answer_create.html',{'form':form})
answer_create.html (template):
{% extends 'base.html' %}
{% load markdownify %}
{% block title %} Add Answer {% endblock %}
{% block header %}
<h2 class="display-5" style="font-family: x-locale-heading-primary,zillaslab,Palatino,Palatino Linotype,x-locale-heading-secondary,serif;">
Add Answer:
</h2>
{% endblock %}
{% block content %}
{% if form.errors %}
<h4 class="alert alert-primary alert-warning" role="alert">Errors:<br> {{form.errors}} <hr></h4>
{% endif %}
<form action="" method="POST">
{% csrf_token %}
{{form.as_p}}
<input type="submit">
</form>
{% endblock %}
It would be really grateful if somebody helps me out.
You forgot to assign the question instance to answer model
answer.question = ques
ques = get_object_or_404(Question, pk = pk)
if form.is_valid():
cd = form.cleaned_data
answer = form.save(commit=False)
answer.question = ques
answer.content = cd['content']
answer.save()
you can also do the following in model form init
def __init__(self,author,question,*args,**kwargs):
super().__init__(*args,**kwargs)
self.form.instance.user = author
self.form.instance.question = question
The Django project that I am working on lists patient details and lets the user edit the details. I have been able to list it out but views.py is not getting linked to the url for updating the list.
views.py:
def update_patient(request, patient_id):
patient = Patient.objects.get(id=patient_id)
if request.method != 'POST':
form = PatientForm(instance=patient)
else:
# POST data submitted; process data.
form = PatientForm(instance=patient, data=request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('patient:patient',
args=[patient.id]))
context = { 'patient': patient, 'form': form}
return render(request, 'patient/update_patient.html', context)
models.py:
class Patient(models.Model):
patientID = models.CharField(max_length=20)
firstName =models.CharField(max_length=20)
lastName = models.CharField(max_length=20)
age = models.IntegerField(max_length=None)
SSN = models.CharField(max_length=15)
address = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
urls.py:
url(r'^patients/(?P<patient_id>\update\d+)/$', views.update_patient, name='update'),
update_patient.html:
{% extends "patient/base.html" %} {% block content %}
<p>{{ patient }}
</p>
<p>Update Patient:</p>
<form action="{% url 'patient:update' patient.id %}" method='post'>
{% csrf_token %} {{ form.as_p }}
<button name='submit'>add entry</button>
</form>
{% endblock content %}
Your URL pattern is wrong, you have \update within capturing group, it shouldn't be, change the pattern to this:
url(r'^patients/(?P<patient_id>\d+)/update/$', views.update_patient, name='update')
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']
#The two below codes do exactly the same thing but partition is faster
extention = url.rpartition('.')[2].lower()
#extension = url.rsplit('.',1)[1].lower()
if extension not in valid_extensions:
raise forms.ValidationError('The given URL does not match valid image extensions')
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.rpartition('.')[2].lower())
#download image from the given URL
response = request.urlopen(image_url)
image.image.save(image_name,ContentFile(response.read()),save=False)
if commit:
image.save()
return image
The image appears alright but the fields are not showing
index.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}Bookmark an image{% endblock %}
{% block content %}
<h1>Bookmark an image</h1>
<img src="{{ request.GET.url }}" class="image-preview">
<form action="." method="post">
{{ forms.as_p }}
{% csrf_token %}
<input type="submit" value= 'Bookmark it!'>
</form>
{% endblock %}
change your form to this
you pass the fields in list and not set type {}
class ImageCreateForm(forms.ModelForm):
class Meta:
model = Image
fields = ['title', 'url', 'description']
widgets = {
'url':forms.HiddenInput,
}
in your views
def image_create(request):
if request.method == 'POST':
#form is sent
form = ImageCreateForm(request.POST)
if form.is_valid():
#form data is valid
cd = form.cleaned_data
new_item = form.save(commit=False)
#assign current user to the item
new_item.user = request.user
new_item.save()
messages.success(request, 'Image added successfully')
#redirect to new created item detail view
return redirect(new_item.get_absolut_url())
else:
#build form with data provided by the bookmarklet via GET
form = ImageCreateForm()
return render(request, 'images/image/index.html',{'section':'images', 'form':form})
and in html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}Bookmark an image{% endblock %}
{% block content %}
<h1>Bookmark an image</h1>
<img src="{{ request.GET.url }}" class="image-preview">
<form action="." method="post">
{{ form.as_p }}
{% csrf_token %}
<input type="submit" value= 'Bookmark it!'>
</form>
{% endblock %}
Although it does not look like it, make sure that the if request.method and its related else are on the same level. I sometimes get the else indented to match the if form.is_valid level.