Populate a django form with data from database in view - django

I have a form in my forms.py that looks like this:
from django import forms
class ItemList(forms.Form):
item_list = forms.ChoiceField()
I need to populate the item_list with some data from the database. When generated in HTML item_list should be something like:
<select title="ItemList">
<option value="1">Select Item 1</option>
<option value="2">Select Item 2</option>
</select>
The options values in my select statement will change almost every time since a variable in the query will often change generating new results.
What do I need to put in the view.py and also in my template files to populate the ItemList with values from the database?

Take a look at this example in the Django documentation:
http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#a-full-example
Basically, you can use the queryset keyword argument on a Field object, to grab rows from your database:
class BookForm(forms.Form):
authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
Update
If you need a dynamic model choice field, you can hand over your item id in the constructor of the form and adjust the queryset accordingly:
class ItemForm(forms.Form):
# here we use a dummy `queryset`, because ModelChoiceField
# requires some queryset
item_field = forms.ModelChoiceField(queryset=Item.objects.none())
def __init__(self, item_id):
super(ItemForm, self).__init__()
self.fields['item_field'].queryset = Item.objects.filter(id=item_id)
P.S. I haven't tested this code and I'm not sure about your exact setup, but I hope the main idea comes across.
Resources:
http://www.mail-archive.com/django-users#googlegroups.com/msg48058.html
http://docs.djangoproject.com/en/dev/ref/forms/fields/#django.forms.ModelChoiceField

What you need to do is to find out which object do you actually want for e.g. if you want to find out a book named "Upvote-if-u-like!" then your urls.py should like
urlpatterns = [
path('textshare/<str:slug>',views.extract,name="textshare"),]
now when someone will search for mybook.com/textshare/upvote-if-u-like!/
it will take him/her to views.py which would look like
def extract(request,slug):
context={}
obj=bookForm.objects.get(title=slug)
form=bookModelForm(instance=obj)
context={'form':form}
return render(request,'bookfound.html',context)
where bookForm is in Models.py and bookModelForm is in forms.py
Happy Djangoing:)

Related

Django: How to add a print button to objects to print some (special) fields of a model instance

(Hopefully) not a duplicate:
I know this might seem to be quite similar to Django admin overriding - adding a print button
But the answer there is to use django-object-actions, which I already tried but it looks a bit too overloaded for such an simple task. Furthermore the buttons there are not placed behind the row.
My question:
I would like to create a printable view of some fields of a Django models instance.
Let's say I want to print an users
Name
Last Name
Number
What I image is something like this:
Clicking on a print button, shown at the list view:
An preformatted and easy to print website opens which contains the data:
What I have so far
I added the button by using the following code:
class MyModelAdmin(admin.ModelAdmin):
list_display = ('number', 'name', 'last_name', ..., 'account_actions')
...
def account_actions(self, obj):
return format_html(
'<form method="post" action="/print_view.htm"> \
<input type="hidden" name="name" value="{}"> \
<button type="submit" name="action">Print</button> \
</form>',
obj.name
)
account_actions.short_description = 'Actions'
account_actions.allow_tags = True
So my idea is to send the data which I want to get printed to another Website (via POST, on the same server). I would extract the data from the request then and create a printable view.
My question is:
Is it possible to do the same within Django (without leaving DjangoAdmin for the printable view)?
The current approach doesn't feel right too me, I bet there is a way to do that using just Django - a way which I don't know of since I am quite a beginner here.
I found a great module out there that is called django-admin-object-actions, it can be found here: https://github.com/ninemoreminutes/django-admin-object-actions
The maintainer/owner #cchurch helped me out with the following answer:
You can specify a custom view method that can render any template or
return any content you'd like. Here's the simplest example I can come
up with to do that:
class TestModelAdmin(ModelAdminObjectActionsMixin, admin.ModelAdmin):
# all of the normal model admin code here
object_actions = [
{
'slug': 'print',
'verbose_name': _('Print'),
'form_method': 'GET',
'view': 'print_view',
},
]
def print_view(self, request, object_id, form_url='', extra_context=None, action=None):
from django.template.response import TemplateResponse
obj = self.get_object(request, object_id)
return TemplateResponse(request, 'print.html', {'obj': obj})
Using the following template (print.html):
<p>Name: {{ obj.name }}</p>
<p>Enabled: {{ obj.enabled }}</p>

Accessing Attributes of a CheckboxSelectMultiple checkbox

Short Version
In the Django template language, how do I access the attributes of a given checkbox within a CheckboxSelectMultiple widget?
Long Version
The attributes of a typical Django widget can be accessed easily:
{% for field in form %}
{{ field.widget.attrs.something }}
{% endfor %}
However, this method isn't working for a checkbox within a CheckboxSelectMultiple widget.
I have a customized CheckboxSelectMultiple widget which I'm using to display a ManyToMany ModelForm field. The customized widget adds additional attributes to each checkbox in the create_option method.
The additional attributes display appropriately within the HTML of the input element:
<input type="checkbox" name="questions" value="22" id="id_questions_12" category="Category Name" category_number="3" question="Question Name" question_number="4">
I need to access these additional attributes for purposes of display and organizing the form fields.
I turned back to this after letting it sit for a week or so. After playing around some more and reading into the docs for BoundField (and BoundWidget specifically), I found out how to access the attrs of an individual checkbox in a CheckboxSelectMultiple widget:
{% for field in form %}
{% for check in field.subwidgets %}
{% for a in check.data.attrs %}
I was able to use the same technique given in this answer. It works perfectly for CheckboxSelectMultiple although it is not used in the answer.
I saved this in my project's forms.py:
from django.forms.widgets import CheckboxSelectMultiple, Select
class SelectWithAttrs(Select):
"""
Select With Option Attributes:
Subclass of Django's Select widget that allows attributes in options,
e.g. disabled="disabled", title="help text", class="some classes",
style="background: color;", etc.
Pass a dict instead of a string for its label:
choices = [ ('value_1', 'label_1'),
...
('value_k', {'label': 'label_k', 'foo': 'bar', ...}),
... ]
The option k will be rendered as:
<option value="value_k" foo="bar" ...>label_k</option>
"""
def create_option(self, name, value, label, selected, index,
subindex=None, attrs=None):
if isinstance(label, dict):
opt_attrs = label.copy()
label = opt_attrs.pop('label')
else:
opt_attrs = {}
option_dict = super().create_option(
name, value, label, selected, index,
subindex=subindex, attrs=attrs)
for key, val in opt_attrs.items():
option_dict['attrs'][key] = val
return option_dict
class CheckboxSelectMultipleWithAttrs(
SelectWithAttrs, CheckboxSelectMultiple):
pass
Here is a working snippet from a project of mine that uses this example. The stuff in the beginning isn't really important, but it shows how to build your attributes dict and pass it into your choices.
from django import forms
from django.whatever import other_stuff
from project_folder import forms as project_forms
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['employees']
def __init__(self, *args, **kwargs)
super().__init__(*args, **kwargs)
self.fields['employees'].queryset =\
self.company.employee_set.filter(is_active=True)
existing_crews_employees = []
for crew in existing_job_crews:
crew_employees =\
[employee.__str__() for employee in crew.employees.all()]
existing_crews_employees.append({'crew_name': crew.crewtype.name,
'employees': crew_employees})
employees_choices = []
for (index, choice) in enumerate(self.fields['employees'].choices):
# loop over each choice and set proper paramaters for employees
# that are unassigned/on the current crew/on a different crew
employee_in_crew = False
employee_name = choice[1]
for crew_and_employees in existing_crews_employees:
for employee in crew_and_employees['employees']:
if employee_name == employee.__str__():
crew_name = crew_and_employees['crew_name']
if self.obj and self.obj.crewtype.name == crew_name:
# check the box if employee in current crew
employees_choices.append((choice[0], {
'label': choice[1],
'checked': True,
'id': f'id_employees_{choice[0].instance.id}'
}))
else:
# disable the choice if employee in another crew
employees_choices.append((choice[0], {
'label':
employee_name + f" (on Crew: {crew_name})",
'disabled': True}))
employee_in_crew = True
# for valid entries, ensure that we pass the proper ID
# so that clicking the label will also check the box
if not employee_in_crew:
employees_choices.append((choice[0], {
'label': choice[1],
'id': f'id_employees_{choice[0].instance.id}'}))
self.fields['employees'].widget = project_forms.CheckboxSelectMultipleWithAttrs(
choices=employees_choices)
There are two important things to keep in mind when using this technique:
Ensure that you pass the id into your attrs for your clickable options, otherwise your labels will not check the proper boxes when they are clicked.
This method currently requires initial values to be set using the new attributes dict. Ensure that you pass the 'checked': True key-value pair to any boxes that should be checked.

