FOREIGN KEY constraint failed , django - python

I have to insert the post through a form but when i submit i got this error FOREIGN KEY constraint failed, the problem is with the author field
models.py
class Post(models.Model):
STATUS_CHOICES = (
('draft','Draft'),
('published','Published'),
)
title = models.CharField(max_length=100)
slug = models.SlugField(max_length=120)
author = models.ForeignKey('auth.User',related_name='blog_posts',on_delete=models.CASCADE,blank=True, null=True)
body = RichTextField()
created = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10,choices=STATUS_CHOICES,default='draft')
tag = models.OneToOneField(Tag,related_name="blog_tag",on_delete=models.CASCADE,default=0)
def __str__(self):
return self.title
views.py
def tagView(request,name):
tag = Tag.objects.get(name=name)
post_form = PostForm(request.POST or None)
if request.method == 'POST':
post_form = PostForm(request.POST)
if post_form.is_valid():
item = post_form.save(commit=False)
item.author = request.user
item.save()
return HttpResponseRedirect(request.path_info)
context = {
'post_form' : post_form,
'tag' : tag,
}
return render(request,'blog/tagPage.html',context)
forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title','body']
template
<form class="post-form" method="POST" enctype="multipart/form-data" action="">
{% csrf_token %}
{{ post_form }}
<input class="post-form-submit submit" type="submit" value="Save">
</form>

If the author field is the problem, be sure to import auth.User

My guess is that you are trying to add the post as anonymous but anonymous user is not null (id is though). Also don't use 'auth.User' and follow the instructions from the documentation.

Related

Unique=True in Django model gives IntergretyError instead of ValidationError

I want to show a validation message like "This email is already in use" inside my html form.
But I think i'm missing something. I keep getting an IntegrityError at my email field. Isn't Django supposed to validate this and give an ValidationError if I use unique=True in my model? Or do I have to Try and Catch the IntegrityError myself?
Or maybe show me a best practice for validating unique users inside a form/model.
models.py
class Customer(models.Model):
FirstName = models.CharField(max_length=50)
LastName = models.CharField(max_length=50)
Email = models.CharField(max_length=50, unique=True, error_messages={'unique':"This email is already in use"})
views.py
def customerform(request):
if request.method == 'POST':
form = CustomerForm(request.POST)
if form.is_valid():
post = Customer()
post.FirstName = form.cleaned_data['FirstName']
post.LastName = form.cleaned_data['LastName']
post.Email = form.cleaned_data['Email']
post.save()
return render(request, 'results.html', {
'FirstName': form.cleaned_data['FirstName'],
'Email': form.cleaned_data['Email'],})
else:
form = CustomerForm()
return render(request, 'form.html', {'form':form})
forms.py
class CustomerForm(forms.Form):
FirstName = forms.CharField (label='First name:', max_length=50)
LastName = forms.CharField (label='Last name:', max_length=50)
Email = forms.EmailField(label='Email:', max_length=50)
form.html
<form action="/customer/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
If you want form validation to automatically use the model attributes, you have to use a ModelForm:
class CustomerForm(forms.ModelForm):
class Meta:
model = Customer
fields = ["FirstName", "LastName", "Email"]
If you want to use a regular Form, you need to do the validation manually.
def customerform(request):
if request.method == 'POST':
form = CustomerForm(request.POST)
if form.is_valid():
# first we check if email is valid
customer = Customer.objects.filter(Email = form.cleaned_data['Email'])
if customer.count() == 0: # email not in use
post = Customer()
post.FirstName = form.cleaned_data['FirstName']
post.LastName = form.cleaned_data['LastName']
post.Email = form.cleaned_data['Email']
post.save()
return render(request, 'results.html', {
'FirstName': form.cleaned_data['FirstName'],
'Email': form.cleaned_data['Email'],})
else: # email in use so we redirect to html and we add an error message
render(request, 'form.html', {'form':form,'error','This email is already in use'})
else:
form = CustomerForm()
return render(request, 'form.html', {'form':form})
<form action="/customer/" method="post">
{% if error %}
<b> {{ error }} </b> <br>
{% endif %}
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>

