Using Django ModelForm for one-to-many relationships - django

I'm trying to extend the Django (version 2.0) tutorial so that it uses ModelForm to create a question with a least one or two choices. I have two models Question and Choice which have a one-to-many relationship. What do I need to do to my model, form, views, and template to generate a field(s) for choice? I've seen a few posts suggesting Inline but that seems like it's only for admin pages.
polls/models.py
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
polls/forms.py
from django.forms import ModelForm
from .models import Choice, Question
class QuestionForm(ModelForm):
class Meta:
model = Question
fields = ['question_text', 'pub_date', 'choice']
polls/views.py
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.utils import timezone
from django.views import generic
from .forms import QuestionForm
from .models import Choice, Question
def create_question(request):
if request.method == 'POST':
form = QuestionForm(request.POST)
if form.is_valid():
question_text = form.cleaned_data['question_text']
pub_date = form.cleaned_data['pub_date']
question = Question(question_text=question_text, pub_date=pub_date)
question.save()
return HttpResponseRedirect(reverse('polls:index'))
else:
form = QuestionForm()
return render(request, 'polls/create-question.html', {'form': form})
polls/create-question.html
{% extends 'polls/base.html' %}
{% block scripts %}{% endblock scripts %}
{% block content %}
<div class="container">
<h1>Create question</h1>
<form action="{% url 'polls:create-question' %}" method="post">
{% csrf_token %}
{{ form }}
<input class="btn btn-lg btn-primary btn-block" type="submit" value="Create">
</form>
</div>
{% endblock content %}

To use ModelForm you should add a ManyToManyField to the Question model in order to connect choices with the certain question. For example like choices = models.ManyToManyField(Choice, on_delete=models.CASCADE).

Related

Django: How do I create a form of model A for each instance of model B

I am trying to create an app, where the user fills out forms (model A). The forms are based on variables (model B), which are defined by the admin.
The form should save the input in model A (i.e. input values) and therefore show the name/label of model B (i.e. the variable name) for each instance of B and the corresponding fields of A (the input value).
I am stuck with showing each input form separately. Technically this works, but creates a terrible user experience. How do I render all input forms for each variable on one page?
I would appreciate any help greatly!
models.py
Model A (input values):
class InputValue(models.Model):
variable = models.ForeignKey(Variable, on_delete=models.CASCADE, default="")
value_char = models.CharField(max_length=128, default="NA")
value_numeric = models.FloatField(default=0)
value_choice = models.CharField(max_length=128, default="NA")
def __str__(self):
return self.variable.var_label
Model B (variables):
class Variable(models.Model):
var_id = models.CharField(max_length=20, default="")
var_label = models.CharField(max_length=20, default="")
description = models.CharField(max_length=200, default="")
def __str__(self):
return self.var_id
For forms.py and view.py I tried something like this:
forms.py
from django import forms
from .models import InputValue
class InputForm(forms.ModelForm):
class Meta:
model = InputValue
fields = ("variable", "value_numeric")
view.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from django.forms import modelformset_factory
from .forms import InputForm
from .models import InputValue
def input_form(request):
SubmissionFormSet = modelformset_factory(InputValue, form=InputForm)
if request.method == 'POST':
formset = SubmissionFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
return HttpResponseRedirect(reverse('myapp:index'))
else:
formset = SubmissionFormSet()
return render(request, 'myapp/input_form.html', {'formset': formset})
And for the template:
input_form.html
<body>
<main class="container">
{% block content %}
<h2>Submission form</h2>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ formset.as_p }}
<input type="submit" value="Submit">
</form>
{% endblock %}
</main>
</body>

I have created a django ModelForm that is not showing up in my html template, I am trying to determine why that code is not rendering my form?

