How to display more things in admin.StackedInline - django

I have Article model and a Comment model. Comment is created in admin.py as admin.StackedInline, and it has several fields, notably content and lastUpdate. For lastUpdate, i have specified as follows: lastUpdate = models.DateTimeField('last update', auto_now=True). Understandably, lastUpdate is not displayed when i try to add new comment (or edit old ones). However, i would like it to display for older comments if possible, as a read only thing. Is there anyway of accomplishing that?
Thanks a lot!
Jason

I guess if this http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.readonly_fields doesn't do what you want it to do, have a look at this: In a Django form, how do I make a field readonly (or disabled) so that it cannot be edited?

Related

Django forms.form header field

I want to have a field type in forms.form that just takes in the text of a header to be displayed so the HTML would be something like:
This is header text for this section
Question
Question
Question
Another header
Question
Question
The idea is I'm declaring all the questions in the form on the fly using a model just for question pages, I need a header for some sections just to say what the sections are about. The inserting the questions on the fly is all working well so far it's just I need the last bit of display code to make it functional for what I need.
To give more information, this is my approach:
the admin creating the form creates questions in the admin interface
then adds the questions to a question form
when a user goes to the question page it renders the page with the questions using forms.form
The questions are declared using:
self.fields['id'] = forms.CharField(
max_length=100,
label=text, required=q.question.required)
What I want is to replace the above line with something like HeaderField which just has header text in a H1/2/3/4...etc container.
So the ideal syntax I want is
self.fields['id'] = forms.HeaderField(label=text, type=1)
Where type 1 is H1, 2 would be H2...etc
I ended up figuring out a solution on the spot using another answer. The solution was just mark the label as safe for HTML, then I can add HTML in directly and style it afterwards.
from django.utils.safestring import mark_safe
self.fields['id'.format(q.question.id)] = forms.CharField(
widget=forms.Textarea,
max_length=1000,
label=mark_safe(text), required=q.question.required)
After I do that I can add things like H1 or BR and style it directly. It's a little bit clunky but at least it works with the code that I already had.

Dynamic model fields in Django

I have a model, for example: "food". Each one of this has some basic info: "name" "calories", etc. I would like to provide a form where the user can add extra fields. For example, if the user is adding a new "food", beside the basic info he could also add new fields, like "sugar", "vitamins", etc.
How could I add the fields to the database so that it can be retrieved/queried later?
Thanks!
Jacob Kaplan-Moss has an extensive writeup on dynamic form fields:
http://jacobian.org/writing/dynamic-form-generation/
Essentially, you add more items to the form's fields member variable
during instantiation.
Source
Even better.

Customizing Django.contrib.comments honeypot

I'm using Django's standard comment system and I would like to extend its anti-spam honeypot capability.
I thought of changing the default "name" and "id" of the field to something more alluring for spam-bots such as "website". I checked the html and this looks like this:
<p style="display:none;">
<label for="id_honeypot">Never send a human to do a machine's job</label>
<input type="text" name="honeypot" id="id_honeypot" />
</p>
Am I correct in thinking that changing the defaults of this element would boost its anti-spam capabilities? I tried modifying it in the django/contrib/comments/forms.py like this:
class CommentForm(CommentDetailsForm):
#use to be honeypot = forms.CharField(...
website = forms.CharField(required=False,
label=_('Never send a human to do a machines job')
def clean_honeypot(self):
"""Check that nothing's been entered into the honeypot."""
value = self.cleaned_data["website"]
if value:
raise forms.ValidationError(self.fields["website"].label)
return value
And this successfully changes the name and id in the html generated by django BUT then the whole mechanism stops working - I tried populating this invisible field, submitted and the comment was added.
I have a few other ideas as well, but first I'd really like to get this working - is it possible to modify the default honeypot name and id AND have it working like it should?
P.S I believe a more elegent way of doing this would be to extend django.contrib.comments and code the modification there instead of working on actual django code - what would be the best way of accomplishing this?
Given a bit more time to tinker around I found the answer to both of my questions:
In order to modify the standard honeypot or to create your own, you have to extend the CommentForm class by adding a clean_NAME_OF_HONEYPOT function as well as a NAME_OF_HONEYPOT variable both of which look similar to the standard ones and you also have to override the security_errors function to include the name of your new/modified honeypot in the dictionary.
The best way to do this is to create your custom comments app as described here: https://docs.djangoproject.com/en/dev/ref/contrib/comments/custom/ .
I hope this answer helps anyone else in my situation.

Alternative form for Django's `ChoiceField` that can handle thousands of entries

I have a form with a ChoiceField in it. It is rendered to the user as a dropdown box.
Problem is, I have thousands of entries in this field, which is causing the page to (a) load very slowly and (b) be sluggish.
I want an alternative widget, instead of Select, that could handle more than 10,000 choices.
Something like the admin's raw_id_fields would be good (if only it were usable in general forms...) but I'm open to ideas.
If autocomplete is an option for your UI you can take a look to django-simple-autocomplete:
App enabling the use of jQuery UI autocomplete widget for
ModelChoiceFields with minimal configuration required.
EDITED (reply OP comment)
I have not tested this solution, but digging documentation and source it seems that not all data is loaded at a time:
The ability to specify an URL for the widget enables you to hook up to
other more advanced autocomplete query engines if you wish.
Source code:
def get_json(request, token):
"""Return matching results as JSON"""
...
di = {'%s__istartswith' % fieldname: searchtext} # <- look here!
items = queryset.filter(**di).order_by(fieldname)[:10]
Widget source code
$("#id_%(name)s_helper").autocomplete({
source: function(request, response){
$.ajax({ # <-- look here
url: "%(url)s",
data: {q: request.term},
success: function(data) {
I don't know what is the raw_id_fields but why not use a model to store all your choices ?
class Choice(models.Model):
value = models.CharField()
class MyModel(models.Model):
choice = models.ForeignKey(Choice)
It would then be easy to select it if you want to display only 20 at a time for example.
Based on this comment (which really, you should have included in your question):
Let me clarify my task: I have 10,000 users. I have a form in which
you choose a user. You need to be able to choose any user you want.
You can't just load 20, because then you won't be able to choose the
other 9,980 users.
If you want something built-in, you can use the FilteredSelectMultiple widget from django.contrib.admin.widgets, which puts a filter on your select.
You should also cache the results of the 10,000 users so you don't hit your db everytime. This is what is causing your delay, not the number of users (which is tiny, for practical performance problems).

Customising specific fields in Django Admin change form

I have a couple of fields in my model that to which I wish to add a link that will allow the user to search for names/files (external from the application's database).
So what I would like is:
Field name: [text box] - LINK
Is there a straightforward django way of achieving this?
Cheers.
You need to change the widget that the form field uses to display the models information. You basically add some html after the input to link to where you want.
Here's some code I put together to create a widget that displays how many characters are left for a CharacterField so it's similar to what you are looking to do:
https://github.com/pastylegs/django-widget-charsleft/blob/master/widget_charsleft/widgets.py