Django 2.0 CreateView not working - django

I am very new in Django. Not sure whether this is a bug or an error.
Here is my model in an app called gcbv (for generic class-based view)
from django.db import models
from core.models import TimeStampModel
from django.urls import reverse
# Create your models here.
class Vehicle(TimeStampModel):
maker = models.CharField(max_length=100)
model_year = models.IntegerField()
vehicle_type = models.CharField(max_length=100)
slug = models.SlugField(max_length=100, unique=True)
vehicle_model = models.CharField(max_length=100)
website = models.URLField(max_length=100, blank=True)
email = models.EmailField(max_length=100, blank=True)
notes = models.TextField(blank=True, default='')
def __str__(self):
x = self.maker + ' ' + self.vehicle_model
return x
And here are the URLs:
from django.contrib import admin
from django.urls import path, include
from django.conf.urls import url
from . import views
from django.urls import reverse
#from django.views.generic.base import TemplateView
app_name = 'gcbv'
urlpatterns = [
path('sub1/', views.SubView.as_view(), name='sub1'),
path('vehicle_list/', views.VehicleListView.as_view(),
name = 'vehicle_list'),
path('vehicle/<str:slug>/',
views.VehicleDetailView.as_view(),
name='vehicle_detail'),
path('vehicle/create', views.VehicleCreateView.as_view(),
name='vehicle_create'),
path('', views.IndexTemplateView.as_view(), name='index'),
]
And here is the relevant view:
class VehicleCreateView(CreateView):
model = Vehicle
fields = ['maker', 'model_year', 'vehicle_type', 'slug',
'vehicle_model', 'website', 'email', 'notes']
labels = {'maker':'Maker', 'model_year':'Year',
'vehicle_type':'Type', 'vehicle_model':'Model',
'website':'Website', 'email':'Email', 'notes':'Notes'}
Here is the template:
{% extends "core/base.html" %}
{% block body_block %}
<h1>Vehicle Create for GCBV</h1>
<form action="POST" action="">
{% csrf_token %}
{{ form.as_p }}
<button name="submit" class="btn btn-primary">Submit</button>
</form>
<h1>End Vehicle Create for GCBV</h1>
{% endblock %}
It looks as if the data aren't saved in the database, but when i'm adding the same data by hand directly in the admin page, everything works fine. I've attached another screenshot showing that VehicleDetailView has found the relevant template and rendered the information.
Any help would be greatly appreciated.
NB: Everything worked fine when I use function views and regex instead of path.
Form
After submit
List
Details
OK, this is what we septuagenarians call a "senior moment". I have been staring at this code for two days and did not see the obvious.
method="POST"!
NOT
action="POST"
Many, many thanks

In the fourth line of your template, method should be equal to "post"
{% extends "core/base.html" %}
{% block body_block %}
<h1>Vehicle Create for GCBV</h1>
<form method="POST" action="">
{% csrf_token %}
{{ form.as_p }}
<button name="submit" class="btn btn-primary">Submit</button>
</form>
<h1>End Vehicle Create for GCBV</h1>
{% endblock %}

Related

Why am I getting a No Reverse Match error when submitting using UpdateView?

