How to set variable maxValue in django forms - django

I'm writing a code in django framework for a sales website and the number of available pieces of a certain merchandise is limited.
to obtain the number of remaining products I have to call a certain function.
Now I wanted to ask if there's any way to call this function in the models.py or forms.py modules or any other way to set this limit.
This is my view module:
from django.http.response import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from .forms import orderForm
from regpage.models import User
from django.views import View
class orderView(View):
def get(self, request):
form = orderForm()
return render(request, "dashboard/order.html", {'form': form,})
This is my forms module:
from django import forms
from .models import Order
class orderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['productCount']
This is my models module:
from django.db import models
from django.db.models.enums import Choices
from regpage.models import User
from django.core import validators
from django.core.validators import EmailValidator, MaxValueValidator, MinValueValidator
class Order(models.Model):
userID = models.ForeignKey(User, on_delete=models.CASCADE)
productCount = models.PositiveSmallIntegerField() #THE LIMITED FIELD
This is my html file:
{% extends 'dashboard.html' %}
{% block dashTitle %}
Order
{% endblock dashTitle %}
{% block dashContent %}
<p style="text-align:center;font-size:30px;"><b> Order Page </b> </p>
<form style="text-align:center;font-size:25px" method="POST">
{% csrf_token %}
{% for field in form %}
<div class="form-control {% if field.errors %}errors{% endif %}">
{{ field.label_tag }}
{{ field }}
{{ field.errors }}
</div>
<br>
{% endfor %}
<br>
<button type="submit">Order</button>
</form>
{% endblock dashContent %}
There's only one product in this website and one function should be called to obtain the number of remaining products.

Give this a try
class orderForm(forms.ModelForm):
quantity = forms.IntegerField(widget=forms.TextInput(
attrs={
'min':0,
'value':0,
'type':'number',
}))
class Meta:
model = Order
fields = ('__all__')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['productCount'].widget.attrs.update(
{'max': self.instance.productCount},
)

Related

Django POST or GET

I have a page for teachers to input the marks and registration number of the students..
After input, it gets stored in the database and the students can fill a form which asks for D.O.B and registration number and get's the marks based on that particular registration from the database..
But when I use post request for the students, it shows form is invalid and says that, the registration number already exists..
My views.py:
from django.shortcuts import render
from django.views.generic.list import ListView
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
from .models import Mark
from django.contrib.auth.views import LoginView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.edit import FormView
from .forms import ViewResultForm, AddResultForm
from django.contrib import messages
class ViewResultFormView(FormView):
template_name = 'main/home.html'
form_class = ViewResultForm
success_url= 'result'
def form_valid(self, form):
global registration_number
global dob
registration_number = form.cleaned_data['registration_number']
dob = form.cleaned_data['dob']
return super(ViewResultFormView, self).form_valid(form)
class MarkListView(ListView):
model = Mark
template_name = "main/result.html"
context_object_name = 'result'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['result'] = context['result'].get(registration_number=registration_number, dob=dob)
return context
class MarkCreateView(LoginRequiredMixin, CreateView):
model = Mark
template_name = "main/add.html"
form_class = AddResultForm
def form_valid(self, form):
total_10th = ((form.cleaned_data['class_10_sub_1'] + form.cleaned_data['class_10_sub_2'] + form.cleaned_data['class_10_sub_3'])/300)*30
total_11th = ((form.cleaned_data['class_11_English'] + form.cleaned_data['class_11_Maths'] +form.cleaned_data['class_11_Physics'] +form.cleaned_data['class_11_Chemistry'] +form.cleaned_data['class_11_Comp_Bio'])/500) * 30
total_12th = ((form.cleaned_data['class_12_English'] + form.cleaned_data['class_12_Physics'] +form.cleaned_data['class_12_Chemistry'] +form.cleaned_data['class_12_Maths']+ form.cleaned_data['class_12_Comp_Bio'] + form.cleaned_data['class_12_practicals_Physics'] + form.cleaned_data['class_12_practicals_Chemistry'] + form.cleaned_data['class_12_practicals_Comp_Bio'] )/500)*40
result = total_10th + total_11th + total_12th
total = form.save(commit=False)
total.teacher_name = self.request.user
total.result = result
total.save()
message = messages.success(self.request, f'Result added successfully')
return super().form_valid(form)
class CustomLoginView(LoginView):
template_name = 'main/login.html'
fields = '__all__'
redirect_authenticated_user = True
def get_success_url(self):
return reverse_lazy('add')
home.html:
{% extends 'main/base.html' %}
{%load crispy_forms_tags %}
{% block content %}
<div class="container mt-5 card shadow p-3 mb-5 bg-white rounded">
<legend>Enter your credentials</legend>
<form method="POST">
{% csrf_token %}
{{ form | crispy }}
<input class='btn btn-outline-info' type="submit" value="Submit">
</form>
</div>
{% endblock content %}
result.html:
{% extends 'main/base.html' %}
{% block content %}
<div class="container">
{{ result.student_name }}
<br>
{{ result.dob }}
<br>
{{ result.result }} %
</div>
{% endblock content %}
So once the teacher enters the marks of the student, I calculate the results and store it in the database.. But bcz the teacher has registered a particular registration number, it shows form is invalid when a student tries to enter the same registration number in the form.. I want the registration number to be unique..
So if I have to use GET in home.html, how to access the values of the form?
You should rewrite your ViewResultFormView.form_valid, because you do not want form.save() to be called in the super call. You should retrieve registration_number and dob from the form and then fill a context for the template with a results of the corresponding student.
Also I do not understand what are those global hacks for? If you need to store that info for a several site pages, then you should implement your own authentication for students which will store their auth tokens/cookies somewhere, and then use that authentication info to allow/deny access to certain pages.

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.

Django: How to save data to ManyToManyField

Your help will be nice for me. Here are that codes:
models.py:
from django.db import models
class TagModel(models.Model):
tag = models.CharField(max_length=50)
def __str__(self):
return self.tag
class MyModel(models.Model):
title = models.CharField(max_length=50)
tag = models.ManyToManyField(TagModel)
forms.py:
from django import forms
from .models import *
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = '__all__'
views.py:
from django.shortcuts import render, get_object_or_404, redirect
from .models import *
from .forms import *
def MyWriteView(request):
if request.method == "POST":
mywriteform = MyForm(request.POST)
if mywriteform.is_valid():
confirmform = mywriteform.save(commit=False)
confirmform.save()
return redirect('MyDetail', pk=confirmform.pk)
else:
mywriteform = MyForm()
return render(request, 'form.html', {'mywriteform': mywriteform})
form.html(1st trial):
<form method="post">
{% csrf_token %}
{{ mywriteform }}
<button type="submit">Save</button>
</form>
form.html(2nd trial):
<form method="post">
{% csrf_token %}
{{ mywriteform.title }}
<select name="tags" required="" id="id_tags" multiple="">
{% for taglist in mywriteform.tags %}
<option value="{{taglist.id}}">{{taglist}}</option>
{% endfor %}
</select>
<button type="submit">Save</button>
</form>
I am trying to add tags on my post. I made a simple manytomany tagging blog but it does not work. I submitted a post by clicking the save button, and the title was saved, but the tag was not. In the admin, it worked well.
Thank you in advance.
update the code like this
if mywriteform.is_valid():
confirmform = mywriteform.save(commit=False)
confirmform.save()
mywriteform.save_m2m()
return redirect('MyDetail', pk=confirmform.pk)
for more details Refer here

Django - how to transfer user input from views.py to models.py?

I am trying to create a Django app that allows a user to select a file name from a drop down menu and upload the file. Regardless of what the user has named their file, I will receive that file saved as whatever they selected on the drop down plus the date. I cannot seem to get my drop downs to show. Hours of reading the documentation, multiple stack overflow posts, and trial and error have not helped. * Does anyone know how to get the user-selected drop down value from views.py to models.py to be inserted into the uploaded file's path? *
On another note, I am sure there are other issues with my code, being a Django newb, so please point them out if you see them.
models.py
from django.db import models
from datetime import datetime
import os
def update_filename(instance, filename):
path = "documents/"
format = '{0}_{1}.csv'.format(vc, datetime.today().strftime('%Y%m%d'))
#note that vc is defined in views.py but I am not sure how to transfer this to models.py
#*************************************************************
return os.path.join(path, format)
class Document(models.Model):
docfile = models.FileField(upload_to= update_filename) #/%Y/%m/%d')
#value_chains = (('coffee', 'coffee'),('tea', 'tea'),)
dropdown = models.CharField(max_length=20, choices=(('coffee', 'coffee'),('tea', 'tea'),))
forms.py
from django import forms
from .models import Document
def validate_file_extension(value):
if not value.name.endswith('.csv'):
raise forms.ValidationError("Only CSV file is accepted")
class DocumentForm(forms.ModelForm):
docfile = forms.FileField(label='Select a file', validators=[validate_file_extension])
value_chains = (('coffee', 'coffee'),('tea', 'tea'),)
dropdown = forms.ChoiceField(choices=value_chains, required=True)
class Meta:
model = Document
fields = ['dropdown']
views.py
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.views.generic.edit import CreateView
from .models import Document
from .forms import DocumentForm
def list(request):
# Handle file upload
if request.method == 'POST':
#bind the data to the form
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
#**** vc is defined here ************************************
vc = form.cleaned_data['dropdown']
newdoc = Document(docfile = request.FILES['docfile'])
newdoc.save()
# Redirect to the document list after POST
return HttpResponseRedirect(reverse('file_upload_app.views.list'))
# if a GET (or any other method) we'll create a blank form:
else:
form = DocumentForm() # A empty, unbound form. This is what we can expect to happen the first time we visit the URL.
# Load documents for the list page
documents = Document.objects.all()
# Render list page with the documents and the form
return render_to_response(
'file_upload_app/list.html',
{'documents': documents, 'form': form},
context_instance=RequestContext(request)
)
list.html
<form action="{% url "list" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.dropdown }}
<p>
<h6>
Note: the uploaded file must be in
<b>.CSV</b>
format and contain a column labeled "A" which contains
<em>only</em>
numbers.
</h6>
</p>
<p>{{ form.non_field_errors }}</p>
<p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
<p>
{{ form.docfile.errors }}
{{ form.docfile }}
</p>
<p><input type="submit" value="Upload"/></p>
</form>
<!-- List of uploaded documents -->
<p>
{% if documents %}
<div class="col-sm-12" align="center" >
<ul>
<p>Files on server:</p>
{% for document in documents %}
<li>{{ document.docfile.name }}</li>
{% endfor %}
</ul>
</div>
{% else %}
<div class="col-sm-12" align="center" >
<p>No documents.</p>
</div>
I recommend you use Djano's CreateView for your view. In your case you would have
Class UploadDocumentView(CreateView):
model = Document
When you click submit on your form, and you have the action pointing to the correct view, it will create a new Document with the fields you provided.
Your template should have this in it, the url should be the name you gave your url. I recommend against using "list" as your url because that is a special name in python and Django has it's own concept of ListView.
<form id="upload_document" method="POST" action="{% url 'document:upload' %}">
{{ form }}
<input class="btn btn-primary" id="upload_document_button" type="submit" value="Upload Document"/>
</form>
Sometimes seeing a working example is useful. The one below uses Django's UpdateView. The UpdateView will use the get_object method to determine which object in the database to modify. It knows what model to look at because it is set to model = UserProfile, and it knows what values to save because you set them in your form.
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE,
primary_key=True)
company_identifier = models.CharField(max_length=5, blank=False)
employee_id = models.CharField(max_length=20, null=True, blank=False)
forms.py
def get_company_choices():
company_list = [('','-------')]
companies = models.Company.objects.values_list('id', 'name').order_by('name')
company_list = list(chain(company_list, companies))
return company_list
class EmployerForm(forms.ModelForm):
employee_id_confirm = forms.CharField(label="Confirm Employee ID", required=True)
company_identifier = forms.ChoiceField(choices=get_company_choices, label="Company")
class Meta:
model = models.UserProfile
fields = ('company_identifier', 'employee_id')
labels = {
'employee_id': "Employee ID",
}
views.py
#method_decorator(login_required, name='dispatch')
class EmploymentUpdate(SuccessMessageMixin, UpdateView):
model = UserProfile
template_name = 'employee/update_employment.html'
form_class = forms.EmployerForm
success_url = reverse_lazy('employee:home')
success_message = "Employment Updated."
def get_object(self):
return self.model.objects.get(pk=self.request.user.userprofile.pk)
I found the solution, denoted by the **** below:
models.py:
from django.db import models
from datetime import datetime
import os
value_chains = (
('coffee', 'coffee'),
('tea', 'tea'),
)
def update_filename(instance, filename):
path = "documents/"
#*************************************************************
#use instance to access the instance of Document's CharField function, which is defined below
format = '{0}_{1}.csv'.format(instance.dropdown, datetime.today().strftime('%Y%m%d'))
#*************************************************************
return os.path.join(path, format)
class Document(models.Model):
docfile = models.FileField(upload_to= update_filename)
dropdown = models.CharField(max_length=20, choices=value_chains)
class Meta:
permissions = (("access_file_upload_app", "Access file upload tool."),)
views.py:
from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
from django.conf import settings
from .models import Document
from .forms import DocumentForm
#login_required
def doc_upload_view(request):
if request.user.has_perm('file_upload_app.access_file_upload_app') and settings.VC_ENABLED == 'Y':
# Handle file upload
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
#********************************************************
# make sure to pass the dropdown value to the Document call:
newdoc = Document(docfile = request.FILES['docfile'], dropdown = form.cleaned_data['dropdown'])
#********************************************************
newdoc.save()
# Redirect to the document list after POST
return HttpResponseRedirect(reverse('file_upload_app.views.doc_upload_view'))
else:
form = DocumentForm() # An empty, unbound form
# Load documents for the list page
documents = Document.objects.all()
# Render list page with the documents and the form
return render_to_response(
'file_upload_app/doc_upload_view.html',
{'documents': documents, 'form': form},
context_instance=RequestContext(request)
)
else:
return redirect('/home/')
forms.py:
from django import forms
from .models import Document
def validate_file_extension(value):
if not value.name.endswith('.csv'):
raise forms.ValidationError("Only CSV file is accepted")
class DocumentForm(forms.ModelForm):
value_chains = (('coffee', 'coffee'),('tea', 'tea'),)
docfile = forms.FileField(label='Select a file', validators=[validate_file_extension])
dropdown = forms.ChoiceField(choices=value_chains, required=True )
class Meta:
model = Document
fields = ('dropdown',)
doc_upload_view.html:
<!-- Upload form. Note enctype attribute! -->
<form action="{% url "doc_upload_view" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.dropdown }}
<p>{{ form.non_field_errors }}</p>
<p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
<p>
{{ form.docfile.errors }}
{{ form.docfile }}
</p>
<p><input type="submit" value="Upload"/></p>
</form>
<!-- List of uploaded documents -->
<p class="top-space">
{% if documents %}
<div class="col-sm-12" align="center" >
<ul>
<p>Files on server:</p>
{% for document in documents %}
<li>{{ document.docfile.name }}</li>
{% endfor %}
</ul>
</div>
{% else %}
<div class="col-sm-12" align="center" >
<p>No documents.</p>
</div>
{% endif %}
</p>

