Drop Down Menu in Django displaying as text field - django

I've followed the process laid out on the Django ModelForm's documentation, as well as a couple of tutorials. My field displays as a standard text-entry, rather than a drop down. Can anyone point me in the right direction?
forms.py
from .models import Authority # change to rating!!!
from django import forms
class AuthorityForm(forms.ModelForm):
class Meta:
model = Authority
fields = ('authority_name',)
views.py
from django.shortcuts import render
from django.views.generic import CreateView
from .models import Authority
from .forms import AuthorityForm
# Create your views here.
class HomeCreateView(CreateView):
model = Authority
form_class = AuthorityForm
template_name = 'home.html'
success_url = 'home.html'
models.py
from django.db import models
# Create your models here.
class Authority(models.Model):
authority_name = models.CharField(max_length = 100)
authority_url = models.URLField()
def __str__(self):
return self.authority_name
class Rating(models.Model):
authority_name = models.CharField(max_length = 100)
ratings = models.CharField(max_length = 20000)
# Could this be reduced if remove the trailing letters of non-int values?
# Perhaps all values could be one-hot encoded
home.html
<h2>Choose Authority:</h2>
<form method="post" novalidate>
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<button type="submit">Submit</button>
</form>

Related

CreateView with OneToOneField relation in one View

I'm a Django beginner and try to implement a class based CreateView with two forms and an OneToOne relation but have no glue how to do this in one view.
For example: the following is given:
#models.py
# some imports..
class RedItem(models.Model):
name = models.Charfield(max_length=255)
storage = models.OneToOneField("Storage", on_delete=models.CASCADE)
class BlueItem(models.Model):
name = models.Charfield(max_length=255)
storage = models.OneToOneField("Storage", on_delete=models.CASCADE)
class Storage(models.Model):
shelf = models.Charfield(max_length=255)
room = models.Charfield(max_length=255)
...the View:
#views.py
from django.views.generic.edit import CreateView
from .models import RedItem, BlueItem, Storage
# some other imports..
class RedItemCreate(CreateView):
model = RedItem
fields = ['name']
template_name_suffix = "_form"
```html
and a Form:
```html
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save">
</form>
The question is now how can a user fill in both (e.g. RedItem + Storage) in one batch?
Thanks in advance for any direction.
Update and a working approach:
I have to create forms in forms.py and add it the the CreateView.
#urls.py
from django.urls import path
from .views import *
urlpatterns = [
path('reditemlist/', ExampleList.as_view(), name='example_list'),
path('reditemcreate/', ExampleCreate.as_view(), name='example_create')
]
#forms.py
from django.forms import ModelForm
from .models import RedItem, Storage
class RedItemForm(ModelForm):
class Meta:
model = RedItem
fields = ['name']
class StorageForm(ModelForm):
class Meta:
model = Storage
fields = ['shelf']
And the CreateView:
#views.py
from django.shortcuts import render
from django.views.generic.list import ListView
from django.views.generic.edit import CreateView
from .models import *
from .forms import *
from django.urls import reverse_lazy
class ExampleList(ListView):
model = RedItem
class ExampleCreate(CreateView):
model = RedItem
form_class = RedItemForm
success_url = reverse_lazy('example_list')
def get_context_data(self, **kwargs):
context = super(ExampleCreate, self).get_context_data(**kwargs)
if self.request.POST:
context['reditem'] = RedItemForm(self.request.POST)
context['storage'] = StorageForm(self.request.POST)
else:
context['reditem'] = RedItemForm()
context['storage'] = StorageForm()
return context
def form_valid(self, form):
context = self.get_context_data()
storage = context['storage']
if storage.is_valid() and form.is_valid():
f = form.save()
shelf = storage.save(commit = False)
shelf.reditem = f
shelf.save()
return super().form_valid(form)
<form method="post">{% csrf_token %}
{{ form.as_p }}
{{ storage.as_p }}
<input type="submit" value="Save">
</form>
Next stop: UpdateView

get_absolute_url: error of Reverse for 'article-detail' not found

