How do I connect forms to models in Django? - python

I've just started learning Django, and I have questions regarding forms and models.
So what I'm trying to create, in simplified feature, is a user inputs his/her basic information--phone #, instagram account, facebook account, and so on--then the data is stored in database and show up dynamically to the user. Just like social media. But I'm having confusion with forms and models.
What I first did was create forms, like below (forms.py) :
from django import forms
from django.contrib.auth.models import User
class InputUserInfo(forms.Form):
phone = forms.CharField(max_length=20)
instagram = forms.CharField(max_length=20)
facebook = forms.CharField(max_length=20)
# and so on. Don't mind about which field to use.
then I have my views.py file, written as below:
from django.shortcuts import render, redirect
from .forms import InputUserInfo
def inputuserinfo(response):
if response.method == "POST":
form = InputUserInfo(response.POST)
if form.is_valid:
form.save()
return redirect('home')
else:
form = InputUserInfo()
return render(response, 'inputuserinfo.html', {'form' : form }
then I have my inputuserinfo.html file, like below:
{% extends 'base.html' %}
{% block content %}
<form method="post" action='/inputuserinfo/'>
{% csrf_token %}
{{form}}
<button type='submit'>Done</button>
</form>
{% endblock%}
Now the problem is, I don't know what to do with my models.py. I don't know which code to write in models.py to store the input data into my database.
I would very much appreciate your help guys. :)

it looks like you left out the ModelForm. Is there any reason you arent using Class Based Views. This would be much easier?
Your ModelForm will end up looking something like this
class InputUserForm(forms.ModelForm):
'''user form to create the user profile'''
class Meta:
model = InputUserInfo
fields = '__all__'

In Django, a model is an interface to a particular database. It will create and issue SQL queries for you.
A form is an interface to HTTP "GET" and "POST." It can generate the HTML to insert into a form-tag (but do not provide the tag itself), and they can interpret the data that is presented to the host from such a form. Instead of monkeying around with the HTML data yourself, you let the Form object do the heavy lifting, both coming and going.
Django provides many convenience shortcuts, such as ModelForm, which is a Form that can be based on the content of a Model. It will "quickly produce an acceptable-looking form" when you are in a hurry ... as you often are. And it can do things like save() directly because it knows what model you want to save the data to.

Related

How can I create a submit form in Django with a dropping down list?

