Use autocomplete light with django-tables2 - python

I'm trying to populate a django table with autocomplete light so that the user can fill in data in the table, which would then be saved (the whole table is in a form tag). I have the table working to display the existing data and I have the autocomplete working in model forms (well, a team member got that part working), but I don't know how to combine the two. The docs are a bit of a mystery to me, but maybe if someone could at least point me in the right direction I'd greatly appreciate it.
I've tried a few random things to combine them, but honestly they were such stabs in the dark that I don't think they're even worth mentioning.
tables.py
class ModifyTable(tables.Table):
name = tables.LinkColumn('app-view', args=[A('pk')], verbose_name='Name')
primary_contact = tables.Column()
secondary_contact = tables.Column()
autocomplete
autocomplete_light.register(Person,
search_fields=['first_name', 'last_name', 'username'],
split_words=True,
autocomplete_js_attributes={'placeholder': 'Find a user',},
)

Django-tables2 provides an API to generate data tables in HTML.
Django-autocomplete-light provides a widget that enables autocompletion inputs.
This widget must be used in a Form. The django Form class will combine your the HTML <form> with models used by django-tables2.
However, a Form must be used by a Formsets to be repeated for every row in the table. Note that you could consider modelformset_factory to generate such a formset.
Use a formset and your work is done here ;)

Related

Django: override form validation to get around this error

