Django: Auto suggest in text field - python

I'm trying to work out how to have suggestions in a text field using Django (1.11). I've been going through the documentation of autocomplete-light but so far I've not been able to figure out my use case. The documentation on that package is not easy to understand for a total noob :)
I want a text field that gives suggestions as you type, were the suggestions come from the database.
E.g. if it's a list of food items the user types in 'C' and it suggest Chicken and Crisps as they have been entered by someone earlier. I also want the user to be able to enter Cheese even though it hasn't been entered before.
The suggestion "algorithm" just has to check if what has been entered matches the first characters of already existing items.
Here is a boiled down version of the django project:
urls.py
from django.conf.urls import url
from django.contrib import admin
from testapp.views import TestView
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'$',TestView.as_view())
]
models.py
from django.db import models
class TestModel(models.Model):
name = models.CharField(max_length=120)
def __str__(self):
return self.name
forms.py
from django import forms
from .models import TestModel
class TestFormClass(forms.ModelForm):
class Meta:
model = TestModel
fields = ('__all__')
views.py
from django.shortcuts import render
from django.views.generic import CreateView
from .forms import TestFormClass
class TestView(CreateView):
form_class = TestFormClass
template_name = 'template.html'
success_url = "/"
template.html
<html>
<header><title>This is title</title></header>
<body>
Enter something <br>
{% block content %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{% endblock %}
</body>
</html>
I'm hoping someone has a relatively simple solution to add the this code, at the moment I'm not worried about authentication or anything, just looking for a basic solution.

You can make use of django-autocomplete-light

Related

Django Question 'ModelChoiceField' object has no attribute 'use_required_attribute'

Dears,
I met a problem in Django.
There is an error about 'ModelChoiceField' object has no attribute 'use_required_attribute' and I don't know where I made mistake.
My goal is to make my submit customizing form but I couldn't understand how CBV in Django can reach this goal, so I went back to use forms.py and FBV in Django. But my fields in form model have foreign keys to refer other models.
I used forms.ModelChoiceField and expected to solve foreign key problem but it doesn't work and show this error.
Thank you for reading and hope someone can help me to solve it.
Here are my code:
forms.py
from django import forms
from .models import Case
from school_app.models import School
from student_app.models import Student
class CaseModelForm(forms.ModelForm):
class Meta:
model = Case
fields='__all__'
widgets = {
'name' : forms.ModelChoiceField(queryset=Student.objects.all()),
'phone' : forms.TextInput(),
'school' :forms.ModelChoiceField(queryset=School.objects.all())
}
models.py
from django.db import models
from django.urls import reverse
import datetime,time
from school_app.models import School
from student_app.models import Student
# Create your models here.
class Case(models.Model):
name=models.ForeignKey(Student,related_name='case_student_name',on_delete=models.CASCADE,verbose_name="姓名")
phone=models.CharField(verbose_name="電話",blank=False,max_length=256)
school=school=models.ForeignKey(School,related_name='case_school',on_delete=models.CASCADE,verbose_name="學校")
views.py
def CaseFormView(request):
print("CaseForm")
form_cus = CaseModelForm()
if request.method == "POST":
form = CaseModelForm(request.POST)
if form.is_valid():
form.save()
return redirect("/")
context={
'form_cus': form_cus
}
return render(request, 'case_app/case_form.html',context)
urls.py
from student_app import views
from django.urls import path
app_name = 'student_app'
urlpatterns=[
path('', views.StudentListView.as_view(),name='list'),
path('<int:pk>/', views.StudentDetailView.as_view(), name='detail'),
path('create/',views.StudentCreateView.as_view(), name='create')]
case_form.html
<form method="post">
{% csrf_token %}
<div class="form-group">
<div class="form-group col-md-6">
<label>{{form_cus.name.label}}</label>
{{form_cus.name}}
</div>
<div class="form-group col-md-6">
<label>{{form_cus.school.label}}</label>
{{form_cus.school}}
</div>
{{form_cus}}
<input type="submit" class="btn btn-primary" value="提交">
</div>
{% if not form.instance.pk %}
<a class='btn btn-secondary' href="{% url 'case_app:list' %}">取消</a>
{% else %}
<a class='btn btn-secondary' href="{% url 'case_app:detail' pk=form.instance.pk %}">取消</a>
{% endif %}
</form>
Thank you!
A ModelChoiceField is not a widget, it is a form field, you thus can implement this as:
from django import forms
from .models import Case
from school_app.models import School
from student_app.models import Student
class CaseModelForm(forms.ModelForm):
school = forms.ModelChoiceField(queryset=School.objects.all())
name = forms.ModelChoiceField(queryset=Student.objects.all())
class Meta:
model = Case
fields='__all__'
widgets = {
'phone' : forms.TextInput(),
}
Since school and name are however ForeignKeys in your Case model, you do not need to specify these: we can implement the CaseModelForm with:
from django import forms
from .models import Case
from school_app.models import School
from student_app.models import Student
class CaseModelForm(forms.ModelForm):
# no school/name field
class Meta:
model = Case
fields='__all__'
widgets = {
'phone' : forms.TextInput(),
}

Model Form not displaying

I am using modelform for a model department is not working. (BTW,I have a custom user model also in users app of same project). All I am getting is a 'Test up' button in the html output. Also, Change E-mail and Signout are displaying may be consequence to usage of allauth in middleware. I don't know whether allauth is interfering with this or not (hope not).I have added department model to admin but there is some strange thing appearing in admin described below
I have tried to debug with many ways.
Here is the model
from django.db import models
from django.conf import settings
from users.models import User,UserProfile
# Create your models here.
class department(models.Model):
Dept_CHOICES = (
(1, 'Inventory'),
(2, 'Dispatch'),
)
dept_type = models.PositiveSmallIntegerField(choices=Dept_CHOICES,default=1,unique=False),
HOD = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,),
Invest = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,),
def __str__(self):
return self.dept_type
Here is the view code
def add_model(request):
if request.method == "POST":
form = departForm(request.POST)
if form.is_valid():
model_instance = form.save(commit=False)
model_instance.save()
return redirect('/')
else:
form = departForm()
return render(request, "test.html", {'form': form})
base.html
<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<main>
{% block content %}
{% endblock %}
</main>
</body>
</html>
test.html
{% extends 'base.html' %}
{% block content %}
<div class = "container">
<h2>Sign up</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Test up</button>
</form>
</div>
{% endblock %}
admin.py
from core1.models import department
# Register your models here.
#admin.register(department)
class DepartmentAdmin(admin.ModelAdmin):
pass
output in admin of the site is a single field with strange name of
<django.db.models.fields.PositiveSmallIntegerField>
For additional info, I am using class view and function view in the same views.py file. Hope it is allowed.
I expect the form to be displayed
Tried form.as_p but getting
<<bound method BaseForm.as_p of <departForm bound=False, valid=False, fields=()>>
Tried form.valid
<bound method BaseForm.is_valid of <departForm bound=False, valid=False, fields=()>>
Solved on my own !
I checked Admin site. There is no department model displaying. This means either I am not migrating properly or my department model has an issue
My department model has all fields ending with a , (comma). Same removed and made the model more robust and without error.
Removed all migrations and done fresh migrate
Modified Admin as follows
# Register your models here.
class departmentadmin(admin.ModelAdmin):
fields = ['HOD', 'Investigator', 'dept_type']
list_display = ('HOD','Investigator','dept_type')
pass
admin.site.register(department, departmentadmin)
Now admin also displaying dpartment and form also displaying departments with required out put..

Trouble Getting User Input in Django

I'm newbie and trying to do something pretty basic after reading the Django Doc Project Documentation, but can't seem to figure it out. I'm getting a user's name with a POST and trying to GET it and display it on the same page. I'm getting an error: hello() missing 1 required positional argument: 'greeting_id'
I'm using Django 2 and wondering if it could be something with the routing? I'm not exactly sure as I'm very new to MVC and Django.
Any help in the right direction would be greatly appreciated.
Here's my code so far:
Views.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import Greeting
# create hello view
def hello(request, greeting_id):
if request.method == 'POST':
if request.POST['firstname']:
greeting = models.Greeting()
greeting.firstname = request.POST['firstname']
greeting.save()
obj = models.Greeting.objects.get(pk=greeting_id)
context = {
'object': obj
}
return render(request, 'greetings/home.html', context)
return render(request, 'greetings/home.html')
Models.py
from django.db import models
# Create your models here.
class Greeting(models.Model):
firstname = models.CharField(max_length=100)
# returns post object in admin interface
def __str__(self):
return self.firstname
urls.py
from django.contrib import admin
from django.urls import path
from greetings import views #import greetings views into the url file
urlpatterns = [
path('admin/', admin.site.urls),
path('hello/', views.hello, name='hello'),
]
home.html
{% block content %}
<h2>Let's Say Hello!</h2>
<br/>
<br/>
<div>
<form method="POST" action="{% url 'hello' %}">
{% csrf_token %}
Enter your first name:
<br />
<input type="text" name="firstname" />
<br />
<br />
<input type="submit">
</form>
{{ object.firstname }}
</div>
{% endblock %}
Your view "hello" requires an parameter "greeting_id"
def hello(request, greeting_id):
These parameters are passed from the url routing to the view, for the view to work your url would have to look like this
path('hello/<int:greeting_id>/', views.hello, name='hello'),
Where is greeting_id supposed to be coming from?

