Django Dropdown populate from database - django

If I pass items to the template through the view, and I want the user to select one of the values that gets submitted to a user's record, I would only have dun a for loop in the template right?
What would that look like?
In the template:
<form method="POST"
<select>
</select>
</form>
Model:
class UserItem(models.Model):
user = models.ForeignKey(User)
item = models.ForeignKey(Item)
class Item(models.Model):
name = models.CharField(max_length = 50)
condition = models.CharField(max_length = 50)
View:
def selectview(request):
item = Item.objects.filter()
form = request.POST
if form.is_valid():
# SAVE
return render_to_response (
'select/item.html',
{'item':item},
context_instance = RequestContext(request)
)

If I understood your need correctly, you can do something like:
<form method="POST">
<select name="item_id">
{% for entry in items %}
<option value="{{ entry.id }}">{{ entry.name }}</option>
{% endfor %}
</select>
</form>
By the way, you should give the name items instead of item, since it's a collection (but it's just a remark ;)).
Doing so, you will have a list of all the items in the database.
Then, in the post, here what you need to do:
def selectview(request):
item = Item.objects.all() # use filter() when you have sth to filter ;)
form = request.POST # you seem to misinterpret the use of form from django and POST data. you should take a look at [Django with forms][1]
# you can remove the preview assignment (form =request.POST)
if request.method == 'POST':
selected_item = get_object_or_404(Item, pk=request.POST.get('item_id'))
# get the user you want (connect for example) in the var "user"
user.item = selected_item
user.save()
# Then, do a redirect for example
return render_to_response ('select/item.html', {'items':item}, context_instance = RequestContext(request),)
Of course, don't forget to include get_object_or_404

Here is a more dry way to do this in 2021:
models.py
from django.db import models
class Country(models.Model):
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class City(models.Model):
country = models.ForeignKey(Country, on_delete=models.CASCADE)
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class Person(models.Model):
name = models.CharField(max_length=100)
birthdate = models.DateField(null=True, blank=True)
country = models.ForeignKey(Country, on_delete=models.SET_NULL, null=True)
city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.name
urls.py
from django.urls import include, path
from . import views
urlpatterns = [
path('', views.PersonListView.as_view(), name='person_changelist'),
path('add/', views.PersonCreateView.as_view(), name='person_add'),
path('<int:pk>/', views.PersonUpdateView.as_view(), name='person_change'),
]
views.py
from django.views.generic import ListView, CreateView, UpdateView
from django.urls import reverse_lazy
from .models import Person
class PersonListView(ListView):
model = Person
context_object_name = 'people'
class PersonCreateView(CreateView):
model = Person
fields = ('name', 'birthdate', 'country', 'city')
success_url = reverse_lazy('person_changelist')
class PersonUpdateView(UpdateView):
model = Person
fields = ('name', 'birthdate', 'country', 'city')
success_url = reverse_lazy('person_changelist')
HTML
{% extends 'base.html' %}
{% block content %}
<h2>Person Form</h2>
<form method="post" novalidate>
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<button type="submit">Save</button>
Nevermind
</form>
{% endblock %}
RESULT:
Reference: https://simpleisbetterthancomplex.com/tutorial/2018/01/29/how-to-implement-dependent-or-chained-dropdown-list-with-django.html

Related

Django filter results on foreign key

