Q:

Join two tables with ManyToMany relationship and save data in intermediary model in Django

I have two tables with the ManyToMany relationship (Service andApiKey), as well as a third table that joins them. I have forms for adding a record to the database based on the model for these tables. I wish that when adding Service there was also a list of which key to bind to it.
How to do it???
Service:
class Service(models.Model):
    flow = models.ForeignKey(
        Flow,
        on_delete=models.CASCADE,
        related_name='services_flows'
    )
    currency = models.ForeignKey(
        Currency,
        on_delete=models.CASCADE,
        related_name='services_currencies'
    )
    contractor = models.ForeignKey(
        Contractor,
        on_delete=models.CASCADE,
        related_name='services_contractors',
    )
    amount = models.IntegerField(default=0)
    callback_url = models.CharField(
        max_length=128,
        blank=True,
        null=True,
        default=None,
    )
    definition = JSONField(null=True, blank=True, default=dict())
    name = models.CharField(max_length=255, db_index=True)
    description = models.TextField(null=True, blank=True)
    charge_strategy = models.CharField(max_length=64, default='default')
    routine = JSONField(null=True, blank=True, default=dict())
    service_key = models.ManyToManyField(ApiKey, through='ServiceKey',through_fields=('service', 'apikey'), related_name='key')

Apikey:
class ApiKey(models.Model):
    open_key = models.CharField(max_length=128)
    secret_key = models.CharField(max_length=128)
    description = models.CharField(max_length=128)
    restrict_ip = models.BooleanField()
    ip = ArrayField(
        models.CharField(max_length=32, blank=False, null=True), size=8, blank=True, null=True
    )
    valid_to_date = models.DateField()
    restrict_methods = models.BooleanField()
    allowed_methods = ArrayField(
        models.CharField(max_length=32, blank=True, null=True),
        size=8, blank=True, null=True
    )
    forbidden_methods = ArrayField(
        models.CharField(max_length=32, blank=True, null=True),
        size=8, blank=True, null=True
    )

Service_key - joins these two tables:
service_key
ServiceForm:
class ServiceForm(forms.ModelForm):
def __init__(self, *args, user=None, **kwargs):
    super(ServiceForm, self).__init__(*args, **kwargs)

class Meta:
    model = Service
    fields = [
        'name', 'amount', 'callback_url', 'charge_strategy',
        'description', 'definition', 'routine', 'contractor',
        'flow', 'currency', 'service_key'
    ]

    widgets = {
        'name': forms.TextInput(attrs={
            'class': ATTR_CLASS_DEFAULT,
            'placeholder': 'name'
        }),
        'amount': forms.NumberInput(attrs={
            'class': ATTR_CLASS_DEFAULT,
            'placeholder': 'amount'
        }),
        'callback_url': forms.TextInput(attrs={
            'class': ATTR_CLASS_DEFAULT,
            'placeholder': 'callback url'
        }),
        'charge_strategy': forms.TextInput(attrs={
            'class': ATTR_CLASS_DEFAULT,
            'placeholder': 'charge strategy',
            'readonly': 'True',
        }),
        'description': Textarea(attrs={
            'cols': 40,
            'rows': 5,
            'class': ATTR_CLASS_DEFAULT + 'sf-sm-fs',
            'placeholder': 'description',
        }),
        'definition': Textarea(attrs={
            'cols': 40,
            'rows': 5,
            'class': ATTR_CLASS_DEFAULT + 'sf-sm-fs',
            'placeholder': 'definition',
            'value': '',
            'data-is-json': 'True',
        }),
        'routine': forms.HiddenInput(),
        'contractor': forms.Select(attrs={
            'class': ATTR_CLASS_DEFAULT,
        }),
        'flow': forms.Select(attrs={
            'class': ATTR_CLASS_DEFAULT,
            'cols': 40, 'rows': 5,
        }),
        'currency': forms.Select(attrs={
            'class': ATTR_CLASS_DEFAULT,
            'cols': 4, 'rows': 5,
        }),
         'service_key': forms.Select(attrs={
            'class': ATTR_CLASS_DEFAULT,
        })
    }

    labels = {
        'name': 'name',
        'amount': 'amount',
        'callback_url': 'callback_url',
        'charge_strategy': 'charge_strategy',
        'description': 'description',
        'definition': 'definition',
        'routine': 'routine',
        'contractor': 'contractor',
        'flow': 'flow',
        'currency': 'currency',
        'service_key': 'service_key'
    }

View  Service:
class CreateServiceView(
    SuccessMessageMixin,
    CustomPermissionRequired,
    CreateView
):
    model = Service

    template_name = 'db_visual/create_service.html'

    form_class = ServiceForm

    permission_required = (
        'db_visual.add_service',
    )

    success_message = "service %(name)s created!"

    def get_form_kwargs(self):
        kwargs = super(CreateServiceView, self).get_form_kwargs()
        kwargs['user'] = self.request.user

        return kwargs

    def get_success_url(self):
        return reverse_lazy(
            'update_service',
            kwargs={'service_id': self.object.id}
        )

service_key model:
class ServiceKey(models.Model):
    service = models.ForeignKey(
        Service,
        on_delete=models.SET_NULL,
        related_name='service',
        null=True
    )
    apikey = models.ForeignKey(
        ApiKey,
        on_delete=models.SET_NULL,
        related_name='apikey',
        null=True
    )

UPD:I added apikey as ManyToManyfield, but I still don’t know how to save this to the table I need (maybe through the model ...) Also, when I tried to save the record, I get this error:  ValidationError
UPD2: I added an intermediate model, now I get the following error: error

A:

Django version form 2.2 supports M2M correctly