Django - proper way to implement threaded comments

I'm developing a blog site using Django. My site will allow users to comment on any of my blog posts and also reply to each other and will be displayed using a 'threaded comments' structure (I haven't started user functionality yet, just comments). I've got the threaded comments to work properly using django-mptt (at least, for now), but I have NO CLUE if the route or steps I'm taking are in the right direction. Almost all the tutorials I've gone through only scratch the surface when it comes to comments and doesn't talk about threaded comments in django. I want some experienced/professional advice on what I might be doing wrong and what I could be doing better. The last thing I want is to find out there was a much more acceptable way of going about, after hours of work put in.
So, here is a list of what I need clarity on:
django-mptt:
I chose this because I can afford slower write times. My site will have more reads than writes. Is this option okay for my case? Is there a better alternative I don't know about?
What should I do if my site does end up having lots of commenting activity? What could I do to optimize tree restructuring? Or would I be better off switching to an adjacency list?
My MPTT comment model has a ForeignKey referenced to itself (for replies). Is this the right way? Or should I create a separate reply model?
The way I insert a reply to another user's comment in the tree is using a hidden input within the form that's within the mptt recursive template tags, and return the input value (which is the id of the comment that the reply is for) and set the parent of the reply to that input value. Is this an accepted method?
Multiple forms on one HTML page
I have two forms on my blog post HTML page. One to comment on the blog post, and one to reply to a user's comment. Is this accepted? Or should I create different URLs and view functions for different forms? I did it this way because I wanted a Reddit style commenting system. I don't want it to have to go to a different page to comment or reply.
If a user comments on my blog post, the hidden input value within the reply form returns nothing, therefore I get an error when trying to assign it to a variable in the views.py function. I used a try/except block to fix it. Is there a better way around this?
I'm sorry if these are noob questions and for my post being so long. I just want to do things the best way possible using realistic solutions for a beginner. Any feedback would help. Thank you! Here's my code for my blog app.
models.py
from django.db import models
from mptt.models import MPTTModel, TreeForeignKey
class Post(models.Model):
"""Blog post"""
title = models.CharField(max_length=200)
body = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.body[:50] + '...'
class Comment(MPTTModel):
"""User comment"""
post = models.ForeignKey(Post, related_name='comments',on_delete=models.CASCADE)
parent = TreeForeignKey('self', null=True, blank=True, related_name='children',db_index=True, on_delete=models.CASCADE)
user_comment = models.CharField(max_length=500, unique=True)
date_added = models.DateTimeField(auto_now_add=True)
# approved = models.BooleanField(default=False)
class MPTTMeta:
order_insertion_by = ['date_added']
def __str__(self):
return self.user_comment[:20]
'approved' is commented out because I get a 'no such column: approved' error for some weird reason.
forms.py
from django import forms
from .models import Post, Comment
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['user_comment']
views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from .models import Post
from .forms import CommentForm
def posts(request):
"""Show all blog posts"""
posts = Post.objects.order_by('-date_added')
context = {
'posts': posts
}
return render(request, 'posts/posts.html', context)
def post(request, post_id):
"""Show single blog post"""
post = Post.objects.get(id=post_id)
comments = post.comments.all()
if request.method != 'POST':
comment_form = CommentForm()
else:
comment_form = CommentForm(data=request.POST)
try:
parent_id = request.POST['comment_id']
except:
pass
if comment_form.is_valid():
comment = comment_form.save(commit=False)
comment.post = post
comment.parent = comments.get(id=parent_id)
comment.save()
return HttpResponseRedirect(reverse('posts:post', args=[post_id]))
context = {
'post': post,
'comment_form': comment_form,
'comments': comments,
}
return render(request, 'posts/post.html', context)
post.html
{% extends 'posts/base.html' %}
{% block blog_content %}
<h1>Post page!</h1>
<h3>{{ post.title }}</h3>
<h4>{{ post.date_added }}</h4>
<p>{{ post.body }}</p>
<form method="post" action="{% url 'posts:post' post.id %}">
{% csrf_token %}
{{ comment_form.as_p }}
<button type="submit">Add comment</button>
</form>
{% load mptt_tags %}
{% recursetree comments %}
<h5>{{ node.date_added }}</h5>
<p>{{ node.user_comment }}</p>
<form method="post" action="{% url 'posts:post' post.id %}">
{% csrf_token %}
{{ comment_form.as_p }}
<input type="hidden" name="comment_id" value="{{ node.id }}">
<button type="submit">Reply</button>
</form>
{% if not node.is_leaf_node %}
<div style="padding-left: 20px">
{{ children }}
</div>
{% endif %}
{% endrecursetree %}
{% endblock %}
urls.py
from django.urls import path
from . import views
app_name = 'posts'
urlpatterns = [
path('posts/', views.posts, name='posts'),
path('posts/<int:post_id>/', views.post, name='post'),
]
MPTT trees are great for getting a list of subnodes or node counts. They are costly for adding/inserting nodes and the cost increases linearly with the size of the three. They are designed to fit tree data into relational databases. Also, don't get fooled by "I'll have much more reads than writes". Ideally, most of the reads should hit a cache, not the database under it.
Why not skip the relational database and go with a NoSQL database that can natively store trees? There are easy integrations for Django and pretty much every NoSQL database you can thing about.

