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

ChainedForeignKey should also provide an option by means of which we can target a specific field #310

Open
6 of 7 tasks
SilverFoxA opened this issue Aug 20, 2020 · 6 comments

Comments

@SilverFoxA
Copy link

You MUST use this template when reporting issues. Please make sure you follow the checklist and fill in all of the information sections below.


All versions of django-smart-selects prior to version 1.2.8 are vulnerable to an XSS attack as detailed in issue 171. As a result, all previous versions have been removed from PyPI to prevent users from installing insecure versions. All users are urged to upgrade as soon as possible.

Checklist

Put an x in the bracket when you have completed each task, like this: [x]

  • This issue is not about installing previous versions of django-smart-selects older than 1.2.8. I understand that previous versions are insecure and will not receive any support whatsoever.
  • I have verified that that issue exists against the master branch of django-smart-selects.
  • I have searched for similar issues in both open and closed tickets and cannot find a duplicate.
  • I have debugged the issue to the smart_selects app.
  • I have reduced the issue to the simplest possible case.
  • I have included all relevant sections of models.py, forms.py, and views.py with problems.
  • I have used GitHub Flavored Markdown to style all of my posted code.

Steps to reproduce

  1. Git clone the master to a app directory
  2. Add the app in Installed apps
  3. Started using the portal

Actual behavior

Inline form don't show any fields.

Expected behavior

Ideal case is that we should be able to see the options.

I'm trying to address the following:

  • Product variations : We are offering admins the feasibility to create dynamic options in the backend. Ex. Color and values are - Red, Blue. Where, color is the option and Red, Blue are the Option Values.
OPTION_TYPE = (
    ('select', 'Select'),
    ('radio', 'Radio'),
    ('checkbox', 'Checkbox')
)
class Option(models.Model):
    id = models.AutoField(db_index=True, primary_key=True)
    type = models.CharField(max_length=32, choices=OPTION_TYPE, default='select')
    sort_order = models.IntegerField(default=0, blank=True)
    name = models.CharField(db_index=True, max_length=128)
    show_image = models.BooleanField(default=True)
class OptionValue(models.Model):
    id = models.AutoField(db_index=True, primary_key=True)
    name = models.CharField(max_length=128)
    image = models.ImageField(null=True, blank=True, upload_to='uploads/optionValue/%Y/%m/%d',
                              validators=[FileExtensionValidator(allowed_extensions=('png', 'jpg', 'jpeg', 'svg'))])
    sort_order = models.IntegerField(default=0, blank=True)

    option_id = models.ForeignKey(
        'catalog.Option',
        db_index=True, on_delete=models.CASCADE,
    )
  • Post adding the options in the backend, admin can now link these to a product - we are calling ProductOption & ProductOptionValue
class ProductOption(models.Model):
    id = models.AutoField(db_index=True, primary_key=True)
    required = models.BooleanField(default=True)

    product_id = models.ForeignKey(
        'catalog.Product', null=True,
        db_index=True, on_delete=models.CASCADE,
    )
    option_id = models.ForeignKey(
        'catalog.Option', null=True,
        db_index=True, on_delete=models.CASCADE,
    )
class ProductOptionValue(models.Model):
    id = models.AutoField(db_index=True, primary_key=True)
    price = models.DecimalField(db_index=True, max_digits=19, decimal_places=4)
    price_prefix = models.CharField(max_length=1, choices=PRODUCT_OPTION_PREFIX, default="+")

    product_option_id = models.ForeignKey(
        'catalog.ProductOption',
        db_index=True, on_delete=models.CASCADE,
    )

    option_value_id = ChainedForeignKey(
        'catalog.OptionValue',
        chained_field="product_option_id",
        chained_model_field="option_id",
        show_all=False,
        auto_choose=True,
        sort=True
    )

Screenshot_5

If you notice this ChainedForeignKey field, we are referring to the model but the ideal chained_field should be option_id from the model ProductOption

option_value_id = ChainedForeignKey(
        'catalog.OptionValue',
        chained_field="product_option_id",
        chained_model_field="option_id",
        show_all=False,
        auto_choose=True,
        sort=True
    )

Is there an option where instead of just defining the entire model we can also refer to a particular field as the chained_field ?

@manelclos
Copy link
Member

Hi @SilverFoxA,

We had the same problem when trying to convert a Foreign Key using to_field option, which smart selects does not support.

I'm marking this as a feature request.

@SilverFoxA
Copy link
Author

Hello @manelclos,

Have you found any workaround yet? I'm trying to debug but failed to see any request log on the console/network.

@manelclos
Copy link
Member

@SilverFoxA after looking carefully at your example, I think that what smart selects needs to implement is following relationships in the chained field, in your case that would be something like:

chained_field="product_option_id__option_id",

That would be an Option model which is a parent of OptionValue. Unfortunately I don't know how difficult this would be to implement.

As a workaround, I think you would be successful by adding a Foreign Key to Option in the ProductOptionValue model, this is untested:

class ProductOptionValue(models.Model):
    id = models.AutoField(db_index=True, primary_key=True)
    price = models.DecimalField(db_index=True, max_digits=19, decimal_places=4)
    price_prefix = models.CharField(max_length=1, choices=PRODUCT_OPTION_PREFIX, default="+")

    product_option_id = models.ForeignKey(
        'catalog.ProductOption',
        db_index=True, on_delete=models.CASCADE,
    )

    option_id = ChainedForeignKey(
        'catalog.Option',
        chained_field="product_option_id",
        chained_model_field="option_id",
        show_all=False,
        auto_choose=True,
        sort=True
    )

    option_value_id = ChainedForeignKey(
        'catalog.OptionValue',
        chained_field="option_id",
        chained_model_field="option_id",
        show_all=False,
        auto_choose=True,
        sort=True
    )

@SilverFoxA
Copy link
Author

SilverFoxA commented Aug 21, 2020

@manelclos Thank you for your prompt response. I would suggest we look at an approach similar to what you have suggested

chained_field="product_option_id__option_id",

The other workaround which you have pointed is something we want to ignore as that will not work for the instance when the product is being created. There's another approach where we ignore the entire productoption and productionoptionvalue model and merge them in one, but that will be just another workaround.

For now we are going for a quickfix with the formset js, as I have limited time. Hoping to contribute on this issue soon.

@charles-co
Copy link

Any update on this yet? currently having the same issue. Are there alternatives, any response will be appreciated. Thanks.

@joel-fmjr
Copy link

Any update here? Or alternatives

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants