Querying a django DB with model forms - django

Okay, so I'm trying to teach myself django by trying to put together a simple DB query application.
So I have in my DB a relation mysql table storing triples (RDF, subj, obj, pred) and I have written a model form with the fields to query that. Though, I have initially setup my form to store the queries in a separate table. What I would like to do however, is the model form I created to instead query the triple table.
Here is my code:
view:
from django.shortcuts import render, get_object_or_404, render_to_response
from django.template import RequestContext
# Create your views here.
from .forms import QueryForm
from .models import Query
def queries_create(request):
form = QueryForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
context = {
"title":"Create",
"form": form,
}
#return HttpResponse("<h1>create</h1>")
return render(request, "query_form.html", context)
model:
from __future__ import unicode_literals
from django.db import models
from django.core.urlresolvers import reverse
# Create your models here.
class Query(models.Model):
studyName = models.CharField(max_length=250)
population = models.IntegerField()
intervention = models.CharField(max_length=250)
comparison = models.CharField(max_length=250)
outcome = models.CharField(max_length=250)
outcomeTiming = models.CharField(max_length=250)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
def __unicode__(self):
return self.studyName
def get_absolute_url(self):
return reverse("queries:detail", kwargs={"id": self.id})
#return "/queries/%s/" %(self.id)
form:
from django import forms
from .models import Query
class QueryForm(forms.ModelForm):
class Meta:
model = Query
fields = [
"studyName",
"population",
"intervention",
"comparison",
"outcome",
"outcomeTiming",
]
html:
<!--DOCTYPE html -->
<html>
<body>
<h1>Query the Model</h1>
<form method='POST' action=''>{% csrf_token %}
{{ form }}
<input type='submit' value='Query!' />
</form>
</body>
</html>
Any help would be appreciated I've tried several modifications but nothing seems to be working.

You need to handle the data differently for the form. Instead of saving it you need to extract the data and query for matching:
def query_queries(request):
form = QueryForm(request.POST or None)
if form.is_valid():
# this is the same as doing
# Query.objects.filter(studyName=form.cleaned_data['studyName']...)
queries = Query.objects.filter(**form.cleaned_data)
context = {
'queries': queries
}
return render(request, "query_queries.html", context)

Related

Django 2.0.3 adding data to the database

I have a small problem with adding data to the database in django 2.0.3
I created the following model:
from django.contrib.auth.models import User
class UserInputSignal(models.Model):
name = models.CharField(max_length=512)
author = models.ForeignKey(User, on_delete=models.CASCADE)
input_file = models.FileField(upload_to='signals/', null=True)
I tried to solve the problem using this form:
from django import forms
from .models import UserInputSignal
class UserInputSignalForm(forms.ModelForm):
name = forms.CharField()
input_file = forms.FileField()
class Meta:
model = UserInputSignal
fields = ('name', 'input_file', )
and this view:
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate
from .forms import UserInputSignalForm
#login_required
def storage(request):
form = UserInputSignalForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
name = request.POST.get('name')
author = request.POST.get(request.user)
input_file = request.POST.get('input_file')
return redirect('home')
else:
form = UserInputSignalForm()
return render(request, 'storage.html', {'form': form})
In the template I called, I created the form as follows:
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
I am able to load a page with a form, but it does not post data to the database. I would like to add that I am a novice in django and some mechanisms are just plain understandable for me. Can I ask someone for help with this problem?
Before the redirect, call form.save()
Okay, i worked on your code and it works with me with slight modifications:
models.py
class UserInputSignal(models.Model):
name = models.CharField(max_length=512)
author = models.ForeignKey(User, on_delete=models.CASCADE)
input_file = models.FileField(upload_to='signals/', null=True)
objects = models.Manager()
#this returns the name for your modelobject
def __str__(self):
return self.name
forms.py
#excluded the assiging as fields defination is enough in itself
class UserInputSignalForm(forms.ModelForm):
class Meta:
model = UserInputSignal
#this will exclude the formfield it self but the author will be saved as the person who is logged in
exclude = ["author"]
Edited - Views.py
#login_required
def storage(request):
#authentication for author field using request.user
insta = UserInputSignal(author=request.user)
print(request.user)
form = UserInputSignalForm(request.POST or None, request.FILES or None,instance=insta)
if request.method == 'POST':
if form.is_valid():
signal = form.save(commit=False)
signal.save()
return redirect('home')
else:
form = UserInputSignalForm(instance=insta)
return render(request, 'storage.html', {'form': form})
JlucasRs was right to tell you to use form.save(), but you needed to assign form to something and need not use model fields here as forms.py does that for you.
app/Urls.py - Just for reference
urlpatterns = [
path('home/', home, name='home'),
path('storage/', storage, name='storage'),
]
Edit- Admin.py
from .models import PostModel, UserInputSignal
class UserInputSignalAdmin(admin.ModelAdmin):
list_display = ('name', 'author', 'input_file' )
admin.site.register(UserInputSignal, UserInputSignalAdmin)
Add this code in Admin.py if its not there.

Form input to a template

EXPECTED OUTPUT
Assuming that the user enters "anaconda" in the Form:
Hashtag Search Results
You searched for: anaconda
ACTUAL OUTPUT
Hashtag Search Results
1) You searched for: <QuerySet [<Hashtag: >, <Hashtag: anaconda>]>
CODE
models.py
from django.db import models
class Location(models.Model):
""" Model representing a Location, attached to Hashtag objects through a
M2M relationship """
name = models.CharField(max_length=1400)
def __str__(self):
return self.name
class Hashtag(models.Model):
""" Model representing a specific Hashtag serch by user """
search_text = models.CharField(max_length=140, primary_key=True)
locations = models.ManyToManyField(Location, blank=True)
def __str__(self):
""" String for representing the Model object (search_text) """
return self.search_text
def display_locations(self):
""" Creates a list of the locations """
# Return a list of location names attached to the Hashtag model
return self.locations.values_list('name', flat=True).all()
forms.py
from django import forms
from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _
from .models import Location, Hashtag
class SearchHashtagForm(ModelForm):
""" ModelForm for user to search by hashtag """
def clean_hashtag(self):
data = self.cleaned_data['search_text']
# Check search_query doesn't include '#'. If so, remove it.
if data[0] == '#':
data = data[1:]
# return the cleaned data
return data
class Meta:
model = Hashtag
fields = ['search_text',]
labels = {'search_text':_('Hashtag Search'), }
help_texts = { 'search_text': _('Enter a hashtag to search.'), }
views.py
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from .models import Location, Hashtag
from .forms import SearchHashtagForm
def hashtag_search_index(request):
""" View function for user to enter search query """
# If POST, process Form data
if request.method == 'POST':
# Create a form instance and populate it with data from request (binding):
form = SearchHashtagForm(request.POST)
# Check if form is valid
if form.is_valid():
search_text = form.cleaned_data['search_text']
form.save()
# redirect to a new URL
return HttpResponseRedirect(reverse('mapping_twitter:results'))
# If GET (or any other method), create the default form
else:
form = SearchHashtagForm()
context = {'form':form, 'search_text':Hashtag.search_text}
return render(request, 'mapping_twitter/hashtag_search_index.html', context)
class SearchResultsView(generic.ListView):
""" Generic class-based view listing search results of locations """
model = Hashtag
template_name = 'mapping_twitter/results.html'
def get_queryset(self, **kwargs):
qs = super(SearchResultsView, self).get_queryset()
return qs
def get_context_data(self, **kwargs):
context = super(SearchResultsView, self).get_context_data(**kwargs)
context['search_text'] = Hashtag.objects.all()
return context
results.html
<h1>Hashtag Search Results</h1>
<p>1) You searched for: {{ search_text }}</p>
{% for obj in queryset %}
<p>2) You searched for: {{ obj.search_text }}</p>
{% endfor %}
I think you should pass the queryset of the Model HashTag as you need to render out hashtag.search_text which is an element of that model.
So you can pass the queryset in the view and for loop through it and print all the search_text or pass the object alone and render out its search_text.
context = {
'queryset': qs
}
{% for obj in queryset %}
<p>{{ obj.search_text }}</p>
{% endfor %}
This is my guess, correct me if I am wrong.
For a template to display something, you have to send context or data to that template to print, how can it print something when you don't send anything. So,
context.update({
'hashtag': //value you want to send.
})

PDF file without content in Django

UPDATE
Hello friends,
I want to ask you for help.
I created a web form that generates PDF files. Everything is fine. Automatically Send PDFs via Email is OK. Unfortunately, the form fields that are not added to the models.Model are not included in the PDF (contents).
PDF documents display (postal_code) as blank field.
I don't know what to do. Where is the problem?
model.py
class Order(models.Model):
name = models.CharField(max_length=50)
forms.py
CHOICES=[('item1','1xx'),
('item2','2xx')]
class OrderCreateForm(forms.ModelForm):
postal_code = forms.ChoiceField(choices=CHOICES, widget=forms.RadioSelect())
class Meta:
model = Order
fields = ['name', 'postal_code']
create.html
<form action="." method="post" class="order-form">
{{ form.as_ul }}
<p><input type="submit" value="Send"></p>
{% csrf_token %}
</form>
tasks.py
from celery import task
from django.shortcuts import get_object_or_404
from oferty.models import Order
from django.template.loader import render_to_string
from django.core.mail import EmailMessage
from django.conf import settings
import weasyprint
from io import BytesIO
#task
def order_created(order_id):
order = Order.objects.get(id=order_id)
subject = 'NEW {}'.format(order.id)
message = 'Hi {}!\n\nBlablabla.\
Ident blabla {}.'.format(order.imię,
order.id)
email = EmailMessage(subject,
message,
'admin#myshop.com',
[order.email])
html = render_to_string('orders/order/pdf.html', {'order': order})
out = BytesIO()
stylesheets = [weasyprint.CSS(settings.STATIC_ROOT + 'css/pdf.css')]
weasyprint.HTML(string=html).write_pdf(out,
stylesheets=stylesheets)
email.attach('order_{}.pdf'.format(order.id),
out.getvalue(),
'application/pdf')
email.send()
pdf.html
<html>
<body>
<h1>Test</h1>
<p>
{{ order.name }}<br>
{{ order.postal_code }}
</p>
</body>
</html>
Do you give me any hint of which way ?
Your help would be greatly appreciated.
UPDATE
views.py
from django.shortcuts import render
from .models import OrderItem
from .forms import OrderCreateForm
from cart.cart import Cart
from .tasks import order_created
from django.contrib.admin.views.decorators import staff_member_required
from django.shortcuts import get_object_or_404
from .models import Order
from django.conf import settings
from django.http import HttpResponse
from django.template.loader import render_to_string
import weasyprint
def order_create(request):
cart = Cart(request)
if request.method == 'POST':
form = OrderCreateForm(request.POST)
if form.is_valid():
order = form.save()
for item in cart:
OrderItem.objects.create(order=order,
product=item['product'],
price=item['price'],
quantity=item['quantity'])
cart.clear()
order_created.delay(order.id)
return render(request,
'orders/order/created.html',
{'order': order})
else:
form = OrderCreateForm()
return render(request,
'orders/order/create.html',
{'cart': cart, 'form': form})
#staff_member_required
def admin_order_pdf(request, order_id):
order = get_object_or_404(Order, id=order_id)
html = render_to_string('orders/order/pdf.html',
{'order': order})
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'filename= "order_{}.pdf"'.format(order.id)
weasyprint.HTML(string=html).write_pdf(response, stylesheets=[weasyprint.CSS(settings.STATIC_ROOT + 'css/pdf.css')])
return response
urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^create/$',
views.order_create,
name='order_create'),
url(r'^admin/order/(?P<order_id>\d+)/pdf/$',
views.admin_order_pdf,
name='admin_order_pdf'),
]
Environment:
Django Version: 1.10.6
Python Version: 3.5.2
Help. Seriously.
Assuming you want to store the postal code on the order you'll need to add the 'postal_code' field present on OrderCreateForm to the Order model.
models.py
class Order(models.Model):
CHOICES = [
('item1', '1xx'),
('item2', '2xx')
]
name = models.CharField(max_length=50)
postal_code = models.CharField(max_length=50, choices=CHOICES)
After that you'll only need to specify the radio select widget for that field your model form.
forms.py
class OrderCreateForm(forms.ModelForm):
class Meta:
model = Order
fields = ['name', 'postal_code']
widgets = {
'postal_code': forms.RadioSelect()
}
since postal_code is not a field of order model.You will have to pass it's value separately.Or you can add the field in the model. if you choose not to include this might help.
from celery import task
from oferty.models import Order
from django.template.loader import render_to_string
from django.core.mail import EmailMessage
from django.conf import settings
import weasyprint
from io import BytesIO
#task
def order_created(order_id,postal_code):
order = Oferta.objects.get(id=order_id)
subject = 'New nr {}'.format(order.id)
message = 'Hallow, {}!\n\nBlaBlaBla.\
BlaBlaBla {}.'.format(order.imię,
order.id)
email = EmailMessage(subject,
message,
'admin#myshop.com',
[order.email])
html = render_to_string('orders/order/pdf.html', {'order': order,'postal_code':postal_code})
out = BytesIO()
stylesheets = [weasyprint.CSS(settings.STATIC_ROOT + 'css/pdf.css')]
weasyprint.HTML(string=html).write_pdf(out,
stylesheets=stylesheets)
email.attach('order_{}.pdf'.format(order.id),
out.getvalue(),
'application/pdf')
email.send()
call the function with both the values
order_created(order_id=order_id,postal_code= postal_code)
and in the pdf.html replace
{{order.postal_code}}
with
{{postal_code}}

django validationerror not being raised

So I have created a a dynamic formset that allows the user to add or remove as many forms as they want. Now, I am trying to do custom validation in a field(block_name) in the forms.
It seems like it is working because if the user input doesn't match a certain regex, then the data will not be saved. The problem is that there is no message showing that the input is wrong.
Also, if the user inputs incorrect data and tries to submit the page will redirect to itself and erase all the input data. How can I make the page stay in the same view if the input is wrong and also show error messages?
forms.py:
import re
from django import forms
from django.forms.models import modelformset_factory
from inventory.models import Block
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
# Form for block requests
class BlockForm(forms.ModelForm):
block_name = forms.CharField(required=True, validators= [RegexValidator('^s\d{3}rf\d*b\d*e\d+r\d+w\d*[cgls][abcdex][ed][hv][sbaec][a-d] [a-d][0-7][apfg]a', message="Please enter valid block name", code="invalid_name")])
def __init__(self, *args, **kwargs):
super(BlockForm, self).__init__(*args, **kwargs)
self.empty_permitted = False
class Meta:
model = Block
fields = ['block_name', 'block_derivatives', 'block_subsystems', 'owners']
def clean_block_name(self):
print self.cleaned_data
block_name = self.cleaned_data.get('block_name')
if block_name == "a":
print ("block name is a")
raise forms.ValidationError(
('Please enter a block name'))
return block_name
models.py:
import datetime
import re
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from django.db import models
from django.utils import timezone
class Inventory(models.Model):
class Meta:
verbose_name_plural = "Inventories"
inventory_name = models.CharField(max_length=100)
pub_date = models.DateTimeField('date published')
def __str__(self): # __unicode__ on Python 2
return self.inventory_name
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
class Block(models.Model):
class Meta:
verbose_name_plural = "Request Blocks"
inventory = models.ForeignKey(Inventory, null=True)
block_status = models.CharField(max_length=20, blank=False)
#617block_name = models.CharField(max_length=50, blank=False, null=False, validators=[block_nameTest])
block_name = models.CharField(max_length=50, blank=False, null=False)
block_derivatives = models.CharField(max_length=100)
block_subsystems = models.CharField(max_length=40)
owners = models.CharField(max_length=100)
def __str__(self):
return self.block_name
def block_owners(self):
return str(self.owners)
views.py:
from django.forms.models import modelformset_factory
from django.forms.formsets import formset_factory
from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.views import generic
from django.http import HttpResponse
from django.shortcuts import render_to_response
from .models import Inventory, Block
from .forms import BlockForm
# Create your views here.
def requests(request, inventory_id):
BlockFormSet = formset_factory(BlockForm, extra=1)
inventory = get_object_or_404(Inventory, pk=inventory_id)
formset = BlockFormSet(request.POST)
if request.method == 'POST':
formset = BlockFormSet(request.POST)
if formset.is_valid():
for form in formset:
print form
form.save()
print "Success"
return HttpResponseRedirect('/inventory/2')
else:
print "Yo, this stuff is not validated"
else:
print "LOLOLOLOL"
return render(request, 'inventory/requests.html', {'inventory': inventory, 'formset': BlockFormSet})
requests.html:
{% block content %}
<div class="requestForm">
<form id="blockForm" class="original" action="{% url 'inventory:requests' inventory.id %}" method="post">{% csrf_token %}
<!-- Add New Row -->
{{formset.management_form}}
{% for form in formset %}
<div class='item'>
<ul>{{ form.as_table}}<ul>
<p style=""><a class="delete" href="#">Delete</a></p>
</div>
{% endfor %}
<p><a id="add" href="#">Add another item</a></p>
<input type="submit" name="submit" value="Request Blocks" id="submitButton">
</form>
</div>
{% endblock %}
You're redirecting after an invalid POST, rather than redisplaying the same form. Even though your redirect is to the same view, it loses the POST data and the form is therefore blank.
Drop the first else block, and let execution fall through to the final render line.

