AppEngine/Django: editing db.Key in the Admin app - django

Or, to be precise, how do I properly present a form to edit a db.ListProperty of db.Keys on a model admin page, with app-engine-patch for Django?
I have a Category like this:
class Category(db.Model):
title = db.CategoryProperty(required=True)
and a Post with this:
categories = db.ListProperty(db.Key)
Currently in the Django admin page the field is shown as a textbox containing the Python list object string, which is wrong and breaks saving:
[datastore_types.Key.from_path(u'blog_category', 3L, _app_id_namespace=u'xyz')]
So I've had to 'exclude' it in my ModelAdmin class. I've thought of writing a ModelForm that manually to wire up the Category db.Keys and present them as a Django multiselect widget, but I suspect there are easier ways to do it...

Having read through the App-engine-patch docs more thoroughly, seems that using ragendja.dbutils.KeyListProperty answers this problem, with the old Django multiselection list too. :)
New code:
categories = KeyListProperty(Category)

Related

Where is ID saved in django ModelAdmin autocomplete_fields?

I am rewriting some administration interface to django 2.2, currently using django autocomplete_fields admin feature. Simply said I have ModelAdmin object OrderAdmin, which has nested TabularInline ProductAdmin: variable-length table of products which might be added to order. Each of these ProductAdmin holders just contains ForeignKey to actual product class, with some other attributes.
Now I wonder: where does django store id - ForeignKey - of item selected with autocomplete field? It doesn't mark OPTION in selectbox as selected, and although there is suspicious hidden input field with #cashregisterproduct_set-0-id on page, it doesn't have any value. Or is there some special way how to access it? I was thinking about adding id to __str__ method of model and parsing, but thats just ugly.
Thanks for tip.
EDIT: to make it 100% clear, where from does django get ForeignKey of object selected through autoselect_field, when creating new object from ModelAdmin?
I got misguided thinking that this is managed by django. Selected data might be accessed by using select2 framework:
selected_value = $('.myselectbox').select2().val();
related: https://stackoverflow.com/a/47451658/16268461

How to create foreign key linked fields in forms just like in Django Admin?

In django admin, you can add, edit, and even delete objects from another model if there is a relationship between the two.
For instance, if my code looks like this:
class Category(models.Model):
...
class Product(models.Model):
...
category = models.ForeignKey(Category)
When I am editing/adding a product using the django admin site, in the category field, I have 3 buttons to add/edit/delete categories. Adding one takes to a new window, and once I submit the form, the category is added, the window is closed, and I am returned to my product form with the extra category present. Like this:
How can I do this in my normal application (outside the admin) using forms?
If I understand your question correctly, you could do what django admin does, which is to link the add button to this:
/admin/<your_app>/<your_model>/add/?_to_field=id&_popup=1
and then it uses a bit of javascript to get back the new object you just created. If you look into the contrib/admin/static/admin/js/admin/RelatedObjectLookups.js file (in django's code), you'll see a few functions that pass the id of the calling field to the popup (in showRelatedObjectPopup), and then bring back the selected id (in dismissRelatedLookupPopup).
This is for adding a new object, but you can look into the logic for changing/deleting.
You can replicate that logic with your own forms.

Django Admin Page: Help Text for Model Methods?

I have a model method in Django that I am displaying on an admin page just like I would a model field. With a field, I can just add a help_text argument to it to give a description of what the field is and what the user should put into it. However, with a model method, help_text does not work. Adding the attribute short_description changes the way the method name is displayed, which is sort of okay, but I'm looking for a way to add a few sentences of description beneath the method value that is displayed. Is there any way to do this natively, or would I have to resort to overriding admin templates or something? (Which I do not think is worth it for something this minor).
You can do this using JS.
Replace ID-OF-THE-FIELD with the actual id of the desired field.
(function($) {
var myField = $('#ID-OF-THE-FIELD');
// find the id of the desired field by doing
// Right-Click > Inspect element
var help = $('<p class="help">A very long help text</p>');
help.insertAfter(myField);
})(django.jQuery);
Put this code into a JS file and supply this file using class Media of your ModelAdmin class.

In Django, when a UrlField is made read only, it prevents it from rendering as a clickable link. Why?

In Django (we are currently using 1.9), when we add an UrlField to a model, the Admin site correctly renders the UrlField value as a clickable link on edit views.
If we were to mark this UrlField as readonly (through the ModelAdmin  readonly_fields attribute), the value is then displayed as non-clickable plain text.
What is a rationale for this behaviour ?
Is there a way to work around it without changing the widget for the associated form field ?
I think it's just that readonly_fields displays the raw content (using the __str__() method) without any widget.
To work it around you might do something like this:
class MyAdmin (ModelAdmin):
readonly_fields = ['myurl_link']
def myurl_link(self, instance):
return format_html('<a href="{url}" target=_blank>{url}</a>', url=instance.myurl)
myurl_link.short_description = _("Website")

Replace "this field is required" message in django admin

is there a way to replace the default error message in django admin. I'm using custom widget so I have the form and I was wondering is there something like:
field_1 = forms.Charfield(widget=X, error_messge='y')
I already tried to add claen_field_1 method but it looks that it is not called when the field is empty. Any ideas will be appreciated
yes there is and actually this is forms functionality and not admin functionality ;), you can use this anywhere.
field_1 = forms.Charfield(widget=X, error_messages={'required': 'y'})
for more information see the django docs