I am just starting to work with Django and I have some problems with forms and dropping lists.
I have a model with two attributes, and I want to display one of the attributes in a dropping down list (this one will be unchangeable) and another one in a text field (this one will be changeable). Also, I have a submit button, so I want to change a second attribute in a text field and by pressing on the button. How can I do this? What would some examples be?
As you are starting to work with Django, you might or might not know about how Django handle forms.
In Django, forms can be handled in two ways:
User-created and managed forms (without any form class)
Class-managed forms (connected to Django models)
Documentation form Django Forms
Now let’s talk about the first type of forms (where you create your HTML form and manage the request sent to server):
These forms are simple to make and when there are only a few and are only suggested when you have a very small amount of inputs (I would say four or fewer inputs).
Here is a simple example of subscription of a newsletter with an email example.
<form id='sub-form' method="POST">
{% csrf_token %}
<div>
<input type="email" name="sub_email">
</div>
<input class="button" value="Subscribe" type="submit" id="subbutton">
</form>
So a very important thing to look at here is {% csrf_token %}, about which you can read more about here and about how it works and prevents cross-site request forgery. This token will be required when you make a request to Django server with any post request and data.
In this subscription form you see one <input> with name="sub_email". Take note of this as we will use this to get this value on the server as this is the key to its value, and then a simple Submit Button.
When you press Submit on a page let’s say url = "http://BASE_URL/home" you will receive a POST request on the view that handles that URL.
So now coming to the view.py, let’s say you only allow registered users to subscribe then the view will go something like this (assuming you are not expecting any other request from the home URL).
def home(request):
user=request.user
if request.method == "POST":
if user.is_authenticated:
email = request.POST['sub_email'] #Using name of input
#Logic to save this email
return HttpResponse("You are Subscribed",status=200)
else:
return HttpReposnse("You are not Authenticated",status=401)
else:
return render(request,"home.html")
Now as you are the expert of simple forms, let’s work with Django class-based forms.
These views are a little work when you have very few inputs, but they are a great help in manageability and when you have to work with large number of inputs.
You will request these Class Based Forms as in your question you are trying to send an instance of a model from your Models.py to a form to user.
I have a model of Posts that can be used for this example:
class Post(models.Model):
postTitle = models.CharField(max_length = 90,null=True)
subTitle = models.CharField(max_length = 160,null=True)
location = models.CharField(max_length = 3,default = 'IN',null=True)
Now according to your question, you are trying to let the user change one attribute, let’s say postTitle and for location you are not letting the user select one of the countries which is preselected and for your post.
Now we have to create a form for this. Forms in class based are created in Forms.py. If you don't have forms.py then you can create one right along models.py and views.py.
Now for the form, I would like to edit some existing data as you are saying one of the attributes (Fields) is fixed and another editable, but you get the value from the model.
class PostEditForm(ModelForm):
location = forms.CharField(label='Country ',widget=forms.Select(attrs={'class': 'Classes_HERE','placeholder':' Select a Country','disabled':'disabled'} ,choices=country_list),required=True)
class Meta:
model = Post
fields= ['postTitle','subTitle','location']
labels = {
'postTitle':'Title',
'subTitle':'Sub-Title',
}
widgets = {
'postTitle': forms.TextInput(attrs={'class': 'mention_class_here','placeholder':' Add Title'}),
'subTitle': forms.TextInput(attrs={'class': 'mention_class_here','placeholder':' Add Sub-Title'})
}
Attributes can be mentioned in forms fields the way I have mentioned them in the above example. I used disabled="disabled" to disable (not editable) location field and used forms.Select to make it drop down.
You might also see that I gave the location field a list to choose from. This is how you can create a list of your items. It's been quite some time when I wrote this, so there might be errors or it may not work for you, so just make sure you are referring to the current documentation and searching Stack Overflow for answers.
country_list = [
('', 'Select a Country'),
("AF", "Afghanistan"),
("AX", "Aland Islands"),
("AL", "Albania"),
("DZ", "Algeria"),
("AS", "American Samoa"),
("AD", "Andorra"),
("AO", "Angola"),
("AI", "Anguilla"),
("AQ", "Antarctica"),
("AG", "Antigua And Barbuda"),
("AR", "Argentina"),
("AM", "Armenia"),
("AW", "Aruba"),
.
.
.
Now this form can be passed as context in a view to an HTML page.
def editPost(request,post_id):
user=request.user
post = get_object_or_404(Post,id=post_id) #Getting the instance of Post
if user.is_authenticated:
formPost = PostEditForm(request.POST or None,instance=post)
if request.method=='POST':
if formPost.is_valid():
savedPost=formPost.save()
else:
return render(request,'postEdit.html',{'formPost':formPost})
else:
return HttpResponse("Not Authorized",status:401)
Now your HTML file postEdit.html should look something like this:
<form id="post-form" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div>
{{formPost}}
</div>
</form>
That is it and adding a submit button in the same form, you can now edit your instance of post that you passed along with this {{formPost}}. Combine your logic wherever you think needs a change to fit in what you want to do.
By no means I am saying all this code is in working condition, but it is shown only to illustrate the flow and working.

I want to use the if statement based on the existence of a web page

So basically i have a complicated scenario. I am current using Django to build a website and i have current made two apps. Both apps have almost identical fields. The field I would want to focus on though is the Information field(which they both have and which i have auto generated with the help of the Wikipedia model)
So the case here is that I want to create an if and else statement in the html in such a way that if the page i am hyperlinking to exists it would go to the link dealing with DetailView but if it doesnt exist I would redirected to the Create View
I should also note that the two apps have their names linked with the help of the foreign key but when i try to open information links using the same name , they gave me different pks
I dont feel like i explained my problem well enough but I hope someone can understand what i mean
UPDATE
ok I create the get function using
def get(self, request, *args, **kwargs):
try:
self.object = self.get_object()
except Http404:
return redirect('/create/')
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
but i dont know how to use the CreateView fuction i created instead of the link i put
This is the Detail View Html
{%extends "home.html"%}
{%block head_title%} {{block.super}}{%endblock head_title%}
{% block content%}
<!-- verify authentication -->
{% if request.user.is_authenticated%}
<h3>{{object.title}}</h3><br/>
{% endif %}
<ul type="disc">
<div class="container">
<li><b>Artist: </b>{{object.Summary}}</li>
<li><b>Genre: </b>{{object.Genre}}</li>
<li><b>Bio: </b><br>{{object.Bio}}</li>
EDIT
</div>
</ul>
{%endif%}
{% endblock %}
This is my model
from django.db import models
from django.conf import settings
from Blog.models import MainPage
from django.urls.base import reverse
from Blog.Retrieve import retriever
from django.db.models.signals import pre_save,post_save
import InfoPedia
class InfoPedia(models.Model):
user =models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
Name =models.ForeignKey(MainPage,on_delete=models.CASCADE)
Location =models.CharField(max_length= 50,null=True,blank=True)
Information =models.TextField(null=True,blank=True)
TrackListing=models.TextField(null=True,blank=True)
Published=models.BooleanField(default=True)
Timestamp=models.DateTimeField(auto_now=True)
Updated=models.DateTimeField(auto_now=True)
def get_absolute_url(self):
# return f"/Blog/{self.slug}"
return reverse('InfoPedia:DetailView', kwargs={"pk":self.pk})
class Meta:
ordering=["-Updated","-Timestamp"] #orranges in order of updated
def get_tracklist(self):
return self.TrackListing.split(",")
def Information_create_pre_save( instance, sender, **kwargs):
instance.Information=retriever(instance.Name)
def rl_post_save_reciever(sender, instance,created,*args,**kwargs):
print("saved")
print(instance.Timestamp)
pre_save.connect(Information_create_pre_save, sender=InfoPedia)
post_save.connect(rl_post_save_reciever, sender=InfoPedia)
An alternative - rather than checking the if/else in the HTML, just make all the links to the DetailView URL.
Then, in the get() handler for the DetailView, you perform a queryset lookup for the object. If no object is found, then instead of displaying the DetailView HTML, return to the user a 302 redirect (i.e. a temporary redirect) to the CreateView for that object. So all your if/else logic is in the view function or class, instead of HTML.

django-forms-builder. How do I update a form?

I am using django-forms-builder in my project and there is just one thing i cant get my head around. How do i set up an update form to edit a filled out form?
Here is my attempt at making an update form for django-forms-builder
urls.py
url('forms/update/(?P<pk>\d+)/$', FormUpdateView.as_view(),
name='form-update'),
views.py
class FormUpdateView(UpdateView):
model = FieldEntry
template_name = 'form/update_form.html'
form_class = FormForForm
success_url = '/assessments/all/'
update-form.py
{% render_built_form id=form_instance.id %}
I haven't used this software yet but it could fill a spot in my arsenal so I took a stab at it. I'm not using CBV because I'm still just poking around. This is the get part only, I can expand on how to handle the post part (and preferably do it with CBV) on the weekend. It's relatively straightforward to implement post with view functions (if request.METHOD == "POST":#update the row). The render is of course just plain raw HTML but forms_builder doesn't offer any styling input. You probably want to tack the user onto the FormEntry, I don't have a good idea about authorization yet. I'll give it some thought and amend the answer.
views.py
from forms_builder.forms.models import Form
def get_form(request, slug, pk):
form_obj = Form.objects.get(slug=slug)
form_instance = form_obj.entries.get(pk=pk)
form = FormForForm(form=form_obj, instance=form_instance, context=request)
return render_to_response('update_form.html', {'form':form_instance.form, 'request':request})
templates/update_form.html
{{ form.as_p }}

How to save POST DATA in django?

Here is an example having:
form with three fields i.e
from django import forms
from models import Article
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ('title','body','thumbnail')
view
from django.shortcuts import render_to_response
from uploadfiles.models import Article
from django.http import HttpResponse, HttpResponseRedirect
from forms import ArticleForm
from django.core.context_processors import csrf
def create (request):
if request.POST:
form = ArticleForm(request.POST, request.FILES)
if form.is_valid():
return HttpResponseRedirect('/all')
else:
form = ArticleForm()
args= {}
args.update(csrf(request))
args['form'] = form
return render_to_response('create_article.html', args)
models
from django.db import models
from time import time
def get_upload_file_name(request):
return "uploaded_files/%s_%s" %(str(time()).replace('.','-'))
class Article(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
thumbnail = models.FileField(upload_to = get_upload_file_name)
def __unicode__(self):
return self.title
html page
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<form action="/create" method="post" enctype="multipart/form-data">{% csrf_token %}
{{form.as_ul}}
<input type="submit" name="submit" value="create"/>
</form>
</body>
</html>
MY QUESTIONS ARE:
1)What is Meta class, why we use this?
2)What this line means args.update(csrf(request))?
3)As in forms page redirects to /create .. as this can be any page! so how to save posted data now. as this returns the submitted data to html page.
My question can be so basic or simple but these are the things that are not clear to me and for that reason i am posting this here! and it can be duplicate so if you don't like it please don't mark negatively.:)
1)
Metaclass is a 'thing' that creates classes.
You define classes in order to create objects, right?
But we learned that Python classes are objects.
Well, metaclasses are what create these objects. They are the classes' classes, you can picture them this way:
MyClass = MetaClass()
MyObject = MyClass()
You've seen that type lets you do something like this:
MyClass = type('MyClass', (), {})
It's because the function type is in fact a metaclass. type is the metaclass Python uses to create all classes behind the scenes.
Now you wonder why the heck is it written in lowercase, and not Type?
Well, I guess it's a matter of consistency with str, the class that creates strings objects, and int the class that creates integer objects. type is just the class that creates class objects.
for more help see this MetaClasses
2)
Cross-site request forgery (CSRF)
A Cross-site request forgery hole is when a malicious site can cause a visitor's browser to make a request to your server that causes a change on the server. The server thinks that because the request comes with the user's cookies, the user wanted to submit that form.
Depending on which forms on your site are vulnerable, an attacker might be able to do the following to your victims:
Log the victim out of your site. (On some sites, "Log out" is a link
rather than a button!)
Post a comment on your site using the victim's login.
Transfer funds to another user's account.
To PREVENT this we use this update(csrf(request))
for more information see this ABOUT CSRF and this CSRF django
3)
/create is a action of your present controller if you see your controller page there you can see this create function in that function you'll get your POST data
1) Meta = class metadata. This is where you define the different metadata elements of the model
2) CSRF = this is the token that prevents cross-site attacks. It is a hidden field/attribute that is added to your request to make sure someone cannot hack your site
3) The submitted data goes to the view and there your can save your data. Or I misunderstood your question....