I'm currently using UpdateView to add edit functionality to my Django project. It's working correctly insofar as I can edit my data, however when I submit the new data, it returns a NoReverseMatch error:
NoReverseMatch at /MyHealth/edit/8
Reverse for 'health_hub_history' not found. 'health_hub_history' is not a valid view function or pattern name.
I've researched it and added a get_absolute_url to my model, but it isn't working. Any help would be appreciated!
models.py:
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
class HealthStats(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
date = models.DateField(auto_now=True)
weight = models.DecimalField(max_digits=5, decimal_places=2)
run_distance = models.IntegerField(default=5)
run_time = models.TimeField()
class Meta:
db_table = 'health_stats'
ordering = ['-date']
def get_absolute_url(self):
return reverse('health_hub_history')
def __str__(self):
return f"{self.user} | {self.date}"
urls.py:
from django.urls import path
from django.contrib.staticfiles.storage import staticfiles_storage
from django.views.generic.base import RedirectView
from . import views
app_name = 'HealthHub'
urlpatterns = [
path('', views.home, name='home'),
path('MyHealth/', views.health_hub, name='health_hub'),
path('MyHealth/update', views.UpdateHealth.as_view(), name='health_hub_update'),
path('MyHealth/history', views.health_history, name='health_hub_history'),
path('favicon.ico', RedirectView.as_view(url=staticfiles_storage.url("favicon.ico"))),
path('MyHealth/delete/<item_id>', views.delete_entry, name='health_hub_delete'),
path('MyHealth/edit/<int:pk>', views.EditHealth.as_view(), name='health_hub_edit'),
]
Views.py:
class EditHealth(UpdateView):
model = HealthStats
template_name = 'health_hub_edit.html'
fields = ['weight', 'run_distance', 'run_time']
health_hub_edit.html:
{% extends 'base.html' %}
{% load static %}
{%load crispy_forms_tags %}
{% block content %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 text-center">
<h1>Edit my Data</h1>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-auto text-center p-3">
<form method="post" style="margin-top: 1.3em;">
{{ form | crispy }}
{% csrf_token %}
<button type="submit" class="btn btn-signup btn-lg">Submit</button>
</form>
</div>
</div>
<div class="row justify-content-center">
</div>
</div>
{% endblock content %}
This error occurs because the django couldn't resolve the url
you didn't specify a primary key to base the query on.
you should modify this function
def get_absolute_url(self):
return reverse('health_hub_history', kwargs={'user': self.user})
also that health_history url is it a class based view you should add .as_view() to the end and observe camel casing
Lastly your url should observe the primary key specified
You can do this:
class EditHealth(UpdateView):
model = HealthStats
template_name = 'health_hub_edit.html'
fields = ['weight', 'run_distance', 'run_time']
def get(self, request):
return HttpResponse("health_hub")
def post(self, request):
# do something
return redirect("health_hub")
urlpatterns = patterns('',
url('', views.home, name='home'),
url('MyHealth/', views.health_hub, name='health_hub'),
url('^MyHealth/update', views.UpdateHealth.as_view(), name='health_hub_update'),
url('MyHealth/history', views.health_history, name='health_hub_history'),
url('favicon.ico', RedirectView.as_view(url=staticfiles_storage.url("favicon.ico"))),
url('MyHealth/delete/<item_id>', views.delete_entry, name='health_hub_delete'),
url('MyHealth/edit/<int:pk>', views.EditHealth.as_view(), name='health_hub_edit'),
)
This will solve your problem
I found the answer to this issue here:
https://stackoverflow.com/a/48068932/19053957
Looks like all I need to do was refer to the app name prior to the name of the URL in get_absolute_url()!

NoReverseMatch at / Reverse for 'profile' with arguments '('',)' not found. 1 pattern(s) tried: ['profile/(?P<name>[^/]+)/$']

I am a beginner in learning code and am working on making a simple django site where users can write comments but I keep getting this error
My urls.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
path("profile/<str:name>/", views.profile, name="profile")
]
views.py
class NewPostForm(forms.Form):
title = forms.CharField(label="Title")
description = forms.CharField(widget=forms.Textarea)
def index(request):
if request.method == "POST":
form = NewPostForm(request.POST)
if form.is_valid():
title = form.cleaned_data['title']
description = form.cleaned_data['description']
author = request.user
post = NewPost(title=title, description=description, author=author)
post.save()
return HttpResponseRedirect(reverse("index"))
else:
return render(request, "network/index.html", {
"form": form
})
return render(request, "network/index.html", {
"form": NewPostForm(),
"posts": NewPost.objects.all()
})
models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
pass
class NewPost(models.Model):
title = models.CharField(max_length=32)
description = models.CharField(max_length=256)
author = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
and my index.html
{% extends "network/layout.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block body %}
<div class="form-group">
<form method="post" action="{% url 'index' %}">
{% csrf_token %}
{{form | crispy}}
<button class="btn btn-primary"> Post </button>
</form>
</div>
{% for post in posts %}
<div class="card">
<div class="card-body"> Title: {{post.title}} </div>
<div class="card-body"> Description: {{post.description}}</div>
<p> {{post.author.username}} </p>
<div class="card-body">
<a href="{% url 'profile' post.author.username %}">
#{{post.author.username}}
</a>
</div>
</div>
{% endfor %}
{% endblock %}
But I keep getting
NoReverseMatch at / Reverse for 'profile' with arguments '('',)' not found. 1 pattern(s) tried: ['profile/(?P[^/]+)/$']
It looks like the error is occurring with
<a href="{% url 'profile' post.author.username %}">
Make sure that each of these posts that you are looping through actually has an author and that each author has a username. Django won't be able to properly construct the url if post.author.username is None.
in this url : path("profile/str:name/", views.profile, name="profile")
do you have an view called profile?
and what does name in str:name refer to? username maybe? or author
you need to provide more details,
This is because you have an project with author I faced the similar issue.
Maybe you need to check your admin panel if there is a post without author that's probably the problem
NoReverseMatch at / Reverse for 'profile' with arguments '('',)' not found. 1 pattern(s) tried: ['profile/(?P[^/]+)/$']
It's means something missing in database thats you are working for in loops .Django won't be able to properly construct the url if somthing is blank. First go to the Django admit panel and find whats are missing.Example:Author,User,Admin etc.
If you define a post without assigning a profile (owner) to it, you get this error. in other words, something that Django wants (in your database) is blank!
You must go to the admin panel and check all posts that are defined, None of them should be without an owner.

Value error : Field 'id' expected a number but got 'create' while loading the form using CBV

I am creating a simple form that takes in basic info of school. I created it using 'CreateView' CBV but when I hit the URL, I get the value error: Value error: Field 'id' expected a number but got 'create'.
error page
Model.py:
from django.db import models
class School(models.Model):
name=models.CharField(max_length=256)
principal = models.CharField(max_length=256)
location = models.CharField(max_length=256)
def __str__ (self):
return self.name
def get_absolute_url(self):
return reverse("basic_app:detail",kwargs={'pk':self.pk})
class Student(models.Model):
name=models.CharField(max_length=256)
age=models.PositiveIntegerField()
school = models.ForeignKey(School,related_name='students',on_delete=models.CASCADE)
def __str__(self):
return self.name
Views.py
from django.views.generic import View, CreateView
from . import models
class SchoolCreateView(CreateView):
fields=["name","principal","location"]
model=models.School
urls.py:
from django.urls import path
from basic_app import views
app_name= 'basic_app'
urlpatterns=[
path('create/',views.SchoolCreateView.as_view(),name='create')
]
school_form.html:
{% block body_block %}
<h1>
{% if not form.instance.pk %}
Create school:
{% else %}
Update school:
{% endif %}
</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class = "btn btn-primary" value="Submit">
</form>
{% endblock %}
Note:
The URL works if I replace the URL path like 'create/school' (anything added after 'create/)
path('create/school',views.SchoolCreateView.as_view(),name='create')
then the page gets loaded. I could not figure out the issue, can anyone point out the mistake with the previous URL path.

update an object without DetailView Django

I'm looking for a solution to update an object without having to go to the detail page but, just edit it on the page itself. What I want to achieve is when I click on edit: the object becomes a field where I can edit and save it. All the YouTube tutorials show the edit->detail page version.
So a quick/direct edit on the object itself that is on the homepage without leaving the homepage.
I have tried to use the UpdateView on this but then there is separate HTML file necessary, which would result in leaving the homepage. I would like to get some help or tips on this.
urls.py
from django.urls import path
from .views import (
HomePageView,
TaskCreateView,
TaskDeleteView,
TaskUpdateView,
)
urlpatterns = [
path('', HomePageView.as_view(), name='home'),
path('task_new/', TaskCreateView.as_view(), name='task_new'),
path('<int:pk>/task_delete/', TaskDeleteView.as_view(), name='task_delete'),
path('<int:pk>/task_edit/', TaskUpdateView.as_view(), name='task_edit'),
]
views.py
from django.views.generic import ListView
from django.views.generic.edit import CreateView, DeleteView, UpdateView
from django.urls import reverse_lazy
from .models import Task
class HomePageView(ListView):
model = Task
template_name = 'home.html'
context_object_name = 'all_tasks_list'
class TaskCreateView(CreateView):
model = Task
fields = ['text',]
class TaskDeleteView(DeleteView):
model = Task
success_url = reverse_lazy('home')
class TaskUpdateView(UpdateView):
model = Task
fields = ['text',]
home.html
<!DOCTYPE html>
<html>
<head>
<title>Todo app</title>
</head>
<body>
<h1>Todo app</h1>
<ul>
{% for task in all_tasks_list %}
<li>{{ task.text }}</li>
<form action="{% url 'task_delete' task.pk %}" method="post">{% csrf_token %}
<input type="submit" value="Delete"/></form>
<form action="{% url 'task_edit' task.pk %}" method="post">{% csrf_token %}
<input type="submit" value="Edit"/>
</form>
{% endfor %}
</ul>
<form action="{% url 'task_new' %}" method="post">{% csrf_token %}
<input type="text" name="text"/>
<input type="submit" value="Add"/>
</form>
</body>
</html>
models.py
from django.db import models
from django.urls import reverse
class Task(models.Model):
text = models.TextField()
def __str__(self):
return self.text[:50]
def get_absolute_url(self):
return reverse('home')
The error says task_form.html doesn´t exist, default template for an UpdateView. Are you sure it exists? If you want to use another template you have to specify
class TaskUpdateView(UpdateView):
model = Task
fields = ['text',]
template_name = 'todoapp/my_template.html'
Considering you are using generic view you should follow documentation for UpdateView
In this particular case you are missing form that UpdateView looks for to render GET request
The UpdateView page displayed to a GET request uses a
template_name_suffix of '_form'.
In your particular case it is todoapp/task_form.html which you should create
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update"> </form>

Bootstrap navbar dropdown populated with database entries in Django 2

I am trying to populate a navbar "dropdown-menu" with individual "dropdown-item"'s populated from data in the sqlite3 DB.
I have something similar working on other pages but I cant get it to work in my navbar.
I am creating a record label, and want the list of artists populated from entries in the DB. I have found one tutorial on doing something similar in php, but doesn't translate, and there doesn't seem to be anything either on youtube or here other than populating form data.
Any help is greatly appreciated, as I have been trying to get it working for about a week now. I know it should be simple, but im missing something.
the app is called "music"
models.py
class Artist(models.Model):
artist_name = models.CharField(max_length=250, default='')
artist_logo = models.FileField()
artist_url = models.URLField(blank=True)
def __str__(self):
return self.artist_name
class Release(models.Model):
artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
release_title = models.CharField(max_length=500)
release_cover = models.FileField()
release_duration = models.IntegerField()
def __str__(self):
return self.release_title
class Track(models.Model):
release = models.ForeignKey(Release, default='', on_delete=models.CASCADE)
artist = models.ForeignKey(Artist, default='', on_delete=models.CASCADE)
track_title = models.CharField(max_length=200)
track_version = models.CharField(max_length=200)
track_genre = models.CharField(max_length=100)
track_duration = models.IntegerField()
track_number = models.SmallIntegerField()
class Meta:
ordering = ["track_number"]
def __str__(self):
return self.track_title
views.py
from django.contrib.auth import authenticate, login
from django.views import generic
from django.views.generic import ListView, View
from .models import Artist, Track, Release
from .forms import UserForm
# class IndexView(ListView):
# template_name = 'music/index.html'
class ReleaseView(generic.ListView):
template_name = 'music/releaselist.html'
context_object_name = 'all_releases'
def get_queryset(self):
return Release.objects.all()
class ArtistView(generic.ListView):
model = Artist
template_name = 'music/artistlist.html'
context_object_name = 'all_artists'
def get_queryset(self):
return Artist.objects.all()
class DetailView(generic.DetailView):
model = Release
template_name = 'music/detail.html'
urls.py (Main)
from django.contrib import admin
from django.urls import path, include, re_path
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
# include urls from the music app
path('music/', include('music.urls'))
urls.py ("music" aka the app urls)
from django.contrib import admin
from django.urls import path, include, re_path
from . import views
# defined the app name in case the same fields are used in other apps
app_name = 'music'
urlpatterns = [
# no info past music return index EG /music/
# path('', views.IndexView.as_view(), name='index'),
# albums/releases
re_path(r'^release/$', views.ReleaseView.as_view(), name='release'),
# looking for music page with album id afterwards /music/1
re_path(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name="detail"),
re_path(r'^(?P<pk>[0-9]+)/$', views.ArtistView.as_view(), name="artist"),
base.html
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Artists
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
{% for artist in all_artists %}
<li><a class="dropdown-item" href="#">{{ artist.artist_id }}</a></li>
{% endfor %}
</div>
</li>
Update:
Here is my releases.html which works using similar code, and at the bottom has a test which looks like the for loop is incorrect
{% extends 'music/base.html' %}
{% block title %}KOLD FUZEON: Releases{% endblock %}
{% block body %}
{% if all_releases %}
<ul>
{% for release in all_releases %}
<div class="releaseitem">
<li>{{ release.artist }} - {{ release.release_title }}</li>
<li><a href="{% url 'music:detail' release.id %}"</a><img src="{{ release.release_cover.url }}" style="width: 300px"></li>
</div>
{% endfor %}
</ul>
{% else %}
<h3>We currently dont have any releases yet.</h3>
{% endif %}
{#basic test for the artist list to be printed to screen#}
<ul>
<li>test1</li>
{% for artist in all_artists %}
<li>test2</li>
{% endfor %}
</ul>
{% endblock %}
In your View.py you have ArtistView where template is artistlist.html and your context is all_artist & you get all objects from db.
Code:
class ArtistView(generic.ListView):
model = Artist
template_name = 'music/artistlist.html'
context_object_name = 'all_artists'
def get_queryset(self):
return Artist.objects.all()
Now i believe you have a template named artistlist.html. If not create it in templates in which you will use for Loop
to render artist list so the code should be this for artistlist.html:
{% extends 'music/base.html' %}
{% block body %}
<h1>Artists!</h1>
<ul>
{% for artist in all_artists %}
<li class="artist">
<h1>
<a href='/music/{{ artist.id }}'>{{artist.artist_name }}</a>
</h1>
</li>
{% endfor %}
</ul>
</div>
{% endblock %}
You can Render Artist list in Base.html.
Using: Context Processor
First Create a file named context_processors.py in your App.Then add this code in that file.
from .models import Artist
def basetest(request):
hello = Artist.objects.values_list("artist_name", flat=True)
return {
'testname': hello
}
After that, open Settings.py and find context_processors and add the following settings 'yourapp.context_processors.add_variable_to_context'.
Settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
#This one is from my code so set it according to you
#appname.context_processors.function_name_context_processor.py',
'blog.context_processors.basetest',
],
},
},
]
After this just place {{ testname }} in your base.html according to your need. it will work. No need for looping just the interpolation will render you a list. Format it according to your need by following this doc
I believe there is some problem in the name of the 'key' that you are passing in the context.
In ReleaseView the context object name is all_releases, while you are trying to iterate on "all_artists".
Even if these changes not work, you can always try running your code on a normal view instead of the a generic view and pass the context in the template.