models.py
from django.db import models
# Create your models here.
class Subscriber(models.Model):
"""A subscriber Model"""
email = models.CharField(max_length=255, blank=False, null=False, help_text="Subscriber Email Address", unique=True)
full_name = models.CharField(max_length=100, blank=False, null=False, help_text="First and Last Name")
class Meta:
verbose_name = "Subscriber"
verbose_name_plural = "Subscribers"
forms.py
from django.forms import ModelForm
from .models import Subscriber
class SubscriberForm(ModelForm):
class Meta:
model = Subscriber
fields = ["email", "full_name"]
views.py
from django.shortcuts import render
from .forms import SubscriberForm
from django.http import HttpResponseRedirect
from django.contrib import messages
# Create your views here.
def subscriber(request):
if request.method == "POST":
subscriber_form = SubscriberForm(request.POST or None)
if subscriber_form.is_valid():
subscriber_form.save()
messages.success(request, "")
return HttpResponseRedirect("/")
else:
subscriber_form = SubscriberForm()
context = {
"form_subscriber": subscriber_form
}
return render(request, "subscriber/subscriber_form.html", context)
subscriber_form.html
{% block content %}
<div>
<form method="POST">
{% csrf_token %}
{{ subscriber_form.as_ul }}
<input type="submit" value="Submit">
</form>
</div>
{% endblock %}
Only my submit button is publishing, however the form is never showing up for me.
I have followed the django docs exactly and still am not getting any good results.
It should be form_subscriber not subscriber_form so:
{% block content %}
<div>
<form method="POST">
{% csrf_token %}
{{ form_subscriber.as_ul }}
<input type="submit" value="Submit">
</form>
</div>
{% endblock %}
Additionally, I'd recommend you to only use SubscriberForm(request.POST) in views without using None for GET request as it is already being handled in else condition so:
views.py:
def subscriber(request):
if request.method == "POST":
subscriber_form = SubscriberForm(request.POST)
...

Django: How to save data to ManyToManyField

Your help will be nice for me. Here are that codes:
models.py:
from django.db import models
class TagModel(models.Model):
tag = models.CharField(max_length=50)
def __str__(self):
return self.tag
class MyModel(models.Model):
title = models.CharField(max_length=50)
tag = models.ManyToManyField(TagModel)
forms.py:
from django import forms
from .models import *
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = '__all__'
views.py:
from django.shortcuts import render, get_object_or_404, redirect
from .models import *
from .forms import *
def MyWriteView(request):
if request.method == "POST":
mywriteform = MyForm(request.POST)
if mywriteform.is_valid():
confirmform = mywriteform.save(commit=False)
confirmform.save()
return redirect('MyDetail', pk=confirmform.pk)
else:
mywriteform = MyForm()
return render(request, 'form.html', {'mywriteform': mywriteform})
form.html(1st trial):
<form method="post">
{% csrf_token %}
{{ mywriteform }}
<button type="submit">Save</button>
</form>
form.html(2nd trial):
<form method="post">
{% csrf_token %}
{{ mywriteform.title }}
<select name="tags" required="" id="id_tags" multiple="">
{% for taglist in mywriteform.tags %}
<option value="{{taglist.id}}">{{taglist}}</option>
{% endfor %}
</select>
<button type="submit">Save</button>
</form>
I am trying to add tags on my post. I made a simple manytomany tagging blog but it does not work. I submitted a post by clicking the save button, and the title was saved, but the tag was not. In the admin, it worked well.
Thank you in advance.
update the code like this
if mywriteform.is_valid():
confirmform = mywriteform.save(commit=False)
confirmform.save()
mywriteform.save_m2m()
return redirect('MyDetail', pk=confirmform.pk)
for more details Refer here

csrf token not showing input fields - Django

I am new to django. am using django==1.11
am trying to create a form which inputs details of users.
my
views.py
from django.shortcuts import render, render_to_response, redirect
from django.template import loader, Template, Context, RequestContext
from forms import UserForm
from django.http import HttpResponse, HttpResponseRedirect
from django.views.decorators import csrf
def action(request):
if request.POST:
form = UserForm(data = request.POST)
if form.is_valid():
form.save(commit = False)
return HTTPResponseRedirect('/rfid/index')
else:
form = UserForm()
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('reg.html', args)
forms.py
from django import forms
from models import UserDetails
class UserForm(forms.ModelForm):
class Meta:
model = UserDetails
fields = '__all__'
reg.html
{% extends "rfid/header.html" %}
{% block content %}
<div class="container">
<form action = "/" method="post">{% csrf_token %}
<ul>
{{ form.as_ul }}
</ul>
<input type="submit" name="submit" class="btn btn-default" value="Add User">
</form>
</div>
{% include "rfid/includes/htmlsnippet.html" %}
{% endblock %}
models.py
from django.db import models
# Create your models here.
class UserDetails(models.Model):
GENDER_CHOICES = (('M', 'Male'), ('F', 'Female'))
user_id = models.IntegerField(primary_key = True)
name = models.TextField(max_length = 50)
gender = models.CharField(max_length = 1, choices = GENDER_CHOICES)
dob = models.DateTimeField()
address = models.TextField(max_length = 200)
phone = models.IntegerField()
email = models.EmailField(max_length=254)
photo_url = models.CharField(max_length = 200)
def __str__(self):
return self.name
But it is only showing the submit button. Model-based fields are not displaying. I had gone through some Questions here but was not able to trace out what was the problem. can anyone help me out.
Hope all required details are given. pls, ask if I miss anything.
regards.
Check out the line with form.save(commit=False).
Except you want to give that line a name and later save the name like saved_form=form.save(commit=False) then saved_form.safe, then the commit=False line isn't necessary. I don't know if that is the problem, but will check and revert