Why am I getting a null constraint error?

I'm Trying to add comments to Facts(posts). When I try to submit a comment I get the following error? I'm using Postgres FYI
IntegrityError at /fc/2/comment/
null value in column "comment_id" violates not-null constraint
DETAIL: Failing row contains (8, It has plugins too, 2018-10-03 07:41:25.249524+00, 1, null).
Exception Value:
null value in column "comment_id" violates not-null constraint
DETAIL: Failing row contains (8, It has plugins too, 2018-10-03 07:41:25.249524+00, 1, null).
Model:
class Fact(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(
default=timezone.now)
published_date = models.DateTimeField(
blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
class Comment(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
comment = models.ForeignKey('fc.Fact', on_delete=models.CASCADE, related_name='comments')
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
View:
def add_comment_to_post(request,pk):
fc = get_object_or_404(Fact, pk=pk)
if request.method =="POST":
form =CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.fc = fc
comment.save()
return redirect('fc_detail',pk=fc.pk)
else:
form =CommentForm()
return render(request,'add_comment_to_post.html',{'form':form})
Form view:
{% extends 'base.html' %}
{% block content %}
<h1>Check this fact</h1>
<form method="POST" class="post-form">{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save btn btn-default">Save</button>
</form>
{% endblock %}
Form:
class FcForm(forms.ModelForm):
class Meta:
model = Fact
fields = ('title', 'text',)
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('author', 'text',)
Why is the comment_id null, I would have thought Django auto-populates this as it did with my Fact model.
Appreciate help on this.
Thank you.
It should be
comment.comment = fc
instead of
comment.fc = fc
hence your view will be
def add_comment_to_post(request, pk):
fc = get_object_or_404(Fact, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.comment = fc # change is here <<<
comment.save()
return redirect('fc_detail', pk=fc.pk)
else:
form = CommentForm()
return render(request, 'add_comment_to_post.html', {'form': form})

Getting "This field is required" error even though I set null=True and blank=True

I have a Post model for users submitting posts. I've given the content field of Post an attribute of blank=True. But for some reason django tells me content is still required. form_post.errors prints this:
<ul class="errorlist"><li>content<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
Here's my code:
models
class Post(models.Model):
...
user = models.ForeignKey(User, blank=True, null=True)
title = models.TextField(max_length=76)
content = models.TextField(null=True, blank=True)
category = models.CharField(max_length=20, choices=CATEGORY_CHOICES, default='1')
forms
class PostForm(forms.ModelForm):
content = forms.CharField(widget=PagedownWidget)
title = forms.TextInput(attrs={'placeholder': 'title'})
class Meta:
model = Post
fields = [
'title',
'content',
'category',
'image',
'id',
'user'
]
views
def post(request):
allauth_login = LoginForm(request.POST or None)
allauth_signup = SignupForm(request.POST or None)
if request.user.is_authenticated():
form_post = PostForm(request.POST or None, request.FILES or None)
if form_post.is_valid():
print('valid')
instance = form_post.save(commit=False)
instance.user = request.user
category = form_post.cleaned_data['category']
for a, b in CATEGORY_CHOICES:
if a == category:
category = b
form_post.save()
return HttpResponseRedirect('/%s' % category)
else:
print(form_post.errors)
form_post = PostForm()
context = {
'allauth_login': allauth_login,
'allauth_signup': allauth_signup,
'form_post': form_post
}
return render(request, 'post.html', context)
else:
return HttpResponseRedirect("/accounts/signup/")
html
...
<form method="post" action="" enctype="multipart/form-data">{% csrf_token %}
<div class="submitContainer">
<div class="article_title_div">
{{ form_post.title|add_class:"article_title" }}
</div>
<div>
</div>
{{ form_post.category }}
</div>
<div class="submitButton">
<button class="submitArticleSubmit" type="submit">Post</button>
</div>
</form>
...
Any idea why I'm getting this error?
The reason for this, is because you're overriding the default model field. Both content and title.
Although, content can be nullable when stored in your database, it is required by your form (content = forms.CharField(widget=PagedownWidget)).
Change to content = forms.CharField(widget=PagedownWidget, required=False) to make it optional on form submission.

Update only ForeignKey field in Django form

I try to update a ForeignKey field of a model in django form. I want a user not to write his name into a input field as an author of the article that he wrote but his idmust be saved in the field in Article model. In my html-form I display only a button with hidden input. But in my views.py I write that the form should take user.id and put it in the 'article_author' field.
Unfortunately, I've got no updates into table. What am I doing wrong?
my model:
class Article(models.Model):
article_pub_date = models.DateField(default=None,null=True,verbose_name="Дата публикации")
article_title = models.CharField(max_length=70, verbose_name="Заголовок", null=True)
article_text = models.TextField(verbose_name="Текст", null=True)
article_author = models.ForeignKey(User, verbose_name='Автор', blank=True, null=True)
my views.py
def article_detail(request, article_id):
user = request.user
article = get_object_or_404(Article, pk=article_id)
author_form = ArticleForm(request.POST or None, instance=article, initial={'article_author': user.id})
if author_form.is_valid():
author_form.save()
else:
return redirect('/')
my forms.py
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ('article_author',)
widgets = {'article_author': forms.HiddenInput()}
and my template:
<form method="POST" action="">
{% csrf_token %}
{{ author_form.as_p }}
<input type="submit" value="BIND" class="btn">
</form>
Try one of the following:
if author_form.is_valid():
article = author_form.save(commit=False)
article.article_author = user
# article.article_author_id = user.id #w ill work as well
article.save()
else:
return redirect('/')
or in the form instantiation:
initial={'article_author_id': user.id}

Django: ModelForms: ImageField is always empty and rejected by ModelForm

I created a form based on several ModelForm elements. All fields work fine excluding the
ImageField. Due to the missing ImageField form.is_valid() always returns False - even though I pass request.FILES to form.
Why the form with the ImageField is always invalid / empty?
Forms
class UserProfileForm2(forms.ModelForm):
class Meta:
model = models.UserProfile
fields = ['description', 'picture']
class LocationForm(forms.ModelForm):
class Meta:
model = models.Location
fields = ['city', 'state', 'country']
class UserForm(forms.ModelForm):
class Meta:
model = registration_models.User
fields = ['first_name', 'last_name']
Models
class Location(models.Model):
city = models.CharField(max_length=100)
state = models.CharField(max_length=100)
country = models.CharField(max_length=100)
def __unicode__(self):
return ' - '.join([self.city, self.state, self.country])
class UserProfile(models.Model):
authenticationuser = fields.AutoOneToOneField(AuthUser)
description = models.TextField()
picture = models.ImageField(upload_to='uploaded_files/', null=True)
location = models.ForeignKey(Location, null=True)
appear_in_public_ranking = models.BooleanField(default=True)
def __unicode__(self):
return self.authenticationuser.username
View
#login_required
def changeprofile(request):
form = None
# user posted his new profile settings
if request.method == 'POST':
user_form = myforms.UserForm(request.POST)
user_profile_form = myforms.UserProfileForm2(request.POST, request.FILES)
location_form = myforms.LocationForm(request.POST)
forms_are_invalid = not (user_form.is_valid() and user_profile_form.is_valid() and not location_form.is_valid())
if forms_are_invalid:
forms = {'user_form':user_form,
'user_profile_form':user_profile_form,
'location_form':location_form}
return shortcuts.render(request, 'changeprofile.html', forms)
location_form.save()
user_form.save()
user_profile_form.save()
return HttpResponseRedirect('/profile')
else:
forms = {'user_form':user_form,
'user_profile_form':user_profile_form,
'location_form':location_form}
return shortcuts.render(request, 'changeprofile.html', forms)
Template
<form action="{% url 'changeprofile' %}" method="post">
{% csrf_token %}
{{ user_form }}
{{ location_form }}
{{ user_profile_form }}
<input type="submit" value="Submit" />
</form>
If your form contains file input then you must set enctype in your form as:
<form action="{% url 'changeprofile' %}" method="post" enctype="multipart/form-data">
Otherwise request.FILES will always be empty.

Categories