Django for Designers/CRUD: Difference between revisions

Content added Content deleted
imported>Paulproteus
No edit summary
imported>Paulproteus
(→‎Part 4: CRUD: Add clarity as to which files we are editing)
Line 19: Line 19:
==== Making a basic, working ModelForm ====
==== Making a basic, working ModelForm ====


Inside our bookmarks app folder, let's make a file named forms.py. Edit it to import ModelForm and our models, then create a BookmarkForm class:
Inside our bookmarks app folder, let's make a file named forms.py. Edit your new ''bookmarks/forms.py'' file to import ModelForm and our models, then create a BookmarkForm class:


<source lang="python">
<source lang="python">
Line 35: Line 35:
Let's add our BookmarkForm to our views and templates!
Let's add our BookmarkForm to our views and templates!


Edit views.py:
Edit ''bookmarks/views.py'':


<source lang="python">
<source lang="python">
Line 53: Line 53:
</source>
</source>


Then edit index.html to take advantage of the new form object in our context:
Then edit ''index.html'' to take advantage of the new form object in our context. Leave most of it intact; just change the ''bookmark_widget'' block.


<source lang="html4strict">
<source lang="html4strict">
Line 71: Line 71:
The .as_p call makes the form put each field inside a paragraph tag. There are similar methods for making the form appear inside a table or inside divs.
The .as_p call makes the form put each field inside a paragraph tag. There are similar methods for making the form appear inside a table or inside divs.


The other thing we need to do here is add a CSRF token to our form, since that isn't included by default. A CSRF token is a special bit of code, built into Django, that protects your site from Cross Site Request Forgeries. It tells Django that a POST from this form really came from this form, not some other malicious site. Django makes this super easy:
The other thing we need to do here is add a CSRF token to our form, since that isn't included by default. A CSRF token is a special bit of code, built into Django, that protects your site from Cross Site Request Forgeries. It tells Django that a POST from this form really came from this form, not some other malicious site. In ''index.html'', keep editing the ''bookmark_widget'' block; Django makes this super easy.


<source lang="html4strict">
<source lang="html4strict">
Line 94: Line 94:
Spin up http://localhost:8000/, login if you're not logged in already, take a look at your beautiful new form!
Spin up http://localhost:8000/, login if you're not logged in already, take a look at your beautiful new form!


Right now, if you try to submit bookmarks with this form, it'll just reload the page. That's because we haven't told the view to do anything with any form data that gets sent to it! Let's edit our index view in views.py to make it do something with this form's data:
Right now, if you try to submit bookmarks with this form, it'll just reload the page. That's because we haven't told the view to do anything with any form data that gets sent to it! Let's edit ''views.py'' and change just the ''index'' function to make it do something with this form's data:


<source lang="python">
<source lang="python">
Line 121: Line 121:
So our form works, but it doesn't look the way we originally expected. For one, there's a dropdown asking us to specify the bookmark's author. For another, we're missing a field for tags. We'll need to customize our BookmarkForm if we want it to look the way we want.
So our form works, but it doesn't look the way we originally expected. For one, there's a dropdown asking us to specify the bookmark's author. For another, we're missing a field for tags. We'll need to customize our BookmarkForm if we want it to look the way we want.


First, let's make the default author always the currently logged-in user. In views.py:
First, let's make the default author always the currently logged-in user. Edit just the ''index'' function in ''views.py'':


<source lang="python">
<source lang="python">
Line 141: Line 141:
Now if you reload, thanks to the initial data we provided our BookmarkForm, you'll see that your account is chosen by default in the author dropdown.
Now if you reload, thanks to the initial data we provided our BookmarkForm, you'll see that your account is chosen by default in the author dropdown.


Then let's hide the author field from the user. We'll do this in our ModelForm specification in forms.py:
Then let's hide the author field from the user. We'll do this by editing our ModelForm specification in ''forms.py'':


<source lang="python">
<source lang="python">
Line 158: Line 158:
Now if you restart your server, you'll see the author field appears to be gone! Instead of the default text input widget, we told Django to use a hidden field for the author, so we no longer see it.
Now if you restart your server, you'll see the author field appears to be gone! Instead of the default text input widget, we told Django to use a hidden field for the author, so we no longer see it.


