first thing first I'm sorry for my bad english. I hope so u can understand me easily.
I'm trying to make a blog with django but there's a place I can't solve. I used unique slug field instead of id for url, whenever I want to update the data I get the UNIQUE constraint failed: post_post.url_text error (url_text is slugfield variable name). Here is the my model,
and the Form looks like this,
At first I followed a way to update the data here:
#login_required(login_url='login')
def post_update(request, url_text=None):
post = get_object_or_404(Post, url_text=url_text)
form = PostWrite(request.POST or None, instance=post)
if form.is_valid():
post_author = request.user
post_title = form.cleaned_data.get('post_title')
post_content = form.cleaned_data.get('post_content')
post_tags = form.cleaned_data.get('tags')
post = Post(post_author=post_author, post_title=post_title, post_content=post_content, tags=post_tags)
post.save()
context = {
'post': post,
'form': form,
}
return render(request, 'post/re_write.html', context)
and I got the error I mentioned at the beginning of the post. Then I found a solution like this in the forums,
if form.is_valid():
form.save()
This time it does not give any error but does not update the data. Despite hours of research, for some reason I could not find a tangible solution. I wanted to ask you esteemed coders as a last resort and I look forward to your help.
The issue is that you're creating a new post with the following code while this view appears to be an update:
post = Post(post_author=post_author, post_title=post_title, post_content=post_content, tags=post_tags)
post.save()
Instead, you should utilize the modelform you're already using to save the changes to the instance:
if form.is_valid():
post = form.save()
I'm guessing maybe because you weren't capturing the post from form.save() the rendered template appeared to not have the data updated because the instance passed into the template was from before the changes.
Other issue:
You're overriding the save method, but not always calling super().save. This means that you're only saving the post when the url_text property is not set. Instead always call super().save
def save(self, *args, **kwargs):
if ...
# other stuff
super().save(*args, **kwargs)
Related
My creation view redirect to blog main page well after creation but
i can't find any post's been created in the posts or admin page posts, can anyone help please
here is my view
#login_required
def add_post(request):
if request.method == 'POST':
post_form = PostForm(request.POST, request.FILES, instance=request.user)
snippet_form = SnippetForm(request.POST)
if post_form.is_valid() and snippet_form.is_valid():
post = post_form.save(commit=False)
snpt = snippet_form.save(commit=False)
post.creator = request.user
snpt.id = post.id
post.save() and snpt.save()
return redirect('blog:index')
else:
post_form = PostForm()
snippet_form = SnippetForm()
return render(request, 'blog/add_post.html', {'post': post_form, 'snpt': snippet_form})
what's wrong in this view cause i been able to save new post from admin add new post but from client it doesn't save anything
Do I need to use model create() method here or what?
*Any required snippet i will provide but the problem is in this snippet
any help is really appreciable
Update:
my Post model
class Post(models.Model):
...
creator = models.OneToOneField(settings.AUTH_USER_MODEL...
snippet = models.OneToOneField(Snippet,...
...
post.save() and snpt.save()
should be:
post.save()
snpt.save()
I suspect you were thinking (by using the keyword and) that you want to ensure both models are saved at the same time, but you are actually asking Python to compare the return results of the two functions to see if they are both True; this is breaking your code (as save() returns None, only your first save() is running as Python will not even execute the second as there's no way they can both be True when the first has already returned Falsey).
You may find this question useful in your scenario.
in case anyone interested to know
Firstly
As The relation between Post model and Snippet model is OneToOne, following line
snpt.id = post.id
need to be removed
would violates the unique pk constraint, if you changed the relation to foreign key that would add another instance of snippet with another pk
you can remove it or assign instead
post.snippet = snpt
Secondly
No need for commit=False in snpt_form as it already an instance of post_form and i didn't want to change anything else except the form fields
Thirdly
Either put
creator=request.user
instead of
instance=request.user
inside the post_form
or remove it and leave
post.creator = request.user
forth
Also as #bigkeefer mentioned but this is secondly arises after solving the main problem
the short circuit python precedence rule causing this line to fail
post.save() and snpt.save()
instead put
post.save()
snpt.save()
Good evening, I am trying to get the id of my model Note that is sent by means of a form, but when I put form.id it tells me that id is not defined, try to get it through the user session but it says that it was not found.
def add_book(request):
template_name = 'books/create_note.html'
book = get_or_create_book(request)
form = NoteForm(request.POST)
if request.method == 'POST' and form.is_valid():
note = Note.objects.get(pk=form.pk)
book.notes.add(note)
form.save()
return redirect('books:book')
return render(request, template_name, {
'form': form,
})
and this is the form
class NoteForm(ModelForm):
class Meta:
model = Note
fields = (
'title', 'nota'
)
labels = {
'title': 'Titulo',
'nota': 'Nota',
}
try creating an instance of my Note model but when it comes time to create it tells me it is empty.
I'm new to Django, but I had similar problems that frustrate me. not sure if I have the hang of it yet, but I think what might be happening is that when you first go to the page there is a GET request, so your if statement misses it. It then it reaches the last line and goes to template_name without the form being assigned so the form never gets a Post requests. In the terminal you can see the POST and GET requests. I ended up also printing out request.method a lot before and after if statements just to help trace what was going on.
else:
form=NoteForm()
Then your return render(request,....
making sure it goes back to the correct html page.
The thing that worked for me eventually was something like
def Search_Page(request):
if request.method=='POST':
form = Search_Page_Form(request.POST)
if form.is_valid():
do some stuff and save the change to the model
return(redirect('mainapp:Evaluate_Page'))
else:
form=Search_Page_Form()
return render(request, 'mainapp/Search_Page.html', {'form': form})
I am trying to get a custom UpdateView to work in Python/Django. I believe that the code that I've writtten is mostly correct, as it seems to be returning the proper Primary Key ID in the URL when I click on the associated dropdown. The problem is that I am not seeing any of the data associated with this record on the screen in update mode. The screen appears in edit mode, but there is no data. I suspect the problem is perhaps the django template in the html form? However, I have played with the form and used {{ form }} and it too returns a blank form. I've played with this all afternoon and I'm out of guesses. Here is my view:
def updating_document(request, pk):
doc = get_object_or_404(Doc, pk=pk)
form = Update_Doc_Form(request.user, request.POST)
if request.method == 'GET':
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('App:main_procedure_menu'))
else:
print("Form is invalid!")
return render(request,'Doc/update_doc.html',{'form':form })
I also have an associated form...
Form.py
class Update_Doc_Form(forms.ModelForm):
class Meta:
model = Doc
exclude = ['user']
doc_name = forms.CharField(widget=forms.TextInput)
description = forms.CharField(required=True,widget=forms.Textarea)
team = forms.CharField(widget=forms.Select)
document = forms.CharField(required=True,widget=forms.Textarea)
def __init__(self, *args, **kwargs):
super(Update_Doc_Form, self).__init__(*args, **kwargs)
self.fields['doc_name'].widget.attrs['class'] = 'name'
self.fields['description'].widget.attrs['class'] = 'description'
self.fields['team'].widget.attrs['class'] = 'choices'
self.fields['team'].empty_label = ''
I'm a newbie, but I do want to use a custom UpdateView so that I can alter some of the fields and pass user information. I feel like the code is close, just need to figure out why it's not actually populating the form with data. Thanks in advance for your help!
What a difference a day makes. Found an answer on SO this morning. Not sure how to credit the person or issue number....
The answer was to add the following line of code to my form:
user = kwargs.pop('object_user')
I also needed to add the following function to my View:
def get_form_kwargs(self):
kwargs = super(ViewName,self).get_form_kwargs()
kwargs.update({'object_user':self.request.user})
return kwargs
This question was answered originally in 2013 by Ivan ViraByan. Thanks Ivan!
I ultimately went with a standard class based UpdateView and scrapped my plans for the custom UpdateView once I was able to figure out how to use the Class Based View(UpdateView) and "pop" off the user information when passing it to the form based on Ivan ViraByan's answer in 2013.
The code above allows you to get the user but not pass it to the ModelForm so that you don't get the unexpected user error.
Trying to create a form where you can sign up as a user, and add yourself to one or more categories. Getting an error while doing it:
TypeError at /users/add-user/
'categories' is an invalid keyword argument for this function
Here's my forms.py:
class AddUser(forms.Form):
name = forms.CharField()
title = forms.CharField()
website = forms.CharField(required=False)
email = forms.EmailField()
phone = forms.CharField(required=False)
company = forms.ModelChoiceField(queryset=Company.objects.all())
categories = forms.ModelMultipleChoiceField(queryset=Category.objects.all())
The last line is the one I'm having trouble with.
Here's my views.py:
def add_user(request):
if request.method == 'POST':
form = AddUser(request.POST)
if form.is_valid():
cd = form.cleaned_data
try:
p = User.objects.get(email=cd['email'])
error = "There's already a user with that e-mail adress registered. Maybe he/she is already here?"
return render_to_response('users/add_user.html', {'form': form, 'error': error}, context_instance=RequestContext(request))
except User.DoesNotExist:
p = User(name=cd['name'], title=cd['title'], website=cd['website'], email=cd['email'], phone=cd['phone'], company=cd['company'], categories=cd['categories'])
p.save()
return HttpResponseRedirect('../thanks/')
else:
form = AddUser(request.POST)
error = "You can't really submit empty forms. Try adding something useful :)"
return render_to_response('users/add_user.html', {'form': form}, context_instance=RequestContext(request))
If anyone has any suggestions to the problem (or even suggestions in general to improve my code), I'd be glad! I'm a beginner to Django and all help is appreciated.
Your problem lies here:
p = User(name=cd['name'], title=cd['title'], website=cd['website'], email=cd['email'], phone=cd['phone'], company=cd['company'], categories=cd['categories'])
The problem is that the User model doesn't include a categories field, just as it doesn't include a website or company. See the list of the available fields.
There's different approaches to handling additional data in combination with Django's auth system. Sublcassing the User class or adding a model with additional info and a one-to-one field to the User come to mind. The latter option seems to be suggested, so I'd suggest going down that path.
A bit of a nit pick, but you did ask for other suggestions. This bit:
else:
form = AddUser(request.POST)
should (IMO) be changed to this:
else:
form = AddUser()
There's no need to use request.POST for a GET request. I've never tried that but I'm guessing it will work, you just get an empty set. So not an error but possibly a source of confusion.
Your error message is also not being used. A GET on the page is not an error at all in this case, it is just how the page is initially displayed.
This may be a dumb question, but I'm a bit unsure if it's safe to manually set the cleaned_data. The docs says:
Once is_valid() returns True, you can process the form submission
safe in the knowledge that it conforms to the validation rules defined
by your form. While you could access request.POST directly at this
point, it is better to access form.cleaned_data. This data has not
only been validated but will also be converted in to the relevant
Python types for you.
For more context, say we have a modelform which has several fields such as a book's title, book's author, and a field which asks for a url.
The form conditions are: if the url field is empty, the user must provide the title and author. If the url field is given and nothing else, I would parse the html from the given url and extract the title and author automatically for the user.
In the case where I automatically grab the title and author from the url, what would be the best way to handle saving this data to the model, since the form would return an empty cleaned_data for author and title? I made sure the data parsed will conform to the validate rules I have in the model, but setting cleaned_data like this seems suspicious.
In modelform class:
def save(self, commit = True, *args, **kwargs):
parsed_title = ... # String returned by my html parsing function
parsed_author = ... # String returned by my html parsing function
self.cleaned_data['title'] = parsed_title
self.cleaned_data['author'] = parsed_author
EDIT:
Thanks, I made it like so:
def save(self, commit=True, *args, **kwargs):
instance = super(BookInfoForm, self).save(commit=commit, *args, **kwargs)
....
instance.title = parsed_title
instance.author = parsed_author
return instance
This is a bit off topic since you've already answered the original question, but the above code breaks some other part. Instead of saving the compiled info to http://..../media/books/<id> where <id> is the book id, it saves it to http://..../media/books/None.
I have a add/edit function in my views.py that handles adding and editing:
def insert_or_modify(request, id=None):
if id is not None:
book = BookModel.objects.get(pk=id)
else:
book = BookModel()
if request.method == 'POST':
form = BookInfoForm(request.POST, instance=book)
if form.is_valid():
form.save()
....
return render_to_response(...)
Is there a way to make sure the id is present so that I won't get id=None? I guess more specifically, in the save() in the modelform, is there a way to create a new instance with an id if instance.id = None? Although I thought calling super(ModelForm, self).save(...) would do that for me?
Thanks again!
In the case you present, your intention isn't setting the cleaned_data, but the model data. Therefore, instead of setting cleaned_data in the save method, just set the attributes of self.instance and then save it.
About setting cleaned_data manually, I don't think it's necessarily wrong, it may make sense to do it in the form's clean method for some cross-field validation, although it's not a common case.