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....
Related
I have 2 Django forms: one, where the user uploads an article, and the second, where the user can edit a list of article words into one of three buckets (change the column value: bucket 1-3).
forms.py
class UploadForm(forms.ModelForm):
class Meta:
model = Upload
fields = ('name','last_name','docfile',)
class Doc_wordsForm(forms.ModelForm):
class Meta:
model= Doc_words
fields= ('id','word','word_type','upload',) #upload is foreign key value
After the user uploads the article, I have a function in views.py that breaks down the uploaded article into a list of words.
I want these words to be looped through and added to a database table(where each row is a word), then have the second form reference these words.
Views.py
# upload_id = (request.GET.get("id"))
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES)
if form.is_valid():
form.save()
data = request.FILES['docfile']#.read().decode('UTF-8')
words=get_keywords(data)
results=list(find_skills(words))
for word in results:
form2 = Resume_words(word = word, word_type='exclude', upload = upload_id)
form2.save()
return render(request, 'word_list.html',{
"results":results
})
else:
form = UploadForm()
return render(request, 'upload.html', {
'form':form
})
I having trouble pulling these pieces together and I'm desperate for help of any kind! I having trouble with the following steps:
I don't know how to capture the current users instance when saving to the table. I get an error in the above Views.py code.
I don't know how to have the second form reference the current user from the first form.
Please let me know if I can provide more information or clarity on anything above. Also, feel free to answer one question, or simply point me to where there is an example similar to this, any light shed is greatly appreciated.
There are many ways to get user's info in view. the most basic way (not recommended, AT ALL!) is to pass user's id to every view from every view. for example in login view you pass user's id in context:
return render(request, 'main_page.html',{
"user_id":user.id
})
and make every view get this id whether in url or query parameter.
using url:
urls.py
path('any/pk/', AnyView.as_view(), name='carrot'),
view.py
class AnyView(Views):
def get(request, pk):
user=User.objects.get(pk=pk)
def post(request, pk):
user=User.objects.get(pk=pk)
your_template.html
<!-- post request -->
<form action="{% url 'carrot' user_id %}" method="post">...</form>
<!-- get request -->
<a href={% url 'carrot' user_id %}></a>
using query parameters:
urls.py
path('any/', AnyView.as_view(), name='carrot'),
view.py
class AnyView(Views):
def get(request):
user=request.GET.get('pk', False)
if user:
user=User.objects.get(pk=pk)
def post(request):
user=request.POST.get('pk', False)
if user:
user=User.objects.get(pk=pk)
your_template.html
<!-- post request -->
<form action="{% url 'carrot' %}?pk={{ user_id }}" method="post">...</form>
<!-- get request -->
a much much better way is using django default authentication for log in, log out, permission handling and finally getting user information from request without all this unnecessary code.
view.py
class AnyView(Views):
def get(request):
user=request.user
def post(request):
user=request.user
to implement django authentication check this link:
https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Authentication
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'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.
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.
I am new to django. I made a form. I want that if the form is filled successfully then django should redirect to a success page showing the name entered in the form but no parameters should be present in the url itself.
I searched on the internet and the solution I got was to redirect to url with pk as a get parameter which fetches the data and shows in the view. But I don't want to pass any thing in the url itself. and some websites say that http can't redirect with post data.
Here's my views.py
class UserRegistrationView(CreateView):
model = UserForm
template_name = 'userregistration.html'
form_class = UserForm
success_url = 'success'
def get_success_url(self):
return reverse('success',kwargs = {'name' : self.object.firstName})
and here's the template to which I want to redirect:
<h2>Congratualations for registering {{name}} </h2>
Basically what I want is that if the person fill form mentioning his/her firstName as "xyz" then the redirected success page should say that "Congratulations for registering xyz"
You can use django sessions, which I believe installed by default in 1.8
Look here
# Set a session value:
request.session["fav_color"] = "blue"
# Get a session value -- this could be called in a different view,
# or many requests later (or both):
fav_color = request.session["fav_color"]
# Clear an item from the session:
del request.session["fav_color"]
You can pass your pk via session and extract your object in another view without affecting your url.
Make sure you clean up after yourself.
Let me know if more help needed.
One of the possible ways of passing data between views is via sessions. So, in your UserRegistrationView you need to override the form_valid method as shown below.
class UserRegsitrationView(CreateView):
def form_valid(self,form):
self.request.session['name'] = self.object.firstName
return super(UserRegistrationView,self).form_valid(form)
class SuccessView(TemplateView):
template_name = "success_template.html"
def get_context_data(self,**kwargs):
context = super(SuccessView,self).get_context_data(**kwargs)
context['name'] = self.request.session.get('name')
del self.request.session['name']
return context
One more thing that you can modify in your code is that you need not declare success_url if you are overriding get_success_url