My specific problem is detailed below, but the main point of my question is this: When I click "Save" on the Django admin form while editing a model, what happens? What is the order of the validation/save process? How can I override these methods to solve my problem below, which is to say updating an intermediate table at the appropriate time as a workaround for the issue I described?
I'm working on a Django application which is facing a PostgreSQL database. The database is relatively large, and I have a lot of many-to-many relationships. The one that I am currently having an issue with is the n:m relationship between People and Sources.
The app is used mainly by non-technical people to add to the database through Django's built-in admin feature. The primary issue that I was having when I started working on the app was severe page slowdown when editing a Person on the admin site. If the person had too many Sources, each drop-down in the TabularInline representation of sources loaded thousands of entries. I found a workaround and overrode the get_formfield_for_foreignkey() method as follows:
def formfield_for_foreignkey(self, db_field, request, **kwargs):
field = super(SourceMaterialInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
# We will overwrite this method to ONLY return relevant materials on this person
materials = SourceMaterial.objects.all()
materials_p = SourceMaterial.people.through.objects.all()
person_ID = get_ID_from_path(request.path)
if not_integer(person_ID):
return field
materials_pid = materials_p.filter(person_id=person_ID)
# The next step is to use these relevant materials to obtain the SourceMaterial objects from the SourceMaterial table
relevant_ids = []
for mat in materials_pid:
relevant_ids += [mat.sourcematerial_id]
relevant_materials = materials.filter(id__in=relevant_ids)
# now we can set the queryset so that only relevant materials are included
field.queryset = relevant_materials
return field
So this accomplishes what I wanted. When you go to edit a Person object through the Admin page, the dropdown menus to select sources only load and display Sources that belong to that Person.
The problem this creates, however, is when I go to add a new Source via the Person change form. I would like to keep this functionality, but it is now broken.
If I go to add a new source, a pop-up window appears. I select the file on my machine, give it a name and click add. At this point it is added to the Sources table, but not to the intermediate table linking it to this Person. When I go to save the Person, the form asks me to correct this error: Select a valid choice. That choice is not one of the available choices.
Here is the pop-up: Add new source material pop-up for clarity
This makes sense, as there is no established link between the Person and the Source yet. So instead I try adding the Person ID as well when adding a source this way, and the error is: Sourcematerial-person relationship with this Sourcematerial and Person already exists. I'm assuming this is because when I add the Source with the Person ID, the intermediate table is populated appropriately, and when I go to save, it tries to add the source again, because the form detects it as being new.
I'm hoping I can override form validation/saving so that I can keep functionality of adding a Source to the database this way. If anybody has any suggestions as to what exactly I could override (I was very confused by the docs) or another work around, that'd be great. Thanks!

CheckboxSelectMultiple not displaying checkboxes with Django-Material

I'm fairly new to Django so please bear with me.
I'm using a ModelForm along with Django-Material (By Viewflow) and it's working really well expect for one thing. It doesn't display checkboxes.
My 'Person' model has a ManyToMany relationship with 'Problem' and I've set the form to show checkboxes as so -
class PersonForm(forms.ModelForm):
class Meta:
model = Person
exclude = ('',)
widgets = {
'problems': forms.CheckboxSelectMultiple(),
}
But it shows up like this
When I remove the Material template the checkboxes show up properly
I'm not really sure if there's a problem with Django-Material or something I may have missed. Help would be really appreciated, thanks!
Actually it was not implemented in time when question was.
Not it works as expected and in addition could be rendered in several columns
http://forms.viewflow.io/demo/hospital/
Alright, so it turned out that they haven't included that functionality in Django-Material yet

Django form to create several objects with one-to-one relation

I have several models with one-to-one relation. For example
class Task(models.Model):
initial_comment = models.OneToOneField('Comment')
# A pack of other fields
class Comment(models.Model)
body = RichTextField()
# A pack of other fields
I want to create "create view" based on form, that gives user ability to create task and initial comment there.
I can't use CreateView because it is based on only one model
I can't use ModelForm because it is based on only one model
I can create several forms, but I can't join them into one formset (forms are different)
I feel "inlineformset_factory" (InlineFormSet) should be used here, but I am not sure it suits best. Is there any 3rd party Django app to do that?
Sure I can create form myself, but I do not want to copy/paste all fields, their types, localized labels, validations and so on. I just want to list their names (like fields attibute).
I can also have 2 forms and support them everywhere and track dependencies manually (save comments first), like in How can create a model form in django with a one-to-one relation with another model , but I hope there has to be better solution.
If you wonder why do I need one-to-one: Comments are used heavily in other places and have different relations with different models.
The inline_formset factory is correct. There are no standard generic views for this, but there is a third party package with generic views to do what you are wanting. Its in the standard Django way of doing things.
https://github.com/AndrewIngram/django-extra-views
You probably want to use the CreateWithInlinesView for that.
Well, I found solution.
CreateWithInlinesView works perfectly with OneToOneField (after all, 1-to-1 is just a foreign key with constraint), but my main model here is Comment, not Task. So I should set Comment as model field in this view and Task as inline. It looks silly. I will create custom form or review my model structure.

Can't create a form to upade part of a model field

This is really frustrating,
I can't and can't find how to create a form (I'm guessing a forms.Form form) to update just one field of a more complex model.
The model has 5 fields, and a form to create, update all of them.
But in a different case i need to let the user update only the title (a field in the model), so i need tried so many things until now (including creating an HTML form by hand and from the view to save it, creating a forms.Form and many more, nothing seem to work), There is no code here because i don't even know which one to put....
Maybe some one can help me with that, I'm sure it is a simple thing, But for some reason i am stuck on this for a long time...
Thank you,
Erez
If you're using ModelForms, you just have to define a fields attribute in Meta as a tuple containing just the names of the fields you want. See the documentation.

Return template as string - Django

I'm still not sure this is the correct way to go about this, maybe not, but I'll ask anyway. I'd like to re-write wordpress (justification: because I can) albeit more simply myself in Django and I'm looking to be able to configure elements in different ways on the page. So for example I might have:
Blog models
A site update message model
A latest comments model.
Now, for each page on the site I want the user to be able to choose the order of and any items that go on it. In my thought process, this would work something like:
class Page(models.Model)
Slug = models.CharField(max_length=100)
class PageItem(models.Model)
Page = models.ForeignKey(Page)
ItemType = models.CharField(max_length=100) # tells me which model to display
InstanceNum = models.IntegerField() # tells me which instance of which model...
Then, ideally, my template would loop through all the PageItems in a page which is easy enough to do.
But what if my page item is a site update as opposed to a blog post? Basically, I am thinking I'd like to pull different item types back in different orders and display them using the appropriate templates. Now, I thought one way to do this would be to, in views.py, to loop through all of the objects and call the appropriate view function, return a bit of html as a string and then pipe that into the resultant template.
My question is - is this the best way to go about doing things? If so, how do I do it? If not, which way should I be going? I'm pretty new to Django so I'm still learning what it can and can't do, so please bear with me. I've checked SO for dupes and don't think this has been asked before...
I've also looked at Django-cms to see if that helps, but I couldn't get to grips with it.
Any suggestions?
First, some puzzelement.
InstanceNum = models.IntegerField() # all models have primary keys.
In Django, all model are assigned an integer primary key.
The comment doesn't make sense, since you don't need to add a primary key like this. The PageItem already has a primary key.
Also, please use lower case letters for attributes. Only Use Upper Case for Class Names. Please.
"But what if my page item is a site update as opposed to a blog post? Basically, I am thinking I'd like to
pull different item types back in
different orders and display them
using the appropriate templates"
Different types usually means different models. Rather than a vague "PageItem", you probably want to have "Site Update" and "Blog Post" as separate models.
You can then iterate through these various objects and display them in the template.
You can easily have your various Models defined with a method to return HTML information. You don't (generally) want to return fully-baked HTML. But CSS ID or Class information is sometimes helpful.
class SiteUpdate( models.Model ):
page = models.ForeignKey(Page)
item_text = models.CharField(max_length=100)
item_css_class = models.CharField(max_length=64)
Now you can generate this into the template with a simple <div class="{{item.item_css_class}}">{{item.item_text}}</div> and use CSS to handle the formatting details that distinguish site update as opposed to a blog post.
The include template tag can take a variable containing the template to include, so you could loop through a sequence containing the various sub-templates and include them in turn, maybe using a dict to map friendly names to template filenames.

Categories