I am attempting to display a list of notes that are attached to a project. I can display the individual project the notes are linked to but I am not able to figure out how to display only the notes related to the project.
My models are:
class Project(models.Model):
title = models.CharField(max_length= 200)
description = models.TextField()
def __str__(self):
return self.title
class ProjectNotes(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
date = models.DateField(auto_now_add=True)
project = models.ForeignKey(Project, default=0, blank=True, on_delete=models.CASCADE, related_name='notes')
def __str__(self):
return self.title
The views:
from django.shortcuts import get_object_or_404, render
from django.urls.base import reverse
from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView
from .models import Project, ProjectNotes
class CompanyProjects(ListView):
model = Project
template_name = 'company_accounts/projects.html'
class CompanyProjectsDetailView(DetailView):
model = Project
id = Project.objects.only('id')
template_name = 'company_accounts/project_detail.html'
context_object_name = 'project'
class ProjectNotes(ListView):
model = ProjectNotes
template_name = 'company_accounts/project_notes.html'
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
context['project'] = get_object_or_404(Project, id=self.kwargs.get('pk'))
return context
class ProjectNotesDetailview(DetailView):
model = ProjectNotes
template_name = 'company_accounts/project_note_detail.html'
The template displays the correct project:
{% extends 'base.html' %}
{% block content %}
<h1>Notes</h1>
{{ project }}
{% for note in notes %}
<div class ="projectnotes-entry">
<h2>{{ note.title }}</h2>
<p>{{ note.body }}</p>
</div>
{% endfor %}
{% endblock content %}
So far I have not been able figure out a way to only display the notes related to the specific project.

Django - saving model via a form is not working

I'm having a little problem with the .save() method in Django. For 1 form it works, for the other it doesn't. And I can't find the problem.
views.py
#login_required
def stock_add(request, portfolio_id):
if request.method == 'POST':
print('request.method is ok')
form = StockForm(request.POST)
print('form is ok')
if form.is_valid():
print('form is valid')
stock = form.save(commit=False)
stock.created_by = request.user
stock.portfolio_id = portfolio_id
stock.save()
return redirect('portfolio-overview')
else:
print("nope")
else:
print('else form statement')
form = StockForm()
context = {
'form':form
}
return render(request, 'portfolios/stock-add.html', context)
forms.py
class StockForm(ModelForm):
class Meta:
model = Stock
fields = ['quote', 'amount']
html
{% extends 'core/base.html' %}
{% block content %}
<div class="container">
<h1 class="title">Add Stock</h1>
<form method="POST" action=".">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="button is-primary">Submit</button>
</form>
</div>
{% endblock %}
models
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Portfolio(models.Model):
title = models.CharField(max_length=56)
description = models.TextField(blank=True, null=True, max_length=112)
created_by = models.ForeignKey(User, related_name='portfolios', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = 'Portfolio'
def __str__(self):
return self.title
class Stock(models.Model):
Portfolio = models.ForeignKey(Portfolio, related_name='stocks', on_delete=models.CASCADE)
quote = models.CharField(max_length=10)
amount = models.IntegerField()
created_by = models.ForeignKey(User, related_name='stocks', on_delete=models.CASCADE)
created_at = models.DateField(auto_now_add=True)
def __str__(self):
return self.quote
If you look at the views.py file, when I submit the form, it won't even do print('request.method is ok')
I can add the stock via the admin page.
So I have no clew where to look anymore...
Cheers
When you post a form and need a special url (like your' with an attribute), i like to set action="{% url myview.views.stock_add portfolio_id %}"
action="." will save to the same page without taking care of extra parameters (if needed)
Just pass portfolio_id in the context and that will work
I found the answer, an InteregerField (from models.py) needs a default value.
Either default=None (or another value).
Cheers

Django - How to make an upvote button?

Currently logged in users can upvote x amount of times.
The idea of fixing it is to create a new model called Vote. And it will have foreignkeys for user and product. When someone goes to upvote, you check and see:
is there vote object with this user id and product id, and if there is, you don't allow him to upvote again; and if it is not, then you can go ahead and create that, and just increase total_votes on one.
But actually, i ran into it and cant figure it out and solve.
So, there is my models.py
from django.db import models
from django.contrib.auth.models import User
class Product(models.Model):
title = models.CharField(max_length=255)
pub_date = models.DateTimeField()
body = models.TextField()
url = models.TextField()
image = models.ImageField(upload_to='images/')
icon = models.ImageField(upload_to='images/')
votes_total = models.IntegerField(default=1)
hunter = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
def summary(self):
return self.body[:100]
def pub_date_pretty(self):
return self.pub_date.strftime('%b %e %Y')
class Vote(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
voteproduct = models.ForeignKey(Product, on_delete=models.CASCADE)
And my views.py
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from .models import Product, Vote
from django.utils import timezone
#login_required(login_url="/accounts/signup")
def upvote(request, product_id):
if request.method == 'POST':
product = get_object_or_404(Product, pk=product_id)
product.votes_total += 1
product.save()
return redirect('/products/' + str(product.id))
Updates:
class Vote(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
class Meta:
unique_together(('user', 'product'),)
views.py
if request.method == 'POST':
product = get_object_or_404(Product, pk=product_id)
try:
Vote.objects.create(user=request.user, product=product)
product.votes_total += 1
product.save()
except:
product.save()
return redirect('/products/' + str(product.id))
Also, how should i change my .html file? I really cant understand what is going on. Looking forward to hear from u.
{% for product in products.all %}
<div class="row pt-3">
<div class="col-2" onclick="window.location='{% url 'detail' product.id
%}';" style="cursor: pointer;">
<img src="{{ product.icon.url }}" class="img-fluid" />
</div>
<div class="col-7" onclick="window.location='{% url 'detail' product.id
%}';" style="cursor: pointer;">
<h1>{{ product.title }}</h1>
<p>{{ product.summary }}</p>
</div>
<div class="col-3">
<a href="javascript:{document.getElementById('{% url 'upvote'
product.id %}').submit()}"><button class="btn btn-primary btn-lg btn-
block" name="btn1" value="upvote"><span class="oi oi-caret-top">
</span> Upvote {{ product.votes_total }}</button></a>
</div>
</div>
<form id="get_redirect_url{{ product.id }}" action="{% url 'upvote'
object.id %}" method="POST">
{% csrf_token %}
<input type="hidden" />
</form>
well if i were you i would do it like that :
#step 1 change votes_total from integerfield to manytomany field
##models
class Product(models.Model):
#other fields goes here
votes_total = models.ManyToManyField(User, related_name="votes" ,)
#step 2 ; go to your views.py and copy paste the following :
from django.views.generic import RedirectView
class ProductVoteToggle(RedirectView):
def get_redirect_url(self, *args ,**kwargs):
obj = get_object_or_404(Product, pk=self.kwargs['pk'])
url_ = obj.get_absolute_url()
user = self.request.user
if user.is_authenticated():
if user in obj.votes_total.all():
# you could remove the user if double upvote or display a message or what ever you want here
obj.votes_total.remove(user)
else:
obj.votes_total.add(user)
return url_
#step 3 : go to urls.py and paste add the following :
urlpatterns = [
#other urls here
path('vote/<int:pk>',ProductVoteToggle.as_view() , name="upvote"),
]
#in your template remove that form and paste the following code :
<a href="{% url 'upvote' product.id %}>Click to vote<a/>
when you are done it should work if it didn't past the error here and i'll let you know what you are doing wrong
Your code doesn't use Vote at all. In upvote(), first try to create a Vote for the user and product:
try:
Vote.objects.create(user=request.user, product=product)
# consider using the name product instead of voteproduct
If it succeeds, increment the counter. If it fails, notify the user that they have voted already.
Obviously, you need a unique constraint in Vote:
class Meta:
unique_together = ('user', 'product')

csrf token not showing input fields - Django

I am new to django. am using django==1.11
am trying to create a form which inputs details of users.
my
views.py
from django.shortcuts import render, render_to_response, redirect
from django.template import loader, Template, Context, RequestContext
from forms import UserForm
from django.http import HttpResponse, HttpResponseRedirect
from django.views.decorators import csrf
def action(request):
if request.POST:
form = UserForm(data = request.POST)
if form.is_valid():
form.save(commit = False)
return HTTPResponseRedirect('/rfid/index')
else:
form = UserForm()
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('reg.html', args)
forms.py
from django import forms
from models import UserDetails
class UserForm(forms.ModelForm):
class Meta:
model = UserDetails
fields = '__all__'
reg.html
{% extends "rfid/header.html" %}
{% block content %}
<div class="container">
<form action = "/" method="post">{% csrf_token %}
<ul>
{{ form.as_ul }}
</ul>
<input type="submit" name="submit" class="btn btn-default" value="Add User">
</form>
</div>
{% include "rfid/includes/htmlsnippet.html" %}
{% endblock %}
models.py
from django.db import models
# Create your models here.
class UserDetails(models.Model):
GENDER_CHOICES = (('M', 'Male'), ('F', 'Female'))
user_id = models.IntegerField(primary_key = True)
name = models.TextField(max_length = 50)
gender = models.CharField(max_length = 1, choices = GENDER_CHOICES)
dob = models.DateTimeField()
address = models.TextField(max_length = 200)
phone = models.IntegerField()
email = models.EmailField(max_length=254)
photo_url = models.CharField(max_length = 200)
def __str__(self):
return self.name
But it is only showing the submit button. Model-based fields are not displaying. I had gone through some Questions here but was not able to trace out what was the problem. can anyone help me out.
Hope all required details are given. pls, ask if I miss anything.
regards.
Check out the line with form.save(commit=False).
Except you want to give that line a name and later save the name like saved_form=form.save(commit=False) then saved_form.safe, then the commit=False line isn't necessary. I don't know if that is the problem, but will check and revert

Creating forms from models

i'm moving my first steps into Django and i'm tryin' to follow the tutorial at this link: https://docs.djangoproject.com/en/dev/topics/forms/modelforms/
but i can't get a form. It just returns a white page!
Can someone explain if i'm missing something?
my models.py:
from django.db import models
from django.forms import ModelForm
class UserProfile(models.Model):
name = models.CharField(max_length=30)
surname = models.CharField(max_length=30)
email = models.EmailField()
tel = models.CharField(max_length=30, null=True, blank=True)
def __unicode__(self):
return '%s %s' % (self.surname, self.name)
class Ad(models.Model):
title = models.CharField(max_length=50)
descr = models.TextField()
city = models.CharField(max_length=30)
price = models.FloatField(null=True, blank=True)
img = models.ImageField(upload_to='./uploaded_imgs', null=True, blank=True)
dateIn = models.DateField(auto_now_add=True)
dateExp = models.DateField(auto_now_add=True)
codC = models.ForeignKey('Cat')
codU = models.ForeignKey('UserProfile')
def __unicode__(self):
return '%s - %s' % (self.title, self.dateIn)
class Cat(models.Model):
cat = models.CharField(max_length=35, primary_key=True)
def __unicode__(self):
return self.cat
my forms.py:
from django import forms
class newAdForm(forms.Form):
title = forms.CharField(max_length=50)
descr = forms.CharField(widget=forms.Textarea)
city = forms.CharField(max_length=30)
price = forms.FloatField(required=False)
img = forms.ImageField(required=False)
dateIn = forms.DateField(auto_now_add=True)
dateExp = forms.DateField(auto_now_add=True)
codC = forms.ModelChoiceField(Cat)
codU = forms.ModelChoiceField(UserProfile)
my views.py:
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.template import RequestContext
from django.http import HttpResponse
from django import forms
from models import *
from django.forms import *
from django.forms.models import modelformset_factory
[...]
def newAd(request):
newAdFormSet = modelformset_factory(Ad)
if request.method == 'POST':
formset = newAdFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
return render_to_response('conf.html', {'state':'Your ad has been successfull created.'}, context_instance = RequestContext(request),)
else:
formset = newAdFormSet()
return render_to_response('ad_form.html', context_instance = RequestContext(request),)
my ad_form_auto.html template:
{% extends "base.html" %}
{% block title %}Ads insertion form{% endblock %}
{% block content %}
{% if error_message %}
<p><strong>{{ error_message }}</strong></p>
{% endif %}
<form method="post" action="">
{{ formset }}
</form>
{% endblock %}
Thanks a lot! This community looks just awesome! :)
You're not passing the form to the template - at present your 'formset' variable containing the form isn't included in the datadict being passed to the view.
return render_to_response('ad_form.html', context_instance = RequestContext(request),)
Should include the data (see render_to_response() docs) here I've renamed the form in your data and to your template as 'form' for ease of nomenclature:
return render_to_response('ad_form.html',
{'form':formset},
context_instance=RequestContext(request))
Then, in your template (see forms in templates docs) replace {{formset}} with {{form.as_p}}. Also add a submit button to the form.
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>