django admin hierarchical inline model edit - django

Consider a wiki application. There is a model Page, that has many Revisions and each revision has many blocks.
What is the simplest way to create an admin in which, you select a page and all the blocks of the latest revision appear; bonus points for letting change of revision by a dropdown (which is by default, sorted in reverse order anyway)
Is it absolutely necessary to create views, or can I extend some of those StackedInline forms, override save and mention some magic meta options, to get it all done automagically.

Have you tried something like this (in admin.py):
class RevInline(admin.TabularInline):
model = Revision
class PageAdmin(admin.ModelAdmin):
model = Page
inlines = (RevInline,)
admin.site.register(Page, PageAdmin)

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

Add a form to admin side

I need to create a form to admin-side with two fields
Number of code: integer
Value of code: float
How can I do that. This form is not related to any model.
You can implement your modelless form as explained in #levi's answer.
Then, you can place it in the admin site in a number of different ways, depending your needs:
Make instances of the form available to all templates via a context processor, and override the admin templates to have it rendered wherever you want. You can create a view for only processing the form.
Create a view for both rendering and processing the form in a unique place, and hook it up to the admin as explained in the old Django Book, you'll need to make sure the template for that view extends one of the admin's templates (admin/change_form.html may be a good choice).
from django import forms
class Your_Form(forms.Form):
number_code = forms.IntegerField()
value_code = forms.FloatField()

django admin inlines (and nested inlines) : how can I get this functionality?