I am using class based views to create a post. I have used get_absolute_url to go to the post page after clicking on post but it is giving an error of no reverse match.
this is my modelspy
from django.db import models
from django.conf import settings
from django.urls import reverse
# Create your models here.
class BlogPost(models.Model):
title = models.CharField(max_length = 50 , null=False,blank=False)
body = models.TextField(max_length = 5000 , null=False,blank=False)
date_published = models.DateTimeField(auto_now_add=True)
date_update = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('article-detail', args=(str(self.id)))
this is my urls.py:
urlpatterns = [
path('',views.home,name="home"),
path('home2/',HomeView.as_view(),name = "home2"),
path('article/<int:pk>',ArticleDetailView.as_view(),name = "article-detail"),
path('add_post/',AddPostView.as_view(),name="add_post"),
]
this is home2.html:
<ul>
{%for post in object_list %}
<li>{{post.title}}-{{post.author}}<br/>
{{post.body}}</li>
{%endfor%}
</ul>
this is views.py:
from django.shortcuts import render
from .models import *
from .forms import *
from django.views.generic import ListView,CreateView
from django.views.generic.detail import DetailView
# Create your views here.
def home(request):
return render(request,'post/home.html')
class HomeView(ListView):
model = BlogPost
template_name = "post/home2.html"
class ArticleDetailView(DetailView):
model = BlogPost
template_name = "post/article_details.html"
context_object_name = 'post'
class AddPostView(CreateView):
model = BlogPost
template_name = "post/add_post.html"
fields = '__all__'
I would suggest doing something like. I provide 2 methods.
1st method:
By using get_absolute_url
from django.urls import reverse
def get_absolute_url(self):
return reverse('post:article-detail', args=(self.id)) #post is the app_name
urls.py
url(r'^article/(?P<pk>\d+)/$', ArticleDetailView.as_view(), name='article-detail'),
home2.html
<ul>
{%for post in object_list %}
<li>
{{post.title}}-{{post.author}}<br/>{{post.body}}
</li>
{%endfor%}
</ul>
2nd Method:
By using template tag.Here get absolute url with help of template tag.
home2.html
{% load templatehelpers %}
<ul>
{%for post in object_list %}
<li>
{{post.title}}-{{post.author}}<br/>
{{post.body}}
</li>
{% endfor %}
</ul>
Here we use a new simple tag namely abs_url (absolute url) in templatehelpers.py (Template tag). And app_name is the name of the app.
templatehelpers.py
from django import template
from django.urls import reverse
register = template.Library()
#register.simple_tag
def abs_url(value, request, **kwargs):
return reverse(value,kwargs=kwargs)
If you change this
def get_absolute_url(self):
return reverse('article-detail', args=(str(self.id)))
to this
def get_absolute_url(self):
return reverse('home')
You will not get the error, but you will not either be redirected to the post you just posted.
So if your goal is to just get rid of this error, but don't care about where you get redirected afterwards, then this is the solution for you.

my django 3 project is shwoing 'ModelForm has no model class specified'

i am a beginner django developer, "ModelForm has no model class specified. " is given on my project , what i can do pls help, i will be greatfull to you if you solve my problem
models.py
from django.db import models
class product(models.Model):
name = models.CharField(max_length=50)
forms.py
from django.forms import ModelForm
from .models import product
class productform(ModelForm):
class Meta:
model:product
fields: '__all__'
views.py
from django.shortcuts import render
from formt.forms import productform
def index(request):
form = productform()
context = {
'form' : form
}
return render(request, 'index.html' , context )
index.html
<h1>form model</h1>
<form action="">
{% csrf_token %}
{{form}}
<input type="submit" text="submit">
</form>
forms.py
class ProductForm(ModelForm):
class Meta:
model = Product
fields = '__all__'
views.py
from .forms import ProductForm
Look at your syntax.
Class names should start with a capital letter.
class ProductForm(ModelForm):
class Meta:
model = Product
fields: '__all__'

Data not shown in Django admin after adding by my form

I am a beginner to Django.
I want to create a form that allow user to store their data to the database, but I face to an issue.
If I add data through Django admin, the data will shown correctly. But if I add data through my form. Data will store into database successfully but they don't shown in my Django admin.
Note: The Django version I used is 1.11.2
The is my Django admin page. There are 8 data in the database but just show the one I added by the Django admin.
views.py
from django.shortcuts import render
from django.views.generic import CreateView
from .forms import ApplyFormCreateForm
from .models import ApplyForm
class ApplyFormCreateView(CreateView):
form_class = ApplyFormCreateForm
template_name = 'form.html'
success_url = "/"
models.py
from django.db import models
from course.models import Semester
DEFAULT_SEMESTER_ID = 1
class ApplyForm(models.Model):
name = models.CharField(max_length=15)
school = models.CharField(max_length=20)
department = models.CharField(max_length=20)
email = models.EmailField(max_length=100)
is_beginner = models.BooleanField(default=False)
introduction = models.TextField(max_length=2000)
motivation = models.TextField(max_length=2000)
comments = models.TextField(max_length=2000, blank=True)
semester = models.ForeignKey(Semester, default=DEFAULT_SEMESTER_ID)
created_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.school + self.department + self.name
def __str__(self):
return self.school + self.department + self.name
form.html
{% extends "base.html" %}
{% block content %}
<form method='POST'> {% csrf_token %}
{{form.as_p}}
<button type='submit'>Save</button>
</form>
{% endblock content %}
form.py
from django import forms
from .models import ApplyForm
class ApplyFormCreateForm(forms.ModelForm):
class Meta:
model = ApplyForm
fields = [
'name',
'school',
'department',
'email',
'is_beginner',
'introduction',
'motivation',
'comments',
]
url.py
from django.conf.urls import url
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
from myweb.views import HomeView
from course.views import CourseListView
from applyform.views import ApplyFormCreateView
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', HomeView.as_view(), name='home'),
url(r'^course/$', CourseListView.as_view(), name='course'),
url(r'^apply/$', ApplyFormCreateView.as_view(), name='applyform'),
]