how to make dynamically generated forms with one to many relationships in django

i am trying to write a quiz system to learn django where users can add quizes to the system.
my models look like
from google.appengine.ext import db
class Quiz(db.Model):
title=db.StringProperty(required=True)
created_by=db.UserProperty()
date_created=db.DateTimeProperty(auto_now_add=True)
class Question(db.Model):
question=db.StringProperty(required=True)
answer_1=db.StringProperty(required=True)
answer_2=db.StringProperty(required=True)
answer_3=db.StringProperty(required=True)
correct_answer=db.StringProperty(choices=['1','2','3','4'])
quiz=db.ReferenceProperty(Quiz)
my question is how do create Form+views+templates to present user with a page to create quizes
so far i have come up with this.
Views:
from google.appengine.ext.db.djangoforms import ModelForm
from django.shortcuts import render_to_response
from models import Question,Quiz
from django.newforms import Form
def create_quiz(request):
return render_to_response('index.html',{'xquestion':QuestionForm(),'xquiz':QuizForm()})
class QuestionForm(ModelForm):
class Meta:
model=Question
exclude=['quiz']
class QuizForm(ModelForm):
class Meta:
model=Quiz
exclude=['created_by']
template(index.html)
Please Enter the Questions
<form action="" method='post'>
{{xquiz.as_table}}
{{xquestion.as_table}}
<input type='submit'>
</form>
How can i have multiple Questions in the quiz form?
so far so good, as of now you should be having a working view with the forms rendered, if there are no errors.
now you just need to handle the post data in create_quiz view
if request.method == 'POST':
xquiz = QuizForm(request.POST)
quiz_instance = xquiz.save(commit=False)
quiz_instance.created_by = request.user
quiz_instance.save()
xquestion = QuestionForm(request.POST)
question_instance = xquestion.save(commit=False)
question_instance.quiz = quiz_instance
question_instance.save()
update: if you are looking for multiple question forms then you need to look at formsets, http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#id1

Categories

Resources