forked from Fediversity/Fediversity
Add fields dynamicly to form and get_or_create in on step
This commit is contained in:
parent
4273c7a608
commit
99f1d78e29
6 changed files with 177 additions and 86 deletions
|
@ -1 +1,5 @@
|
|||
from django.contrib import admin
|
||||
from panel.models import Configuration
|
||||
|
||||
|
||||
admin.site.register(Configuration)
|
|
@ -1,44 +1,56 @@
|
|||
from django import forms
|
||||
from panel.models import (
|
||||
Configuration,
|
||||
PeertubeConfig,
|
||||
PixelfedConfig,
|
||||
MastodonConfig,
|
||||
)
|
||||
|
||||
from django.db import models
|
||||
from panel.models import Configuration
|
||||
|
||||
class Deployment(forms.ModelForm):
|
||||
"""Dynamically includes all related OneToOne fields from Configuration."""
|
||||
|
||||
class Meta:
|
||||
model = Configuration
|
||||
fields = [
|
||||
'domain',
|
||||
]
|
||||
fields = ['domain'] # Only the base model fields (related fields added dynamically)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
config = self.instance # The Configuration instance
|
||||
|
||||
operator = self.instance.operator.username
|
||||
self.fields['domain'].choices = [
|
||||
(code, f"{operator}.{label}")
|
||||
for code, label in self.instance._meta.get_field('domain').choices
|
||||
]
|
||||
model = Configuration
|
||||
fields = ['domain']
|
||||
# Dynamically add related model fields
|
||||
for field in config._meta.get_fields():
|
||||
if isinstance(field, models.OneToOneField): # Check for OneToOne fields
|
||||
related_instance = getattr(config, field.name, None)
|
||||
|
||||
# Auto-create related instance if missing
|
||||
if related_instance is None:
|
||||
related_instance = field.related_model.objects.create()
|
||||
setattr(config, field.name, related_instance)
|
||||
config.save()
|
||||
|
||||
class MastodonConfigForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = MastodonConfig
|
||||
fields = ['enable']
|
||||
# Add all BooleanFields from the related model
|
||||
for related_field in field.related_model._meta.get_fields():
|
||||
if isinstance(related_field, models.BooleanField):
|
||||
field_name = f"{field.name}_{related_field.name}" # e.g., "mastodon_enable"
|
||||
self.fields[field_name] = forms.BooleanField(
|
||||
required=False,
|
||||
initial=getattr(related_instance, related_field.name),
|
||||
label=f"{field.name.capitalize()} {related_field.name.capitalize()}"
|
||||
)
|
||||
|
||||
def save(self, commit=True):
|
||||
"""Saves the Configuration model and all related models dynamically."""
|
||||
config = super().save(commit=False) # Save Configuration model but don't commit yet
|
||||
|
||||
class PixelfedConfigForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = PixelfedConfig
|
||||
fields = ['enable']
|
||||
# Save related model fields dynamically
|
||||
for field in config._meta.get_fields():
|
||||
if isinstance(field, models.OneToOneField): # Only process related models
|
||||
related_instance = getattr(config, field.name)
|
||||
|
||||
for related_field in field.related_model._meta.get_fields():
|
||||
if isinstance(related_field, models.BooleanField): # Only BooleanFields
|
||||
field_name = f"{field.name}_{related_field.name}"
|
||||
setattr(related_instance, related_field.name, self.cleaned_data[field_name])
|
||||
|
||||
class PeertubeConfigForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = PeertubeConfig
|
||||
fields = ['enable']
|
||||
related_instance.save() # Save related model
|
||||
|
||||
if commit:
|
||||
config.save()
|
||||
|
||||
return config
|
|
@ -1,4 +1,4 @@
|
|||
# Generated by Django 4.2.16 on 2025-03-04 07:55
|
||||
# Generated by Django 4.2.16 on 2025-03-04 10:59
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
@ -15,36 +15,115 @@ class Migration(migrations.Migration):
|
|||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='MastodonConfig',
|
||||
name="MastodonConfig",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('enable', models.BooleanField(default=False)),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("enable", models.BooleanField(default=False)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PeertubeConfig',
|
||||
name="PeertubeConfig",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('enable', models.BooleanField(default=False)),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("enable", models.BooleanField(default=False)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PixelfedConfig',
|
||||
name="PixelfedConfig",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('enable', models.BooleanField(default=False)),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("enable", models.BooleanField(default=False)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Configuration',
|
||||
name="Configuration",
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('enable', models.BooleanField(default=False, help_text='Enable the configuration')),
|
||||
('domain', models.CharField(choices=[('fediversity_eu', 'fediversity.eu'), ('fediversity_net', 'fediversity.net')], max_length=255)),
|
||||
('mastodon', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='config', to='panel.mastodonconfig')),
|
||||
('operator', models.ForeignKey(help_text='Operator who owns the configuration', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='configurations', to=settings.AUTH_USER_MODEL)),
|
||||
('peertube', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='config', to='panel.peertubeconfig')),
|
||||
('pixelfed', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='config', to='panel.pixelfedconfig')),
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"enable",
|
||||
models.BooleanField(
|
||||
default=False, help_text="Enable the configuration"
|
||||
),
|
||||
),
|
||||
(
|
||||
"domain",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("fediversity_eu", "fediversity.eu"),
|
||||
("fediversity_net", "fediversity.net"),
|
||||
],
|
||||
max_length=255,
|
||||
),
|
||||
),
|
||||
(
|
||||
"mastodon",
|
||||
models.OneToOneField(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="config",
|
||||
to="panel.mastodonconfig",
|
||||
),
|
||||
),
|
||||
(
|
||||
"operator",
|
||||
models.ForeignKey(
|
||||
help_text="Operator who owns the configuration",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="configurations",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"peertube",
|
||||
models.OneToOneField(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="config",
|
||||
to="panel.peertubeconfig",
|
||||
),
|
||||
),
|
||||
(
|
||||
"pixelfed",
|
||||
models.OneToOneField(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="config",
|
||||
to="panel.pixelfedconfig",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
|
|
@ -24,6 +24,38 @@ class PeertubeConfig(models.Model):
|
|||
|
||||
|
||||
class Configuration(models.Model):
|
||||
class ConfigurationManager(models.Manager):
|
||||
# Define which related fields should be auto-created
|
||||
auto_create_related = [
|
||||
'mastodon',
|
||||
'pixelfed',
|
||||
'peertube',
|
||||
]
|
||||
|
||||
def create(self, **kwargs):
|
||||
# Create the model instance but don't save yet
|
||||
instance = self.model(**kwargs)
|
||||
|
||||
# Auto-create any missing related objects
|
||||
for field_name in self.auto_create_related:
|
||||
# Skip if the field was provided
|
||||
if field_name in kwargs:
|
||||
continue
|
||||
|
||||
# Get the related model class
|
||||
field = self.model._meta.get_field(field_name)
|
||||
related_model = field.related_model
|
||||
|
||||
# Create the related object
|
||||
related_obj = related_model.objects.create()
|
||||
|
||||
# Set the relation
|
||||
setattr(instance, field_name, related_obj)
|
||||
|
||||
# Save and return the instance
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
operator = models.ForeignKey(
|
||||
User,
|
||||
on_delete=models.SET_NULL,
|
||||
|
@ -48,3 +80,4 @@ class Configuration(models.Model):
|
|||
mastodon = models.OneToOneField(MastodonConfig, on_delete=models.CASCADE, related_name='config', null=True)
|
||||
pixelfed = models.OneToOneField(PixelfedConfig, on_delete=models.CASCADE, related_name='config', null=True)
|
||||
peertube = models.OneToOneField(PeertubeConfig, on_delete=models.CASCADE, related_name='config', null=True)
|
||||
|
||||
|
|
|
@ -4,9 +4,6 @@
|
|||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
|
||||
<h2>Services</h2>
|
||||
{{ children.as_p }}
|
||||
|
||||
<button class="button" disabled>Deploy</button>
|
||||
<button class="button" type="submit" >Save</button>
|
||||
</form>
|
||||
|
|
|
@ -9,15 +9,9 @@ from panel.models import Configuration
|
|||
from panel import forms
|
||||
from .models import (
|
||||
Configuration,
|
||||
MastodonConfig,
|
||||
PixelfedConfig,
|
||||
PeertubeConfig,
|
||||
)
|
||||
from .forms import (
|
||||
Deployment,
|
||||
MastodonConfigForm,
|
||||
PixelfedConfigForm,
|
||||
PeertubeConfigForm,
|
||||
)
|
||||
|
||||
|
||||
|
@ -44,33 +38,5 @@ class ConfigurationForm(LoginRequiredMixin, UpdateView):
|
|||
success_url = reverse_lazy('configuration_form')
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
obj, created = Configuration.objects.get_or_create(
|
||||
operator=self.request.user)
|
||||
|
||||
return obj
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
deploy_form = self.get_object()
|
||||
|
||||
context.update({
|
||||
'mastodon_form': MastodonConfigForm(self.request.POST or None, instance=deploy_form.mastodon),
|
||||
'pixelfed_form': PixelfedConfigForm(self.request.POST or None, instance=deploy_form.pixelfed),
|
||||
'peertube_form': PeertubeConfigForm(self.request.POST or None, instance=deploy_form.peertube),
|
||||
})
|
||||
|
||||
return context
|
||||
|
||||
def form_valid(self, form):
|
||||
response = super().form_valid(form) # Save main Configuration form
|
||||
obj = self.get_object() # Get instance
|
||||
|
||||
# Save related forms
|
||||
MastodonConfigForm(self.request.POST,
|
||||
instance=obj.mastodon).save()
|
||||
PixelfedConfigForm(self.request.POST,
|
||||
instance=obj.pixelfed).save()
|
||||
PeertubeConfigForm(self.request.POST,
|
||||
instance=obj.peertube).save()
|
||||
|
||||
return response
|
||||
obj, created = Configuration.objects.get_or_create(operator=self.request.user)
|
||||
return obj
|
Loading…
Add table
Reference in a new issue