How do you expose a bulk create to django admin page users?

Let's say that, as part of an administrative process, thousands of values are created offline. These values are entered into a dead-simple model:
class Foo(models.Model):
value = models.CharField(max_length=32)
I'd like to have a field on the model creation page that allows the user to enter (copy-paste) 1000 values in, and as a result, 1000 rows would be created in the table.
If I can add a text field to the model creation, all I have to do is parse out the values and call Foo.create for each. How would I add this free-form field, and how would I go about processing it when the user hits the Save button? ...or is there entirely a different way that I should be going about this?
I realize my comment is more of an answer now.
Sure, why not? You hardly even need django for this. You could just create a <textarea name="foo"></textarea>, and in your view parse the data by line break.
Create a custom admin view via Admin.get_urls and write a custom view for your bulk create page.
https://docs.djangoproject.com/en/1.8/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_urls
Here's a copy and paste out of the live example for get_urls
class MyModelAdmin(admin.ModelAdmin):
def get_urls(self):
urls = super(MyModelAdmin, self).get_urls()
my_urls = [
url(r'^my_view/$', self.my_view),
]
return my_urls + urls
def my_view(self, request):
# ...
context = dict(
# Include common variables for rendering the admin template.
self.admin_site.each_context(request),
# Anything else you want in the context...
)
if request.method == 'POST':
for line in request.POST['bulk-create-paste'].split('\n'):
Foo.objects.create(myfield=line)
return TemplateResponse(request, "sometemplate.html", context)
sometemplate.html
<form method="POST">
<p>Paste bulk create info.</p>
<textarea name="bulk-create-paste">
</textarea>
</form>

Django: How to return model formset in ajax and use in template

