I'm new to the flask-admin library so please forgive me if this is trivial. When I click 'Save' to create a new row for a model, I also want to do some custom things. In my case, I'll create a table dynamically whose name is the string entered in the form. This will be in addition to what flask-admin does for me i.e. add a new row to the model table. So where will I put the custom logic to do what I want to do? I saw this post on so: Customize (override) Flask-Admin's Submit method from edit view with Joe's answer about overriding on_model_change but I'll like some more explanation. From the docs, it says that on_model_change is called from update_model and create_model. When I click on the source link to the right, I get to: http://flask-admin.readthedocs.org/en/latest/_modules/flask_admin/model/base/#BaseModelView.create_model . It doesn't show the code. So I don't know how it is implemented.
Can someone please illustrate what I'm trying to in a simple sample code? Thanks.
The right way of doing this (as you have mentioned) is through after_model_change function. Quoting Flask-Admin source code
def after_model_change(self, form, model, is_created):
"""
Perform some actions after a model was created or updated and
committed to the database.
Called from create_model after successful database commit.
By default does nothing.
:param form:
Form used to create/update model
:param model:
Model that was created/updated
:param is_created:
True if model was created, False if model was updated
"""
pass
So basically, in your case, you need to perform the table creation inside this function on your model. Namely
class MyModelView(BaseModelView):
column_list = ('fieldX', 'fieldY')
def after_model_change(self, form, model, is_created):
tablename = form.tablename
if is_created: # create the table just once
perform_dynamic_table_creation(conn,tablename)
Related
I have a form (ModelForm) in Django, where I am adding a field for users in the init method as so:
self.fields["users"] = forms.ModelMultipleChoiceField(
queryset=users, widget=forms.CheckboxSelectMultiple, required=False,label="Add Designer(s)"
)
In the save method how I can iterate over the queryset for this field, however, I do not know how I can test if the particular model has been selected/checked. Help, please.
EDIT:
Let's say that you have a form where you want to be able to add users to a certain project, I set the users field as above (also usedMultipleChoiceField) but my real question is how do you determine the state of those checkboxes (which users should be added)?
Managed to fix it using MultipleChoiceField instead of ModelMultipleChoiceField. Then populated the choices with existing event IDs and passed it to the template.
In forms:
choices = forms.MultipleChoiceField(widget = forms.CheckboxSelectMultiple())
In views:
form.fields['choices'].choices = [(x.eventID, "Event ID: " + x.eventID) for x in unapproved]
Had to change some of the logic for finding and editing Event objects too.
The Django documentation states that a ModelMultipleChoiceField normalizes to a QuerySet of model instances. That means in your example, it will only return the users that have been checked. If none have been checked, it will return an empty QuerySet.
If you are overriding your ModelForm save method, you could include something like this:
selected_users = self.cleaned_data.get('users')
for user in selected_users:
project_users.add(user)
For example, if I had a model: StoragePosition(models.Model) which has a field, 'name'.
I would want to enter the model's list/change view. Then select a few items, choose a 'copy names to clipboard' action. Then be able to paste in the format:
name_1
name_2
name_3
I would especially want it to be able to paste contents into an excel spreadsheet, each name in its own cell.
I found a very simple solution to the actual problem by using no external dependencies and no javascript.
I really just wanted a view with the information I required on its own, listed one beneath the other.
In admin.py:
def copy_selection_to_clipboard(modeladmin, request, queryset):
return HttpResponse("<br>".join([str(q) for q in queryset]))
copy_selection_to_clipboard.short_description = 'Copy selection to clipboard'
In MyModelAdmin(admin.ModelAdmin):
...
actions = (copy_selection_to_clipboard,)
...
I am yet to test #martin-stoyanov's answer out, so won't mark this as accepted answer yet. Also, unlikely to be marked as such since it provides a workaround to the problem and not a direct solution to it.
Check Pyperclip.
You can define your own main action in model's list by doing:
import pyperclip
def copy_selected_to_clipboard(modeladmin, request, queryset):
#pyperclip code example
pyperclip.copy('The text to be copied to the clipboard.')
#or whatever logic you need.
Then include it in your ModelAdmin class as following:
MyModelAdmin(admin.ModelAdmin):
actions = ['copy_selected_to_clipboard', ] // <-- include list function here
I'd like to create a confirmation page for selected objects before a change is made to them (outside the admin). The objects can be of different models (but only one model a time).
This is much like what is done in administration before deletion. But the admin code is complex and I haven't grasped how it is done there.
First I have severall forms that filter the objects differently and then I pass the queryset to the action / confirmation page. I have created a form factory so that I can define different querysets depending on model (as seen in another similiar question here at Stackoverflow):
def action_factory(queryset):
''' Form factory that returns a form that allows user to change status on commissions (sale, lead or click)
'''
class _ActionForm(forms.Form):
items = forms.ModelMultipleChoiceField(queryset = queryset, widget=forms.HiddenInput())
actions = forms.ChoiceField(choices=(('A', 'Approve'), ('D' ,'Deny'), ('W' ,'Under review'), ('C' ,'Closed')))
return _ActionForm
Which I use in my view:
context['form']=action_factory(queryset)()
The problem is that the items field wont be displayed at all in the html-code when it is hidden. When I remove the HiddenInput widget it displays the form correctly.
I don't want to display the choice field since there can be thousands of objects. All I want to have is something like "Do you want to change the status of 1000 objects" and a popdown and a submit button. A simple enough problem it seems, but I can't get it to work.
If someone has a solution to my current attempt I would be glad to hear how they have done it. Even better would be if there is a cleaner and better solution.
I used the wrong widget. It should be MultipleHiddenInput not HiddenInput.
I have been working on forms only recently and I am still puzzeld by them.
What I want are standard Forms:
Next Button
Submit Data to Db
Timestamp
Clickable Images with Regions defined where when I click I get to the next page
And
I would like to combine these.
E.g. have a next button + Record the Timestamp.
or
E.g. Click into an Image + Next + Timestamp
If anybody could give me some examples for code that can achieve that or a good online resource on where to get info on that, that would be awesome.
Thanks for the time!!
I'm a little unclear about what you're trying to accomplish, but if you're trying to move data from an HTML form to the database, I'd suggest looking at how to use ModelForms. In a nutshell, you create a model class, like this:
class MyModel(models.Model):
field1 = models.CharField(max_length=50)
Then you create a ModelForm class that references that model:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
You can render an instance of MyModelForm in a view function. Inside of a POST request in that view, you bind the POST data to the form, validate it, and call save() on it to commit it to the database:
if request.method == 'POST':
form = MyModelForm(request.POST)
if form.is_valid():
model_instance = form.save()
This really isn't a question, I'm not exactly sure what you're trying to accomplish.
If you want to use Django forms, start here, or here.
I assume the stuff you mention about a timestamp should probably be an auto_now field in a model. Take a look at this.
The stuff you mention about buttons and click-able images is really just HTML and has nothing to do with Django. I would try Google for that.
Here, I am a bit confused with forms in Django. I have information for the form(a poll i.e the poll question and options) coming from some db_table - table1 or say class1 in models. Now the vote from this poll is to be captured which is another model say class2. So, I am just getting confused with the whole flow of forms, here i think. How will the data be captured into the class2 table?
I was trying something like this.
def blah1()
get_data_from_db_table_1()
x = blah2Form()
render_to_response(blah.html,{...})
Forms have nothing to do with models in Django. They are just class meant to get informations from a dictionary (often request.POST) and check if each data linked to a key match a type and a format (e.g: is this a string of the form "bla#foo.tld").
You can ask django to create a form from a model, and in that case it will do its checking job, then if the data match, it will create a model, fill it and save it.
If a form is not created from a model, it will do nothing but checking. It will save nothing.
If it is created from a model, it will create a new instance of this particular model instance and save it.
If you want something more complicated, like, pre fill a form from various models or according to some conditions, or, say, you need to save several models according to the result of one form, you must do it manually.