Django Form: django-autocomplete-light is showing empty dropdown - python

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

Related

Django UpdateView generating 'GET' request instead of 'POST'

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 using CreateView in django but getting error- The view blog.views.PostCreateView didn't return an HttpResponse object. It returned None instead

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.

Django generic UpdateView returns 404 error: "No user found matching the query" when using pk

I am creating a Django web app and want to use the generic UpdateView by passing in a user's primary key. It works for the DetailView, but not the UpdateView.
I've tried specifying the template_name, changing the order of paths in my urls.py file. I haven't tried using a slug yet, but I know I should be able to use a pk.
I am using the built-in User model from django.contrib.auth below for my profile.
views.py:
class Profile(generic.TemplateView):
template_name = 'accounts/profile.html'
class ProfileUpdate(generic.UpdateView):
model = User
fields = ['first_name']
template_name = 'accounts/profile_update_form.html'
models.py
from django.db import models
from django.contrib import auth
# Create your models here.
class User(auth.models.User,auth.models.PermissionsMixin):
readonly_fields = ('id',)
def __str__(self):
return self.username
class UserProfile(models.Model):
user = models.OneToOneField(auth.models.User,on_delete=models.CASCADE)
join_date = models.DateTimeField(auto_now=True)
profile_pic = models.ImageField(upload_to='profile_pics',default='media/block-m.png')
skills = models.TextField()
major = models.CharField(max_length=128)
grad_year = models.CharField(max_length=4)
clubs = models.TextField() #make FK to Clubs
opt_in = models.BooleanField(default=True)
def __str__(self):
return self.user.username
My urls.py is what frustrates me the most. The address http://127.0.0.1:8000/accounts/profile/5/ works fine, but http://127.0.0.1:8000/accounts/profile/5/edit/ returns a 404 error "No user found matching the query". So I know that the pk=5 exists, but doesn't work for my url ending in /edit/.
urls.py:
from django.urls import path,include
from django.contrib.auth import views as auth_views
from . import views
app_name = 'accounts'
urlpatterns = [
path('login/',auth_views.LoginView.as_view(template_name='accounts/login.html'),name='login'),
path('logout',auth_views.LogoutView.as_view(),name='logout'),
path('signup/',views.SignUp,name='signup'),
path('profile/<int:pk>/',views.Profile.as_view(),name='profile'),
path('profile/<int:pk>/edit/',views.ProfileUpdate.as_view(),name='profile_update'),
]
profile_update_form.html:
{% extends 'base.html' %}
{% load bootstrap4 %}
{% block content %}
<div class="container">
<h2>Sign Up</h2>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{% bootstrap_form form layout='inline' %}
<input type="submit" class="btn btn-primary" value="Sign Up">
</form>
</div>
{% endblock %}
That's because user.pk is not the same as primary key for the same users userprofile, if you check their respectable tables in database you will see the difference, yes it is confusing at first simplest solution I did is using signals:
def profile_creation_signal(sender, instance, created, **kwargs) :
if created:
UserProfile.objects.create(pk=instance.id, user=instance)
post_save.connect(profile_creation_signal, sender=User)
It should work!
path('<username>/', ProfileView.as_view(), name="public_profile"),
class ProfileView(DetailView):
model = User
template_name = "pages/public_profile.html"
context_object_name = "profile"
slug_field = "username"
slug_url_kwarg = "username"
You can replace -username- with unique fields

Django QuerySet is Empty while I added some stuff

Hello I am new in Django, and I decided to do a Blog page. Problem is that my queryset is empty after I create a new aplication. any idea why ?
Tried with active and without active.
views.py
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView
from django.http import Http404
from .models import BlogPost
class BlogPostListView(ListView):
queryset = BlogPost.objects.all().active()
template_name = "blog.html"
def get_queryset(self, *args, **kwargs):
request = self.request
return BlogPost.objects.all().active()
def BlogPost_list_view(request):
queryset = BlogPost.objects.all().active()
context = {
'object_blog': queryset
}
return render(request, "blog.html", context)
models.py
import random
import os
from django.db import models
from django.db.models.signals import pre_save, post_save
from django.urls import reverse
def get_filename_ext(filepath):
base_name = os.path.basename(filepath)
name, ext = os.path.splitext(base_name)
return name, ext
def upload_image_path(instance, filename):
print(instance)
print(filename)
new_filename = random.randint(1,18341264712)
name, ext = get_filename_ext(filename)
final_filename = '{new_filename}{ext}'.format(new_filename= new_filename, ext=ext)
return "products/{new_filename}/{final_filename}".format(
new_filename= new_filename,
final_filename=final_filename
)
class BlogPostQuerySet(models.query.QuerySet):
def active(self):
return self.filter(active=True)
def featured(self):
return self.filter(featured=True, active=True)
class BlogPostManager(models.Manager):
def get_queryset(self):
return BlogPostQuerySet(self.model, using=self._db)
def all(self):
return self.get_queryset()
class BlogPost(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField(blank=True, unique=True)
description = models.TextField()
image = models.ImageField(upload_to=upload_image_path, null=True, blank=True)
timestamp = models.DateTimeField(auto_now_add=True)
active = models.BooleanField(default=True)
objects = BlogPostManager()
def get_absolute_url(self):
return "{slug}/".format(slug=self.slug)
# return reverse("products:detail", kwargs={"slug": self.slug})
def __str__(self):
return self.title
def __unicode__(self):
return self.title
urls.py
from django.conf import settings
from django.conf.urls import url, include
from django.conf.urls.static import static
from .views import BlogPostListView, BlogPostDetailSlugView
urlpatterns = [
url(r'^$', BlogPostListView.as_view(), name='list'),
url(r'^(?P<slug>[-\w]+)/$', BlogPostDetailSlugView.as_view(), name='detail'),
]
if settings.DEBUG:
urlpatterns = urlpatterns + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns = urlpatterns + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
admin.py
from django.contrib import admin
from .models import BlogPost
class BlogPostAdmin(admin.ModelAdmin):
list_display = ['__str__', 'slug']
class Meta:
model = BlogPost
admin.site.register(BlogPost, BlogPostAdmin)
blog.html
{% for obj in object_blog %}
<!-- Blog Post -->
<div class="card mb-4 text-white bg-dark">
{% if obj.image %}
<!-- {{MEDIA_URL}} -->
<img class="card-img-top" src="{{ obj.image.url }}" alt="Card image cap">
{% else %}
<h1> No pic </h1>
{% endif %}
<div class="card-body">
<h2 class="card-title">{{ obj.title }}</h2>
<p class="card-text">{{ obj.description|slice:":255" }} ...</p>
Read More →
</div>
<div class="card-footer text-muted">
{{ obj.timestamp }}
Start Bootstrap
</div>
</div>
{% endfor %}
I am using almost the same pattern as I used in different application, where everything works. Few days ago I noticed some kind of strange bahavior from Django side, because it did want to show me images on the website, until I restarted a PC completely. If anyone needs more information / to see some different files, I can provide more. Here are few pictures from my Django admin.
Your two views BlogPostListView and BlogPost_list_view do almost exactly the same thing, I don't know why you have two of them. But note that the first one is the one that is actually used by your URL.
Now, that view is a class-based view that will send a variable called blog_list or object_list to the template. However, the template itself is iterating over a variable called object_blog, which would be sent by the (unused) second view. You should change that to object_list - or, in the view, you could add context_object_name = 'object_blog' (but I don't recommend that).

Django, Can't get delete button to work

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.

Categories

Resources