Django, how to do CRUD with django-mptt?

How we can implement CRUD functionality using generic views and django-mptt ?? I've searched a lot and couldn't find a single tutorial/sample code.
Let's say we have a Course hierarchy or Category hierarchy, or similar thing ... How we can Add/Delete/Update/Read them ??
For instance I have this model:
from django.db import models
from mptt.models import MPTTModel , TreeForeignKey
class Genre(MPTTModel):
name = models.CharField(max_length = 50 , unique = True)
parent = TreeForeignKey('self' , null = True , blank = True , related_name = 'children')
class MPTTMeta:
order_insertion_by = ['name']
and this views.py:
from django.views.generic.list_detail import object_list
from mp.models import Genre
def genres_list(request):
''' Shows all of the genres '''
return object_list(request,
queryset = Genre.tree.all() ,
template_name = 'genres.html' ,
# template_object_name = 'nodes' ## Adding "nodes" variable didn't solve the problem
)
well ... I get this error (error is in line number "5" : {% recursetree nodes %}):
Caught VariableDoesNotExist while rendering: Failed lookup for key [nodes] in u"[{'paginator': None, 'is_paginated': False, 'page_obj': None, 'nodes_list': [<Genre: Genre object>, <Genre: Genre object>, <Genre: Genre object>, <Genre: Genre object>]}, {'csrf_token': <django.utils.functional.__proxy__ object at 0x7f5bb810f090>}, {'perms': <django.utils.functional.__proxy__ object at 0x7f5bb810ff10>, 'messages': <django.contrib.messages.storage.user_messages.LegacyFallbackStorage object at 0x324af50>, 'user': ....................................
<html>
2
3 {% load mptt_tags %}
4 <ul>
5 {% recursetree nodes %}
6 <li>
7 {{node.name}}
Simple CRUD application with MPTT models and class-based generic views (Django 1.4 The function-based implementation has been deprecated).
Let's begin
urls.py
from django.conf.urls.defaults import patterns, include, url
from django.views.generic import DetailView, ListView, CreateView, UpdateView
from genre.models import Genre
urlpatterns = patterns('',
url(r'detail/(?P<pk>\d+)', DetailView.as_view(model=Genre), name="genre_detail",),
url(r'update/(?P<pk>\d+)', UpdateView.as_view(model=Genre), name="genre_update",),
url(r'create', CreateView.as_view(model=Genre), name="genre_create",),
url(r'list', ListView.as_view(model=Genre), name="genre_list",),
)
models.py
from django.core.urlresolvers import reverse
from django.db import models
from mptt.models import MPTTModel
class Genre(MPTTModel):
name = models.CharField(max_length=50 , unique=True)
parent = models.ForeignKey('self' , null=True , blank=True , related_name='children')
def get_absolute_url(self):
return reverse('genre_detail', kwargs={'pk': self.pk, })
class MPTTMeta:
order_insertion_by = ['name']
templates/genre_detail.html
<html>
<body>
<div>Object: {{ object }}</div>
<div>Object's name: {{ object.name }}</div>
<div>Object's parent: {{ object.parent }}</div>
</body>
</html>
templates/genre_form.html
<html>
<body>
<form action="" method="post">
{% csrf_token %}
{{ form.as_ul }}
<button>save</button>
</form>
</body>
</html>
templates/genre_list.html
{% load mptt_tags %}
<html>
<body>
<ul class="root">
{% recursetree object_list %}
<li>
{{ node.name }}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
</body>
</html>
and that's it.
I had some spare time today and shared this project on github https://github.com/kaygorodov/simple-crud-mptt.
How can I define my own class-based view?
genre/views.py
from django.view.generic import UpdateView
class MyCustomUpdateView(UpdateView):
model = Genre
def get_form_kwargs(self):
"""
Returns the keyword arguments for instanciating the form.
"""
kwargs = super(MyCustomUpdateView, self).get_form_kwargs()
kwargs.update({'my_first_param_to_init_form': 1,
'my_second_param_to_init_form': 2,
})
return kwargs
genre/urls.py
url(r'update/(?P<pk>\d+)', MyCustomUpdateView.as_view(), name="genre_update",),