Editing existing entries in Django forms

My problem is similar to how to edit model data using django forms, but I'm not able to solve it.
I would like to get an form with prefielled fields and to allow user to edit them.
I believe my problem is in views.py file, but unfrotuntely I'm not able to solve it.
models.py
from django.db import models
class Item(models.Model):
product = models.CharField(max_length=150)
quantity = models.DecimalField(max_digits=8, decimal_places=3)
price = models.DecimalField(max_digits=7, decimal_places=2)
purchase_date = models.DateTimeField()
warranty = models.DecimalField(max_digits=4, decimal_places=1)
comment = models.TextField()
forms.py
from django import forms
from items.models import Item
class EditItemForm(forms.ModelForm):
class Meta:
model = Item
fields = ('product','quantity', 'price', 'purchase_date', 'warranty', 'comment')
urls.py
from django.conf.urls import patterns, include, url
urlpatterns = patterns('',
url(r'^show_all/$', 'items.views.items'),
url(r'^(?P<item_id>\d+)/$', 'items.views.item'),
url(r'^edit/(?P<item_id>\d+)/$', 'items.views.edit'),
)
edit.html
<form action="/items/edit/" method="post" class="form horizontal well">{% csrf_token %}
{{ form.as_p }}
<imput type="submit" class="btn btn-inverse" value="Aktualizuj">
</form>
views.py
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from items.models import Item
from decimal import Decimal
from django.core.context_processors import csrf
from items.forms import EditItemForm
def edit(request):
if request.method == 'POST':
form = EditItemForm(request.POST, instance=request.item)
if form.is_valid():
form.save()
return HttpResponseRedirect('/items/show_all/')
else:
form = EditItemForm(instance=item)
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('edit.html', args)
Above code is resulting this message:
TypeError at /items/edit/1/
edit() got an unexpected keyword argument 'item_id'
Can you please help me?
Django 1.6, Python 3.4
You've imagined an attribute called request.item. There's no such thing. You need to get the item from the database, via the ID passed into the function as alecxe showed.
def edit(request, item_id):
item = Item.objects.get(pk=item_id)
if request.method == 'POST':
form = EditItemForm(request.POST, instance=item)
edit() view should allow a keyword argument item_id:
def edit(request, item_id=None):
if request.method == 'POST':
...