I want to add tags to posts in my Django app.
I can add tags through the admin interface, but when I try to do it through the form I created, I get an IntegrityError.
I couldn't find the solution in the existing topics with the same error. I ran makemigrations and migrate.
From models.py:
class Post(models.Model):
title = models.CharField(null=False, blank=False)
text = models.TextField()
class Tag(models.Model):
post = models.ForeignKey('my_app.Post', on_delete=models.CASCADE, related_name='tags')
tag_text = models.CharField()
The view:
def post_add_tags(request, pk):
post= get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = TagForm(request.POST)
if form.is_valid():
tag = form.save()
tag.post= post
tag.save()
return redirect("single_post_view", pk=post.pk)
else:
form = TagForm()
return render(request, "add_tags.html", {"form": form})
The form from forms.py:
class TagForm(forms.ModelForm):
class Meta:
model = Tag
fields = ["tag_text"]
The template:
<form method="POST"> {% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save btn btn-default">Add tags</button>
</form>
The error:
IntegrityError at /post/4/add_tags/
NOT NULL constraint failed: my_app_tag.post_id
I'm using Django version 2.2, Python 3.6.8.
do not save form until you set all required fields, specially foreign keys :
def post_add_tags(request, pk):
post= get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = TagForm(request.POST)
if form.is_valid():
tag = form.save(commit=False)
tag.post= post
tag.save()
return redirect("single_post_view", pk=post.pk)
else:
form = TagForm()
return render(request, "add_tags.html", {"form": form})
Related
I am trying to upload image from form but whenever I submit everything got saved in database other than image field.But when I try to do samething from admin panel it works.
models.py
class Post(models.Model):
title = models.CharField(("Title"), max_length=100)
title_image = models.ImageField(
("Title Image"),
upload_to='static/Images/TitleImages/',
max_length=None,
blank = True,null = True)
Forms.py
class AddPostForm(ModelForm):
class Meta:
model = Post
fields = ['title','title_image']
Views.py
class AddPostView(LoginRequiredMixin,CreateView):
model = Post
template_name = 'MainSite/add_post.html'
fields = '__all__'
def dispatch(self, request, *args, **kwargs):
if request.user.is_anonymous:
messages.error(request,"You need to login to access this page")
return redirect('/')
elif request.user.is_superuser:
if request.method == "POST":
form = AddPostForm(request.POST)
if form.is_valid():
form.save()
messages.success(request,"POST added successfully")
return redirect('/')
else:
print("error")
else:
print("method is not post")
form = AddPostForm()
return render(request,'MainSite/add_post.html',{'form':form})
else :
messages.error(request,"You need to have superuser permission to access this page")
return redirect('/')
addpost.html
<form action= "" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.media }}
{{ form|crispy}}
<button class="btn btn-primary profile-button" style = "width:150px;"type="submit" >Add Post</button></div>
</form>
my model have 2 things title and title_image but whenever I submit only title is saved and when I do through admin panel it works.
I dont know what I am doing wrong here any advice will be helpful.
Thanks in advance
You've to pass request.FILES in order to save files
if request.method == "POST":
form = AddPostForm(request.POST, request.FILES)
if form.is_valid():
form.save()
messages.success(request,"POST added successfully")
return redirect('/')
I'm taking data that the user puts into a form and saving it to the database in Django. When I submit the form, the value actually does save to the database. But I keep getting this error. Not sure how to fix it?
views.py
def home(request):
if request.method == "GET":
form_for_post = {'form': PostForm()}
return render(request, "capstone/home2.html", form_for_post)
else:
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
city = form.cleaned_data['city']
place = Location.objects.create(username=request.user, city=city,)
place.save()
else:
return render(request, "capstone/home2.html")
models.py
class User(AbstractUser):
pass
class Location(models.Model):
city = models.CharField(max_length=500)
username = models.ForeignKey('User', on_delete=models.CASCADE,
related_name='author', null=True, blank=True)
forms.py:
class PostForm(forms.Form):
city = forms.CharField(max_length=500)
Form in html:
<form method="POST">
{% csrf_token %}
<label for="city">City:</label><br>
<input type="text" id="city" name="city"><br>
<input type="submit" value="Submit">
</form>
By default if request is made it will be a get request so don't need to add if request.method == 'GET'
so do like this
def home(request):
form_for_post = {'form': PostForm()}
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
city = form.cleaned_data['city']
place = Location.objects.create(username=request.user, city=city,)
place.save()
return render(request,"your_page_after_form_successfully_submited")
return render(request, "capstone/home2.html",form_for_post)
def home(request):
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
city = form.cleaned_data['city']
place = Location.objects.create(username=request.user, city=city,)
place.save()
else:
return render(request, "capstone/home2.html",form)
form_for_post = {'form': PostForm()}
return render(request, "capstone/home2.html", form_for_post)
try this one
I'm trying to create a post and update my list of posts. I currently get this error IntegrityError at /posts/create/ NOT NULL constraint failed: posts_post.publish Not sure what the error means and how to fix it. The files below are my posts/views.py, forms.py, post_forms.py and models
def posts_create(request):
# return HttpResponse("<h1> Create a posts. </h1>")
form = PostForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instance.save()
context = {
"form": form
}
# if request.method == "POST":
# print("This is the content: ", request.POST.get("content"))
return render(request, "post_form.html", context)
def posts_detail(request, id):
instance = get_object_or_404(Post, id=id)
context = {
"user": instance.user,
"instance": instance
}
return render(request, "posts_detail.html", context)
def posts_list(request):
# return HttpResponse("<h1> List a posts. </h1>")
# TODO: Privacy stuff
queryset = Post.objects.all()
context = {
"object_list": queryset,
"user": "username"
}
return render(request, "post.html", context)
Models for post:
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
status = models.CharField(max_length=6, choices=Status, default=POST)
content = models.TextField()
publish = models.DateField(auto_now=False, auto_now_add=False)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
privacy = models.IntegerField(choices=Privacy, default=PUBLIC)
unlisted = models.BooleanField(default=False)
This is the post_form.html
<html>
<body>
<h3>Create Post</h3>
<form method="POST" action="">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Share" />
</form>
</body>
</html>
This is the respective forms.py
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = [
"content"
]
from datetime import datetime
def posts_create(request):
# return HttpResponse("<h1> Create a posts. </h1>")
form = PostForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instance.publish = datetime.now()
instance.save()
context = {
"form": form
}
# if request.method == "POST":
# print("This is the content: ", request.POST.get("content"))
return render(request, "post_form.html", context)
do this in your view. import the first line then change your view
I've implemented a MultipleChoiceField form with a CheckboxSelectMultiple. It works perfectly in that the form is displayed and user selected options are saved to the BaseServicesOffered model as desired. The problem is that when the user goes back to the form, the checkboxes that the user had previously selected/submitted are not selected -- they are all unchecked. I'd imagine that it's a problem with my views.py. Here is my code:
models.py
class BaseServicesOffered(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
service = models.CharField(max_length=255, default='', null=True, blank=True)
def __str__(self):
return self.user.username
forms.py
class BaseServicesOfferedForm(forms.ModelForm):
service = forms.MultipleChoiceField(required=False, widget=forms.CheckboxSelectMultiple)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user') #this takes in the value of 'user', which is passed from the view function.
super(BaseServicesOfferedForm, self).__init__(*args, **kwargs)
self.fields['service'].choices = [(t.id, t.service) for t in AllServices.objects.filter(industrycode=user.userprofile.industry)]
class Meta:
exclude = ('user',)
model = BaseServicesOffered
views.py
#login_required(login_url="/accounts/login/")
def baseservicesoffered(request):
try:
base_services_offered = BaseServicesOffered.objects.create(user=request.user)
except:
pass
user = request.user
instance = get_object_or_404(BaseServicesOffered, user=user)
form = BaseServicesOfferedForm(request.POST or None, user=request.user, instance=instance)
if request.method == 'POST':
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
service = form.cleaned_data['service']
services = [int(i) for i in service]
instance.service = services
instance.save()
return redirect('/accounts/profile/')
else:
context = {'form': form}
return render(request, 'accounts/setup8.html', context)
context = {'form': form}
return render(request, 'accounts/setup8.html', context)
setup8.html
<form id="post_form" method="post" action="" enctype="multipart/form-data">
{{ form.non_field_errors }}
{% csrf_token %}
{{ form.as_p }}
<div class="submitbutton">
<button type="submit">
SUBMIT
</button>
</div>
</form>
Update:
This is how you store a list of ints in the Charfield:
service = form.cleaned_data['service']
services = [int(i) for i in service] #converts list of strings to list of ints
instance.service = services
I've updated my code above with this.
multiple_choice = forms.MultipleChoiceField(
label=u"Select multiple",
choices=MY_CHOICES,
widget=forms.widgets.CheckboxSelectMultiple,
initial=(c[0] for c in MY_CHOICES)
)
You should set the inital parameter for the options to be checked for a particular user.
I want to limit a queryset for a form based on the user sending the request. I am having some trouble getting a ModelForm to properly limit the queryset of a field when the form is submitted but invalid. The form gets redisplayed with the error text, but no longer has the queryset limited. What could be the cause here?
models.py
from django.db import models
from django.contrib.auth.models import User
class Patient(models.Model):
name = models.CharField(max_length=100)
doctor = models.ForeignKey(User)
def __unicode__(self):
return self.name
class Prescription(models.Model):
name = models.CharField(max_length=100)
patient = models.ForeignKey(Patient)
views.py
import medical.models as models
import medical.forms as forms
from django.shortcuts import render
def add_form(request):
if request.method == 'POST':
form = forms.PrescriptionForm(request.POST)
if form.is_valid():
form.save()
else:
form = forms.make_prescription_form(request.user)
return render(request, 'add_form.html', {'form': form})
forms.py
import medical.models as models
from django.forms import ModelForm, ModelChoiceField
class PrescriptionForm(ModelForm):
class Meta:
model = models.Prescription
def make_prescription_form(dr):
class PrescriptionForm(ModelForm):
patient = ModelChoiceField(queryset=models.Patient.objects.filter(doctor=dr))
class Meta:
model = models.Prescription
return PrescriptionForm
add_form.html
{{ request.user.first_name }}
{% if form.errors %}
<p style="color: red;">Please correct the error{{ form.errors|pluralize }} below.</p>
{% endif %}
<form action="" method="post">{% csrf_token %}
{{ form }}
<br>
<input type="submit" value="Submit">
</form>
I would greatly appreciate any help with this, or suggestion on a better way to achieve the same thing! Let me know if any more files would be helpful. I'm using Django 1.3.
First off, it looks like you left off a bit - make_prescription_form returns a class, not a form instance, and you're passing the class directly to the rendering in the GET path. I am assuming that's a typo.
You're not using your make_prescription_form wrapper in the POST path. The smallest change from this implementation would be:
def add_form(request):
form_class = forms.make_prescription_form(request.user)
if request.method == 'POST':
form = form_class(request.POST)
if form.is_valid():
form.save()
else:
form = form_class()
return render(request, 'add_form.html', {'form': form})
As for other ways to do this - you can just set the form field's queryset directly in your view.
forms.py
class PrescriptionForm(ModelForm):
class Meta:
model = models.Prescription
views.py
def add_form(request):
if request.method == 'POST':
form = PrescriptionForm(request.POST)
form.fields['patient'].queryset = models.Patient.objects.filter(doctor=request.user)
if form.is_valid():
form.save()
else:
form = PrescriptionForm()
form.fields['patient'].queryset = models.Patient.objects.filter(doctor=request.user)
return render(request, 'add_form.html', {'form': form})
Or set doctor as an argument to PrescriptionForm's __init__ and update the queryset there:
forms.py
class PrescriptionForm(ModelForm):
class Meta:
model = models.Prescription
def __init__(self, *args, doctor=None, **kwargs):
super(PrescriptionForm, self).__init__(*args, **kwargs)
if self.doctor is not None:
self.fields['patient'] = models.Patient.objects.filter(doctor=doctor)
views.py
def add_form(request):
if request.method == 'POST':
form = PrescriptionForm(request.POST, doctor=request.user)
if form.is_valid():
form.save()
else:
form = PrescriptionForm(doctor=request.user)
return render(request, 'add_form.html', {'form': form})