Django 1.7 old style custom user model

Could you please help me with Django and custom user model? I'm a new in Django world, so I started to learn from newest version 1.7. In my project I'm using django-allauth package and I want to create OneToOne relationship between standard user class from contrib.auth and my custom model "users".
#models.py
import datetime
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user=models.OneToOneField(User)
f_name=models.CharField(null=True, blank=True, max_length='30')
l_name=models.CharField(null=True, blank=True, max_length='30')
birth_date=models.DateField(null=True, blank=True)
company=models.CharField(null=True, blank=True, max_length='30')
rate=models.FloatField(null=True, blank=True, default=0.0)
skills=models.CharField(null=True, blank=True, max_length='255')
bill_rate=models.CharField(null=True, blank=True, max_length='255')
contacts=models.CharField(null=True, blank=True, max_length='255')
portfolio=models.CharField(null=True, blank=True, max_length='127')
avatar = models.ImageField(upload_to='/static/img/%Y/%m/%d', blank=True, null=True)
def __unicode__(self):
return self.user.username
This is forms.py
#forms.py
from django.forms import ModelForm
from users.models import Profile
class ProfileForm(ModelForm):
class Meta:
model = Profile
fields = ('f_name', 'l_name', 'company', )
This is a template:
{% extends "base_.html" %}
{% block main_content%}
<div>
{% if user.is_authenticated %}
<p>Welcome, {{ request.user.id }}!</p>
<form id="profile_form" method="POST" action="/accounts/profile" enctype="multipart/form-data">
{% csrf_token %}
{{ profile_form.as_p }}
<input type="submit" name="submit" value="Save" />
</form>
{% endif %}
</div>
{% endblock%}
And views.py:
from django.http import HttpResponse
from django.template import RequestContext
from django.conf import settings
from django.shortcuts import render, render_to_response
from models import Profile
from forms import ProfileForm
def edit(request):
profile_form = ProfileForm()
user = request.user
if request.method == 'POST':
profile_form = ProfileForm(data=request.POST, instance=user)
if profile_form.is_valid():
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
return render_to_response("profile.html", RequestContext(request))
return render_to_response('profile_edit.html', RequestContext(request, {'profile_form' : profile_form}))
I built all of this files according by this tutorial:
http://www.tangowithdjango.com/book/chapters/login.html
And finally, all of this works fine, but when I push Save button, POST form doesn't work. I can't see any changes in database. Redirecting works good, actually it seems that all works fine, but I don't have any data in table (I'm using postgres by the way).
I spent a lot to find the answer and tried almost everything in the internet, but I still have this issue. Maybe I can't understand how it works from django documentation, but I tried the same method and still have a problem.
Thank you in advance!
UPDATE:
My urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
urlpatterns = patterns('',
# Examples:
url(r'^$', 'laniakea.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
url(r'^admin/', include(admin.site.urls)),
url(r'^accounts/', include('allauth.urls')),
url('accounts/profile', 'laniakea.views.prof', name='prof'),
url(r'^edit', 'users.views.edit', name='edit'),
)
I found a solution! As Daniel said, I changed "action" attribute to transfer POST request to the same form. And as I discovered, I not created a right instance of User parent class. Actually, I don't need to use them.
#views.py
from django.template import RequestContext
from django.shortcuts import render
from models import Profile
from forms import ProfileForm
def edit(request):
user = request.user
if request.method == 'POST':
profile_form = ProfileForm(request.POST)
if profile_form.is_valid():
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
return HttpResponseRedirect('accounts/profile')
else:
profile_form = ProfileForm()
return render(request, 'profile_edit.html', {'profile_form' : profile_form})
and
#profile_edit.html
{% extends "base_.html" %}
{% block main_content%}
<div>
{% if user.is_authenticated %}
<p>Welcome, {{ request.user.id }}!</p>
<form id="profile_form" method="POST" action="" enctype="multipart/form-data">
{% csrf_token %}
{{ profile_form.as_p }}
<input type="submit" name="submit" value="Save" />
</form>
{% endif %}
</div>
{% endblock%}
Thank you very much for help and good luck!