I need to dynamically add forms to my formset during runtime using ajax, for which I am referring to Dynamically adding a form to a Django formset with Ajax
I have multiple formsets on the same page with different prefixes.
My models are designed like so:
A user can have many phones. A phone can have many lines (if details are needed)
Accessing Many to Many "through" relation fields in Formsets
Once a user adds a new phone, I save the phone using ajax. The view is as follows
def addUserPhone(request, customer_id, location_id, user_id, **kwargs):
error_msg = u"No POST data sent."
context = {}
if request.is_ajax():
if request.method == "POST":
user = End_User.objects.get(id=user_id)
phone_client = PartialPhone_ClientForm(request.POST, prefix='new_client')
instance = phone_client.save()
#associate user to a phone
instance.end_user.add(user)
#Creating an empty lineFormset for a phone
LineFormSet = modelformset_factory(Line, form=Line_Form, can_delete=True)
client_lines = LineFormSet(queryset=Line.objects.none(), prefix='phone_client_'+str(instance.id))
# how to return the two objects instance and client_lines back to the template??
#format = 'json'
#mimetype = 'application/javascript'
#data = serializers.serialize(format, [instance])
#return HttpResponse(data)
#can we return as a context?? this gives me only a string "phoneline_set" in the template
context['phone'] = instance
context['line_set'] = client_lines
return HttpResponse(context)
else:
error_msg = u"Insufficient POST data (need 'Name ' and 'Telephone Number'!)"
else:
error_msg = "Non Ajax"
return HttpResponseServerError(error_msg)
What is the best way to now return the phone instance, and LineFormSet back to the view for rendering in the template??
If I just return a context, my view gets only string "phoneline_set". But I want to do something like
$.post("addUserPhone/",phoneData,function(data){
$('.scroll').append("<h2> {{ line_set }} </h2>")
});
If I serialize using Json and pass how can I pass the LineFormSet and use it in template?
Currently if I try to serialize my client_lines formset I get the error
AttributeError: 'LineFormFormSet' object has no attribute '_meta'
Any help is appreciated, Thanks!!
Just elaborating on Daniel's answer as requested in the comment.
Django is an MVC style framework. Models are used in order to store and access data. In Django controllers are called views, which have a job of getting a request from a user with a certain URL, get some data which might be associated with the url, and then push that data throught some tempalte which will use the data view gave it in order to fill in the placeholders inside of the template.
Here is a simple example which explains all the aspects. Imagine that there is a web site which has a database of books. So your model would store information relevant to each book - Title, Author, ISBN number, etc.
# models.py
class Book(models.Model):
title = models.CharField(max_length=64)
author = models.CharField(max_length=64)
isbn = models.CharField(max_length=64)
Now you want to add a URL example.com/book/<id>/ which will display all of the information about the book with specified id. For that to happen, couple of things need to happen. First Django controller has to catch the url with this pattern. You specify the url pattern in the urls.py file.
# urls.py
urlpattern('',
url(r'^book/(?P<id>\d+)/$', views.book),
)
Since urls.py specify a mapping between url patterns and views, that tells Django that whenever user goes to a URL with the specified pattern, Django has to give the request to the view book which will know what to do. Additionally Django will pass the book id to the view.
# views.py
def book(request, id):
# get the book
book = get_object_or_404(Book, pk=id)
context = {
'book': book
}
return render_to_response('book_template.html', context)
So inside of the view, given the ID of the book, it uses models in order to look up the book from the database, and it case it is not found, it returns 404 error to the user. Then it populates a dictionary which I called context with some values which it will pass to the template. The job of the template is to take this context dictionary and use values inside of it in order to fill in some placeholders inside the template.
# book_template.html
<html>
<head>...</head>
<body>
<h1>{{ book.title }}</h1>
<p>Author: {{ book.author }}</p>
<p>ISBN: {{ book.isbn }}</p>
</body>
</html>
So the template will take the context from the view and then use the book inside of the context in order to fill in the values inside {{ }}.
In your case you are trying to return a context to the user which does not make much sense. What you have to do is create a template which will take the that context { 'phone': instance, 'line_set': client_lines } and according to it, will render some HTML which will be returned to the user. And that HTML you can pull using AJAX and then use it however you need it.
Hopefully this clarifies some concepts for you.
Django documentation is excellent so I would recomment to also read the intro. It will explain all of the syntax and some of the shortcuts I have used in this answer (render_to_response, etc).
You don't send the context as the Ajax response, you send a rendered template fragment using that context. The template should just be the HTML containing the form that you want to insert into your div.

Add a prefix do Django comment form

I would like to add a prefix to each django comment form. I'm using multiply comment forms in the same page and depsite it's working well, i don't like having many input fields with the same id attribute like <input type="text" name="honeypot" id="id_honeypot" />.
So, is there a way to tell django do add a prefix to each form instance? I know i can do it with other forms when i create a form instance in this waynewform = CustomForm(prefix="a") but using Django's comment system, this part is handled by a comment template tag {% get_comment_form for [object] as [varname] %}.
Can I tell to the template tag to add a prefix?
Well, I have an idea. Add your custom comments form and override __init__. You can generate prefix from target_object and set it to self.prefix:
def __init__(self, target_object, data=None, initial=None):
...
Or better, override BaseForm.add_prefix:
def add_prefix(self, field_name):
"""
Returns the field name with a prefix appended, if this Form has a
prefix set.
Subclasses may wish to override.
"""
return self.prefix and ('%s-%s' % (self.prefix, field_name)) or field_name
Update:
Yes, you're right. Prefix wouldn't work, the main reason is the code in contrib.comments.views.comments.post_comment. So I've reread your question and if you only need to change "id" attribute use BaseForm.auto_id:
class CustomCommentForm(CommentForm):
def __init__(self, target_object, data=None, initial=None):
super(CustomCommentForm, self).__init__(target_object, data, initial)
idprefix = target_object.__class__.__name__.lower()
self.auto_id = idprefix + "_%s"