DetailView not showing data

I am trying to display a ListView of items that when clicked opens the respective DetailView for that item. This is a pretty straightforward thing to do in Django, but I'm running into some trouble with it.
I have successfully created a ListView, but I can't get the DetailView to display the information for each item.
I am building a password safe. The ListView lists all the passwords saved, and the DetailView is the view/edit page for each password. And yes, I realize actually putting a password safe on the internet is a terrible idea, it's just a test project :)
My PasswordSafe class:
class PasswordSafe(models.Model):
user = models.OneToOneField(User)
pwWebsite = models.CharField(max_length=30)
pwUsername = models.CharField(max_length=30)
pwEmail = models.CharField(max_length=30)
pwPassword = models.CharField(max_length=30)
def __unicode__(self): # __unicode__ on Python 2, __str__ on Python 3
return self.pwWebsite
User.passwordSafe = property(lambda u: PasswordSafe.objects.get_or_create(user=u)[0])
My urls.py:
from django.conf.urls import patterns, include, url
from django.views.generic import ListView, DetailView
from models import PasswordSafe
urlpatterns = [
url(r'^passwordSafe/$', ListView.as_view(queryset=PasswordSafe.objects.all().order_by('-pwWebsite')[:10], template_name = 'userprofile/passwordSafe_list.html')),
url(r'^passwordSafe/(?P<pk>\d+)/$', DetailView.as_view(model=PasswordSafe, template_name='userprofile/passwordSafe.html')),
]
I use the following code successfully in my ListView template (passwordSafe_list.html):
{% for passwordSafe in object_list %}
<h2>{{ passwordSafe.pwWebsite }}</h2>
{% endfor %}
However, when I try to use the passwordSafe data in my Detailview (the passwordSafe.html template), nothing shows up. I use the following code to try and change the title:
<title>{% block title %} | Edit {{ passwordSafe.pwWebsite }} Password{% endblock %}</title>
This should show a title something like "Password Safe | Edit Google Password", but passwordSafe.pwWebsite returns with nothing. Am I doing something wrong in trying to reference passwordSafe from this template? I know I haven't passed a query set like I did with the ListView, but I'm not sure if that's part of the problem or not.
In the DetailView, Django uses the model name in lowercase, by default, if you haven't set context_object_name.
{{ passwordsafe.pwWebsite }}

Categories

Resources