I'm a little confused as to why this sort of functionality isn't default in the admin, but maybe someone can give me a few hinters to how to go about it.
I have a projects application which keeps track of projects and is to be edited through the admin. Each project has numerous ForeignKey related models (links, flatpages, video, image etc.) that could be placed as inlines within the project admin.
(One or two models have nested inlines, so they don't display in the admin (this and this ticket deal with this) )
Instead of being able to edit these models inline on the project admin (which gets messy and difficult to use), I would love a list of all the current instances of that related model, and simple add/edit button for each model which opens a popup with that model's form.
Project Admin:
- Normal Fields
- Links:
-Link 1 (edit)
-Link 2 (edit)
+ add link <- popup
- Images:
-Image 1 (edit)
-Image 2 (edit)
+ add image <- popup
so on. How would I go about writing this? I only need to do it for one section/model of the admin panel so I don't think writing my own Crud backend is necessary.
Thanks
I implemented something like this in an application once, but since django-admin doesnt support nested inlines (by which i mean inlines within inlines), i followed a slightly different approach. The use case was that you had an invoice (with a few inline attributes) and u had reciepts (again with inline attributes). Reciepts had a foreign key to the invoice model (basically a reciept was part payment of the invoice).
I implemented it by adding a field to the invoice list view which linked to a filtered reciept list view.
So in the invoice admin, there would be:
def admin_view_receipts(self, object):
url = urlresolvers.reverse('admin:invoice_%s_changelist'%'receipt')
params = urllib.urlencode({'invoice__id__exact': object.id})
return 'Receipts' % (url, params)
admin_view_receipts.allow_tags = True
admin_view_receipts.short_description = 'Receipts'
This gives you a link in the list view that takes you to another list view, but filtered by foreignkey. Now you can have inlines for both models and easy access to the related models.

How do you modify the default widget for all builtin form fields of a certain type in Django?

This is a follow-up on How do you change the default widget for all Django date fields in a ModelForm?.
Suppose you have a very large number of models (e.g. A-ZZZ) that is growing with the input of other developers that are beyond your control, and you want to change the way all date fields are entered (i.e. by using jQueryUI). What's the best way to ensure that all date fields are filled out using that new widget?
One suggestion from the cited question was:
def make_custom_datefield(f):
if isinstance(f, models.DateField):
# return form field with your custom widget here...
else:
return f.formfield()
class SomeForm(forms.ModelForm):
formfield_callback = make_custom_datefield
class Meta:
# normal modelform stuff here...
However, is this possible to do where you don't have explicit ModelForm's, but url patterns come from models directly? i.e. your url config is likeso:
url(r'^A/?$', 'list_detail.object_list', SomeModelA)
where SomeModelA is a model (not a form) that's turned into a ModelForm by Django in the background.
At present in my system there are no Forms for each Model. The only point of creating forms explicitly would be to add the formfield_callback suggested in the prior solution, but that goes against DRY principles, and would be error prone and labour intensive.
I've considered (as suggested in the last thread) creating my own field that has a special widget and using that instead of the builtin. It's not so labour intensive, but it could be subject to errors (nothing a good grep couldn't fix, though).
Suggestions and thoughts are appreciated.
It sounds like you want to do this project-wide (ie: you're not trying to do this in some cases, but in ALL cases in your running application).
One possibility is to replace the widget attribute of the DateField class itself. You would need to do this in some central location... something that is guaranteed to be loaded by every running instance of the django app. Middleware can help with this. Otherwise, just put it in the __init__ file of your app.
What you want to do is re-assign the widget property for the forms.DateField class itself. When a new DateField is created, Django checks to see if the code specifies any particular widget in the field property definition. If not, it uses the default for DateField. I'm assuming that if a user in your scenario really defined a particular widget, you'd want to honour that despite the change to your global API.
Try this as an example of forcing the default to some other widget... in this case a HiddenInput:
from django import forms
forms.DateField.widget = forms.HiddenInput
class Foo(forms.Form):
a = forms.DateField()
f = Foo()
print f.fields['a'].widget
# results in <django.forms.widgets.HiddenInput object at 0x16bd910>

Multiple images per Model

I'm writing a simple real-estate listing app in Django. Each property needs to have a variable number of images. Images need to have an editable order. And I need to make the admin user-proof.
So that said, what are my options?
Is there a ImageList field that I don't know about?
Is there an app like django.contrib.comments that does the job for me?
If I have to write it myself, how would I go about making the admin-side decent? I'm imagining something a lot slicker than what ImageField provides, with some drag'n'drop for re-ordering. But I'm a complete clutz at writing admin pages =(
Variable lists, also known as a many-to-one relationship, are usually handled by making a separate model for the many and, in that model, using a ForeignKey to the "one".
There isn't an app like this in django.contrib, but there are several external projects you can use, e.g. django-photologue which even has some support for viewing the images in the admin.
The admin site can't be made "user proof", it should only be used by trusted users. Given this, the way to make your admin site decent would be to define a ModelAdmin for your property and then inline the photos (inline documentation).
So, to give you some quick drafts, everything would look something like this:
# models.py
class Property(models.Model):
address = models.TextField()
...
class PropertyImage(models.Model):
property = models.ForeignKey(Property, related_name='images')
image = models.ImageField()
and:
# admin.py
class PropertyImageInline(admin.TabularInline):
model = PropertyImage
extra = 3
class PropertyAdmin(admin.ModelAdmin):
inlines = [ PropertyImageInline, ]
admin.site.register(Property, PropertyAdmin)
The reason for using the related_name argument on the ForeignKey is so your queries will be more readable, e.g. in this case you can do something like this in your view:
property = Property.objects.get(pk=1)
image_list = property.images.all()
EDIT: forgot to mention, you can then implement drag-and-drop ordering in the admin using Simon Willison's snippet Orderable inlines using drag and drop with jQuery UI
Write an Image model that has a ForeignKey to your Property model. Quite probably, you'll have some other fields that belong to the image and not to the Property.
I'm currently making the same thing and I faced the same issue.
After I researched for a while, I decided to use django-imaging. It has a nice Ajax feature, images can be uploaded on the same page as the model Insert page, and can be editable. However, it is lacking support for non-JPEG extension.
There is a package named django-galleryfield. I think it will meet your demand.