Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chainfield as FilteredSelectMultiple #337

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions smart_selects/static/smart-selects/admin/js/bindfields.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
}
}

$(window).on('load', function () {
$(document).ready(function () {
$.each($(".chained-fk"), function (index, item) {
initItem(item);
});
$.each($(".chained"), function (index, item) {
initItem(item);
});
Expand All @@ -31,12 +34,6 @@
});
});

$(document).ready(function () {
$.each($(".chained-fk"), function (index, item) {
initItem(item);
});
});

function initFormset(chained) {
var re = /\d+/g,
prefix,
Expand Down
61 changes: 51 additions & 10 deletions smart_selects/static/smart-selects/admin/js/chainedm2m.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,27 +134,68 @@
trigger_chosen_updated();
});
},

init: function (chainfield, url, id, value, auto_choose) {
var fill_field, val, initial_parent = $(chainfield).val(),
initial_value = value;

// In case of filtered chainfield.
var chainfield_filtered = chainfield + '_to';

if (!$(chainfield).hasClass("chained")) {
val = $(chainfield).val();
this.fill_field(val, initial_value, id, url, initial_parent, auto_choose);
}
fill_field = this.fill_field;
$(chainfield).change(function () {
var prefix, start_value, this_val, localID = id;
if (localID.indexOf("__prefix__") > -1) {
prefix = $(this).attr("id").match(/\d+/)[0];
localID = localID.replace("__prefix__", prefix);

if($(chainfield_filtered).length) {
/**
* Handle chainfield with filtered elements.
*
* The option selection is completely different compared to the `$(chainfield).change` call.
*
* Keep track on DOM modifications and submit the fill_field function using the
* rendered options of the element `chainfield_filtered` ( #id_<chainfield>_to ).
*/

var options = 0;
var timeoutID = null;

function onSubtreeModified() {
var optionElements = $(chainfield_filtered).children('option')
if(options !== optionElements.length) {
options = optionElements.length

var val = optionElements.map((idx, ele) => $(ele).val())

/**
* DEBOUNCE, avoid redundant calls
* DOMSubtreeModified is invoked multiple times during the multiple
* selection, avoid redundant queries using the timeout as debounce.
*/
if(timeoutID) clearTimeout(timeoutID)
timeoutID = setTimeout(function() {
fill_field(val.length ? Array.from(val) : false, initial_value, id, url, initial_parent, auto_choose);
}, 200);
}
}

start_value = $(localID).val();
this_val = $(this).val();
fill_field(this_val, initial_value, localID, url, initial_parent, auto_choose);
});
$(chainfield_filtered).on("DOMSubtreeModified", onSubtreeModified)

// initial
onSubtreeModified()
} else {
$(chainfield).change(function () {
var prefix, start_value, this_val, localID = id;
if (localID.indexOf("__prefix__") > -1) {
prefix = $(this).attr("id").match(/\d+/)[0];
localID = localID.replace("__prefix__", prefix);
}

start_value = $(localID).val();
this_val = $(this).val();
fill_field(this_val, initial_value, localID, url, initial_parent, auto_choose);
});
}

// allait en bas, hors du documentready
if (typeof(dismissAddAnotherPopup) !== 'undefined') {
Expand Down
7 changes: 6 additions & 1 deletion test_app/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
Location,
Publication,
Book,
BookStore,
Writer,
Grade,
Team,
Expand Down Expand Up @@ -47,7 +48,6 @@ class AreaAdmin(admin.ModelAdmin):
class LocationAdmin(admin.ModelAdmin):
list_display = ("continent", "country", "city", "street")


class PublicationAdmin(admin.ModelAdmin):
list_display = ("name",)

Expand All @@ -56,6 +56,10 @@ class BookAdmin(admin.ModelAdmin):
list_display = ("name",)


class BookStoreAdmin(admin.ModelAdmin):
list_display = ('name', )
filter_horizontal = ('books', )

class WriterAdmin(admin.ModelAdmin):
list_display = ("name",)

Expand Down Expand Up @@ -127,3 +131,4 @@ class TalentAdmin(admin.ModelAdmin):
admin.site.register(Person, PersonAdmin)
admin.site.register(Group, GroupAdmin)
admin.site.register(Talent, TalentAdmin)
admin.site.register(BookStore, BookStoreAdmin)
140 changes: 140 additions & 0 deletions test_app/migrations/0008_auto_20211027_1307.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Generated by Django 3.2.8 on 2021-10-27 13:07

from django.db import migrations, models
import django.db.models.deletion
import smart_selects.db_fields


class Migration(migrations.Migration):

dependencies = [
('test_app', '0007_auto_20200207_1149'),
]

operations = [
migrations.AlterField(
model_name='area',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='book',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='book1',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='book1',
name='writer',
field=smart_selects.db_fields.ChainedManyToManyField(chained_field='publication', chained_model_field='publications', limit_choices_to={'name__contains': '2'}, to='test_app.Writer'),
),
migrations.AlterField(
model_name='client',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='continent',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='country',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='domain',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='grade',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='group',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='location',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='location1',
name='country',
field=smart_selects.db_fields.ChainedForeignKey(auto_choose=True, chained_field='continent', chained_model_field='continent', limit_choices_to={'name__startswith': 'G'}, on_delete=django.db.models.deletion.CASCADE, to='test_app.country'),
),
migrations.AlterField(
model_name='location1',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='membership',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='person',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='publication',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='student',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='tag',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='tagresource',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='talent',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='team',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='website',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.AlterField(
model_name='writer',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
migrations.CreateModel(
name='BookStore',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=255)),
('books', models.ManyToManyField(blank=True, to='test_app.Book')),
('publications', smart_selects.db_fields.ChainedManyToManyField(chained_field='books', chained_model_field='book', horizontal=True, related_name='stores', to='test_app.Publication')),
('writers', smart_selects.db_fields.ChainedManyToManyField(chained_field='books', chained_model_field='book', related_name='stores', to='test_app.Writer')),
],
),
]
26 changes: 26 additions & 0 deletions test_app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ class Book(models.Model):
)
name = models.CharField(max_length=255)

def __str__(self):
return "%s" % self.name


# test limit_to_choice field option
class Book1(models.Model):
Expand All @@ -102,6 +105,29 @@ class Book1(models.Model):
)
name = models.CharField(max_length=255)

# test based on chainfield with filtered many_to_many

class BookStore(models.Model):
name = models.CharField(max_length=255)
books = models.ManyToManyField('Book', blank=True)

publications = ChainedManyToManyField(
"Publication",
chained_field="books",
chained_model_field="book",
related_name="stores",
horizontal=True
)

writers = ChainedManyToManyField(
"Writer",
chained_field="books",
chained_model_field="book",
related_name="stores"
)




# group foreignkey
class Grade(models.Model):
Expand Down