I have a section of my site where an admin can add a widget. However the delete button to delete any current widgets is not working. I have this code implemented else where on my site and it is working.
I copied the same code from the other section of my site where this is being used. The other section of my site which uses this code is a little different in that a post can only be deleted be the user who created it, and the widgets can be delete by any user with the "access_level" field is equal to "admin". However, I am the only admin so it should still work. The page that the widget stuff is displayed on is only accessible if your "access_level" is equal to admin so I don't need to validate whether or not they have the permission before deleting. Please help.
widget_list.html:
{% extends "base.html" %}
{% block content %}
<div class="container">
<div class="content">
<div class="widgets-list">
{% for widget in widget_list %}
<h3>{{ widget.name }}</h3>
<h3>{{ widget.widget_order }}</h3>
<div>
<p>{{ widget.body }}</p>
</div>
{% if user.is_authenticated %}
<a class="auth-user-options" href="{% url 'adminpanel:delete-widget' pk=widget.pk %}">Delete</a>
{% endif %}
{% endfor %}
</div>
</div>
</div>
{% endblock %}
Adminpanel app views.py:
from django.shortcuts import render
from adminpanel.forms import WidgetForm
from adminpanel.models import Widget
from django.utils import timezone
from django.contrib.auth import authenticate,login,logout
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse,reverse_lazy
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from braces.views import SelectRelatedMixin
from django.views.generic import (TemplateView,ListView,
DetailView,CreateView,
UpdateView,DeleteView)
# Create your views here.
class CreateWidgetView(LoginRequiredMixin,CreateView):
login_url = '/login/'
redirect_field_name = 'index.html'
form_class = WidgetForm
model = Widget
def form_valid(self,form):
self.object = form.save(commit=False)
self.object.save()
return super().form_valid(form)
def get_success_url(self):
return reverse('adminpanel:widgets')
class SettingsListView(ListView):
model = Widget
ordering = ['widget_order']
class DeleteWidget(LoginRequiredMixin,SelectRelatedMixin,DeleteView):
model = Widget
select_related = ('Widget',)
success_url = reverse_lazy('adminpanel:widget')
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(user_id=self.request.user.id)
def delete(self,*args,**kwargs):
return super().delete(*args,**kwargs)
Project url spy:
from django.conf.urls import url
from django.contrib import admin
from django.conf.urls import include
from accounts import views
from colorsets import views
from colors import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$',views.home,name='index'),
url(r'^accounts/',include('accounts.urls',namespace='accounts')),
url(r'^colorsets/',include('colorsets.urls',namespace='colorsets')),
url(r'^adminpanel/',include('adminpanel.urls',namespace='adminpanel')),
]
Adminpanel app urls.py:
from django.conf.urls import url
from adminpanel import views
app_name = 'adminpanel'
urlpatterns = [
url(r'^widgets/',views.SettingsListView.as_view(),name='widgets'),
url(r'^new/$',views.CreateWidgetView.as_view(),name='create-widget'),
url(r'^delete/(?P<pk>\d+)/$',views.DeleteWidget.as_view(),name='delete-widget'),
]
EDIT: Here is the error I'm getting I forgot to add it.
FieldError at /adminpanel/delete/10/
Cannot resolve keyword 'user_id' into field. Choices are: body, id, name, widget_order
and the traceback points to this:
/Users/garrettlove/Desktop/colors/adminpanel/views.py in get_queryset
return queryset.filter(user_id=self.request.user.id) ...
▶ Local vars
Adminpanel app models.py (widget model):
from django.db import models
from adminpanel.choices import *
# Create your models here.
class Widget(models.Model):
name = models.CharField(max_length=50)
widget_order = models.IntegerField(blank=False,unique=True)
display_name = models.IntegerField(choices=WIDGET_NAME_CHOICES,default=1)
body = models.TextField(max_length=500)
def __str__(self):
return self.name
As your error is saying:
Cannot resolve keyword 'user_id' into field.
And it points to this line:
return queryset.filter(user_id=self.request.user.id)
It's that your queryset model does not have a user_id field. In your DeleteWidget view you have specified model = Widget
and as you see in your Widget model, you have the following fields: body, id, name, widget_order. There is no user_id field.
You need to change your filtering logic. If you want to have a related User model, you should use ForeignKey relation and then you can filter by the User's id.
In your models.py:
from django.contrib.auth.models import User
class Widget(models.Model):
# ...
user = models.ForeignKey(User, on_delete=models.CASCADE)
And then in your DeleteWidget's get_queryset, you can do the following:
return queryset.filter(user__id=self.request.user.id)
# __________________________^
# Note that there is a double underscore here!
# This is because Django uses double underscore for accessing related models in queries.
Related
I really dislike django CBV design which makes things without flexibility.
I would like to have a page whose upper part showing the content of objects and lower part has a form to be posted.
CBS formview
class EditStudent(FormView):
template_name = "editstudent.html"
model = models.Student
success_url = "/home"
Update:
I add the method but the error
'NoneType' object is not callable shows up.
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['students'] = Student.objects.all()[:5]
return context
How can I retriev objects of studens and show them on the template.
Thanks.
'NoneType' object is not callable: I get this error when I don't specify a form class. Created form class 'StForm' associated with model 'Student'.
In the EditStudent view class, the CreateView class was inherited, since the data was not saved to the database with the FormView.
Replace bboard with the name of the folder where your templates are placed.
I have this: templates/bboard which are in the application folder.
template_name = 'bboard/tam_form.html'
The success_url row specifies a path based on the path name.
success_url = reverse_lazy('student')
The five most recent records are also transmitted in the context.
context['students'] = Student.objects.order_by('-pk')[:5]
In the template, the first five records are displayed on top and a form is displayed below to fill out.
forms.py
from django.forms import ModelForm
from .models import Student
class StForm(ModelForm):
class Meta:
model = Student
fields = '__all__'
views.py
from .models import Student
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
from .forms import StForm
class EditStudent(CreateView):
template_name = 'bboard/editstudent.html'
form_class = StForm
success_url = reverse_lazy('student')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['students'] = Student.objects.order_by('-pk')[:5]
return context
urls.py
from django.urls import path
from .views import *
urlpatterns = [
path('student/', EditStudent.as_view(), name='student'),
]
editstudent.html
<h4>
{% for aaa in students %}
<p>{{ aaa }}</p>
{% endfor %}
</h4>
<h2>form</h2>
<form method="post" action="{% url 'student' %}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="adding">
</form>
It seems like my models.py, forms.py, urls.py and views.py are not recognizing the elements in each other and I don't understand what could be going wrong. I'm just starting the project (CS50W Project4-Network) and I noticed the problem when I tried to render the model form and the textarea field of the form linked to the model wouldn't show on the browser, it only shows when I click submit, as a missing field to be filled, I'm not sure if its because of the same pylint errors I'm getting or something else.
Here is my models:
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
pass
class Post(models.Model):
body = models.TextField()
date = models.DateTimeField(auto_now_add = True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="author", default=None)
def __str__(self):
return f"{self.body} by {self.author} at {self.date}"
The forms.py:
from django import forms
from django.forms import ModelForm
from .models import Post
class PostForm(ModelForm):
class Meta:
model = Post
fields = ["body"]
widgets = {
"body": forms.Textarea(attrs={'class': 'form-control col-md-5 col-lg-6'}),
}
The views
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.db import IntegrityError
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse
from .forms import PostForm
from .models import User, Post
**I left out logging in routes**
#login_required(login_url='login')
def create_post_page(request):
return render(request, "network/create_post.html")
def create_post(request):
posted = False
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.author = request.user
instance.save()
return HttpResponseRedirect("/create_post?posted=True")
else:
form = PostForm()
if "posted" in request.GET:
posted = True
return render(request, "network/create_post.html", {
"posted": posted,
"form": form
})
The urls:
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("create_post", views.create_post, name="create_post"),
path("create_post_page", views.create_post_page, name="create_post_page")
]
The template code where the form is not showing, only showing when I click submit as a missing field to be field
{% extends "network/layout.html" %}
{% block body %}
{% if posted %}
{% else %}
<h2>Create a new post</h2>
<form action="{% url 'create_post' %}" method = "POST">
{% csrf_token %}
{{ form.as_p }}
<input class="btn btn-secondary" type="submit" value="Post">
</form>
{% endif%}
{% endblock %}
The problems vscode keep raising:
No name 'Post' in module 'network.models'Pylint(E0611:no-name-in-module)
Module 'network.views' has no 'create_post' memberPylint(E1101:no-member)
Module 'network.views' has no 'create_post_page' memberPylint(E1101:no-member)
Somebody help me please, I feel like its a small problem but its driving me nuts because I can't figure out why.
Make sure you load the plugin "pylint_django" when pylint is called, and that you pass it the correct value for django-settings-module. To do this, create a file pylintrc in your project folder and give it the following contents:
[MAIN]
load-plugins = pylint_django,
django-settings-module = mysite.settings
I'm following along a book called Django for Beginners and creating a project which displays newspaper articles. Part of the functionality is being able to edit those articles. I've followed along as closely as I could but I'm still getting an error when hitting the 'Update' button:
My urls.py
from django.urls import path
from .views import (ArticleListView,
ArticleUpdateView,
ArticleDetailView,
ArticleDeleteView)
urlpatterns = [
path('<int:pk>/edit/', ArticleUpdateView.as_view(), name = 'article_edit'),
path('<int:pk>/', ArticleDetailView.as_view(), name = 'article_detail'),
path('<int:pk>/delete/', ArticleDeleteView.as_view(), name = 'article_delete'),
path('', ArticleListView.as_view(), name = 'article_list'),
]
my views.py
from django.shortcuts import render
from django.views.generic import ListView, DetailView
from django.views.generic.edit import UpdateView, DeleteView
from django.urls import reverse_lazy
from .models import Article
# Create your views here.
class ArticleListView(ListView):
model = Article
template_name = 'article_list.html'
class ArticleDetailView(DetailView):
model = Article
template_name = 'article_detail.html'
class ArticleUpdateView(UpdateView):
model = Article
fields = ('title', 'body')
template_name = 'article_edit.html'
class ArticleDeleteView(DeleteView):
model = Article
template_name = 'article_delete.html'
success_url = reverse_lazy('article_list')
My models.py:
from django.db import models
from django.conf import settings
from django.contrib.auth import get_user_model
from django.urls import reverse
# Create your models here.
class Article(models.Model):
title = models.CharField(max_length=225)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
)
def __str__(self):
return self.title
def get_absolute_url(self):
reverse('article_detail', args=[str(self.id)])
My HTML:
<!-- templates/article_edit.html -->
{% extends 'base.html' %}
{% block content %}
<h1>Edit</h1>
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}\
<button class="btn btn-info ml-2" type="submit">Update Article {{article.pk}}</button>
</form>
{% endblock content %}
After hitting the edit button, according to the book the app is supposed to forward me to the 'article_detail' page however that is not happening.
Any assistance would be gratefully received.
Thanks
Andy
In the end it was a simple omission of a return statement in the get_absolute_url function within models.py.
I am having a post model with a user having OneToMany Relationship with inbuilt user model for authentication
my urls.py
from django.contrib import admin
from django.urls import path, include
# from views import PostView
from . import views
urlpatterns = [
path('', views.PostView.as_view(), name='blogHome'),
path('post/<int:pk>/', views.PostDetailView.as_view(), name='post-detail'),
path('post/new/', views.PostCreateView.as_view(), name='post-create'),
path('about/', views.about, name='about')
]
my views.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import Post
from django.views.generic import (
ListView,
DetailView,
CreateView
)
# Create your views here.
def home(request):
context = {
'posts': Post.objects.all()
}
return render(request, 'blog/home.html', context)
def about(request):
return render(request, 'blog/about.html')
class PostView(ListView):
model = Post
template_name = 'blog/home.html'
context_object_name = 'posts'
ordering = ['-date_published']
class PostDetailView(DetailView):
model = Post
class PostCreateView(CreateView):
model = Post
fields = ['title', 'body']
#to add author before validation
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
Post Model
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
# Create your models here.
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
body = models.TextField()
date_published = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
I am using post_form.html as the template name
post_form.html
{% extends 'blog/layout.html' %}
{% load crispy_forms_tags %}
{% block body %}
<div class="content-section p-20">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group p-30">
<legend class="border-bottom mb-4">Create new post</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Create</button>
</div>
</form>
</div>
{% endblock %}
I am a beginner in Django , please tell if anything more is needed to solve the problem. Also why this type of error is coming only with Createview and not with other views
Apparently the return of super().form_valid(form) is None and not a valid response. I don't know much of this design pattern in Django but seeing your other methods seems like this view is decorated by some method which returns a valid response. So you should not return something in your implementation. So, drop the return and test again.
I am building a web app in Django trying to use django-autocomplete-light(v.3.8.2) to create an auto-complete field. I have form that allows users to create a Trade record. I'm trying to add an auto-complete field for Trade.owned_game (a lookup field). I am just getting an empty dropdown field for the auto-complete field (screenshot attached at bottom of this post) Below is my code:
models.py:
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
class Game(models.Model):
name = models.TextField() # Unrestricted text
platform = models.CharField(max_length=100) # character field
created_date = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name # return game name when game.objects.all() is called
class Trade(models.Model):
name = models.TextField() # Unrestricted text
created_date = models.DateTimeField(default=timezone.now)
is_trade_proposed = models.BooleanField(default=False)
user_who_posted = models.ForeignKey(User, on_delete=models.CASCADE)
owned_game = models.ForeignKey(Game, on_delete=models.CASCADE, related_name='owned_game', db_column='owned_game')
def __str__(self):
return self.name # return game name when game.objects.all() is called
urls.py:
from django.urls import path
from django.conf.urls import url
from .views import (
PostListView,
TradeListView,
PostDetailView,
TradeCreateView,
GameAutoComplete,
PostUpdateView,
PostDeleteView,
UserPostListView
)
from . import views
urlpatterns = [
path('', views.home, name='blog-home'),
path('post/new/', views.trade_new, name='trade-create'),
url(
r'^game-autocomplete/$',
GameAutoComplete.as_view(),
name='game-autocomplete')
,
]
views.py:
from django.shortcuts import render, get_object_or_404
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.models import User
from django.views.generic import (
ListView,
DetailView,
CreateView,
UpdateView,
DeleteView
)
from .models import Trade, Game
def trade_new(request):
form = TradeCreateForm()
return render(request, 'blog/trade_form.html', {'form': form, 'title': 'asdf'})
class TradeCreateForm(forms.ModelForm):
game = forms.ModelChoiceField(
queryset=Game.objects.all(),
to_field_name = 'name',
widget=autocomplete.ModelSelect2(url='game-autocomplete')
)
class Meta:
model = Trade
fields = ['owned_game', 'desired_game']
class TradeCreateView(LoginRequiredMixin, CreateView):
model = Trade
fields = ["owned_game"]
class GameAutoComplete(autocomplete.Select2QuerySetView):
def get_queryset(self):
if not self.request.user.is_authenticated:
return Game.objects.none()
qs = Game.objects.all()
if self.q:
qs = qs.filter(name__istartswith=self.q)
return qs
trade_form.html:
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Propose New Trade</legend>
{{ form|crispy }}
{{ form.media }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Submit</button>
</div>
</form>
</div>
{% endblock content %}
Screenshot:
enter image description here
I have tried the solutions from these similar StackOverflow questions but they're not working:
Django-autocomplete-light showing empty dropdown instead of autocomplete widget
django-autocomplete-light displays empty dropdown in the form
I should have checked the javascript console earlier! The problem was one of the <link ...> scripts for jQuery was invalid. Once i fixed that, the auto-complete field worked