Since titles aren't even required, the URL is the most important piece of data for a bookmark. Let's change the order of the fields, so the URL comes first. Again in forms.py
Since titles aren't even required, the URL is the most important piece of data for a bookmark. Let's change the order of the fields, so the URL comes first. Again, update the''BookmarkForm'' in ''forms.py'':


<source lang="python">
<source lang="python">
Line 174: Line 174:
==== Save tags with our form ====
==== Save tags with our form ====


Finally, let's add a tags field:
Finally, let's add a tags field. Edit ''forms.py'' again and continue to change the ''BookmarkForm'':


<source lang="python">
<source lang="python">
Line 187: Line 187:
</source>
</source>


Note that since tags isn't a field in the Bookmark model, we're going to need to make sure it gets saved separately. For that, let's go back to views.py:
Note that since tags isn't a field in the Bookmark model, we're going to need to make sure it gets saved separately. For that, let's go back to ''views.py''. First, toward the top,


<source lang="python">
<source lang="python">
Line 216: Line 216:
context = {
context = {
'bookmarks': bookmarks,
'bookmarks': bookmarks,
'form': form
'form': form,
}
}
return render(request, 'index.html', context)
return render(request, 'index.html', context)
Line 237: Line 237:
(Warning: we'll be writing some Javascript in this section.)
(Warning: we'll be writing some Javascript in this section.)


First, we need to tell our templates to import some Javascript files. In base.html:
First, we need to tell our templates to import some Javascript files. Edit ''base.html'':


<source lang="html4strict">
<source lang="html4strict">
Line 251: Line 251:
</source>
</source>


Right now, our static/js/script.js is blank. Let's write a quick and dirty JS function that gets triggered when someone submits the bookmarks form:
Right now, our ''static/js/script.js'' is blank. Let's write a quick and dirty JS function that gets triggered when someone submits the bookmarks form:


<source lang="javascript">
<source lang="javascript">
Line 285: Line 285:
For the sake of speed and simplicity, we'll go with the latter. First, though, we need to refactor our templates a little.
For the sake of speed and simplicity, we'll go with the latter. First, though, we need to refactor our templates a little.


Create a new template called bookmark.html, and paste in the bookmark list element from index.html in there.
Create a new template called ''bookmark.html'', and paste in the bookmark list element from ''index.html'' in there.


<source lang="html4strict">
<source lang="html4strict">
Line 302: Line 302:
Note that unlike the other templates, this template doesn't inherit anything -- it's just a block of HTML with some template markup.
Note that unlike the other templates, this template doesn't inherit anything -- it's just a block of HTML with some template markup.


Then, rewrite index.html so the content block looks like this:
Then, open ''index.html''and edit just the ''content'' block so it looks like this:


<source lang="html4strict">
<source lang="html4strict">
Line 316: Line 316:
Reload the page. Nothing should have changed, in terms of how the page looks. We've just changed the structure of the templates. Using the include tag, the index template drops in the contents of bookmarks.html rendered with the values for a given bookmark, for each bookmark in the list.
Reload the page. Nothing should have changed, in terms of how the page looks. We've just changed the structure of the templates. Using the include tag, the index template drops in the contents of bookmarks.html rendered with the values for a given bookmark, for each bookmark in the list.


Now we're ready to teach our view to send back a partial bit of HTML.
Now we're ready to teach our view to send back a partial bit of HTML. Open ''views.py'' and edit just the ''index'' function to be as follows.


<source lang="python">
<source lang="python">
Line 356: Line 356:
</source>
</source>


Eek. Our index view doesn't handle the case where the request is a POST, but the form doesn't validate, and Django noticed this and returned an error. Let's fix this:
Eek. Our index view doesn't handle the case where the request is a POST, but the form doesn't validate, and Django noticed this and returned an error. Let's fix this by editing the ''index'' function in ''views.py'' again:


<source lang="python">
<source lang="python">