Clean() method from custom Django form not being called

I need to validate a condition in my Experiment class that depends on more than one field. I specified a 'clean' method in my ExperimentForm, but the validation method is never raised. The model's validation errors are perfectly displayed.
This is how the forms.py looks like:
from django import forms
from django.utils.translation import ugettext, ugettext_lazy as _
class ExperimentForm(forms.Form):
name = forms.CharField(max_length=254)
student_n = forms.IntegerField()
expert_n = forms.IntegerField()
student_cmd_n = forms.IntegerField()
expert_cmd_n = forms.IntegerField()
is_active = forms.BooleanField()
error_messages = {
'insufficient_assignments': _("The total number of commands to be evaluated must be"
"Greater than 28. Right now it's %(command_number)"),
}
def clean(self):
cleaned_data = super(ExperimentForm, self).clean()
s_n = cleaned_data.get("student_n")
e_n = cleaned_data.get("expert_n")
s_cmd_n = cleaned_data.get("student_cmd_n")
e_cmd_n = cleaned_data.get("expert_cmd_n")
command_number = s_n*s_cmd_n + e_n*e_cmd_n
if command_number < 28:
raise forms.ValidationError(
self.error_messages['insufficient_assignments'],
code='insufficient_assignments',
params={'command_number': command_number},
)
return self.cleaned_data
This is my views.py
from __future__ import unicode_literals
from django.shortcuts import render
from django.http import HttpResponse
from django.template import loader
from django.core.urlresolvers import reverse_lazy
from vacs.forms import ExperimentForm
from django.views.generic import TemplateView,ListView
from django.views.generic.edit import FormView, CreateView, UpdateView, DeleteView
from django.views.generic.detail import DetailView
from vacs.models import Experiment
class ExperimentView(FormView):
template_name = 'vacs/experiment.html'
form_class = ExperimentForm
success_url = '/vacs/experiments/'
def form_valid(self, form):
return super(ExperimentView, self).form_valid(form)
class ExperimentDetailView(DetailView):
model = Experiment
class ExperimentListView(ListView):
model = Experiment
class ExperimentCreateView(CreateView):
model = Experiment
success_url = reverse_lazy('experiment_list')
fields = ['name', 'student_n', 'expert_n', 'student_cmd_n', 'expert_cmd_n']
class ExperimentUpdateView(UpdateView):
model = Experiment
success_url = reverse_lazy('experiment_list')
fields = ['is_active' ]
class ExperimentDeleteView(DeleteView):
model = Experiment
success_url = reverse_lazy('experiment_list')
The models.py is defined in the following way:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
from django.core.validators import MaxValueValidator, MinValueValidator
from django.utils.encoding import python_2_unicode_compatible
from django.contrib.auth.models import User
from django.db import models
from jsonfield import JSONField
import collections
class Experiment(models.Model):
name = models.CharField(max_length=200)
student_n = models.IntegerField(default=0,
validators=[MinValueValidator(0)])
expert_n = models.IntegerField(default=0,
validators=[MinValueValidator(0)])
student_cmd_n = models.IntegerField(default=2,
validators=[MinValueValidator(2)])
expert_cmd_n = models.IntegerField(default=1,
validators=[MinValueValidator(1)])
is_active = models.BooleanField(default=True)
replications = JSONField(load_kwargs={'object_pairs_hook': collections.OrderedDict},
blank=True)
Finally, the template experiment_form.html:
{% extends "vacs/base.html" %}
{% load widget_tweaks %}
{% block content %}
{% if form.errors %}
<div class="alert alert-danger" role="alert">
Form error!
</div>
{% endif %}
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
Thank you!
You need to override the save method for the model.
So to run clean_fields() and clean() Add the following method to your model
def save(self, *args, **kwargs):
self.full_clean()
return super().save(*args, **kwargs)
Three types of cleaning methods are run during form processing. These are normally executed when you call the is_valid() method on a
form.
Django documentation