0

I'm looking into creating some kind of dashboard to do some easy server admin tasks online. As much as possible stored in the database, so I could configure there tasks online instead of programming them.

What I'm trying to achieve in my data model is the following:

I have a model for Applications:

class Application(models.Model):
    name = models.CharField(max_length=30)

    def __str__(self):
        return self.name

In my Server model I have ManyToManyField mapping to my Applications model so I could select one or more applications which run on this server:

from applications.models import Application

class Server(models.Model):
    name = models.CharField(max_length=20,blank=False, null=False)
    application = models.ManyToManyField(Application, blank=True, related_name='applications')
    ip = models.CharField(max_length=15, blank=True)
    dns = models.CharField(max_length=100, blank=True)

To support multiple server types (web server, database), I have a Servertype model:

from applications.models import Application

class Servertype(models.Model):
    application = models.ForeignKey(Application, on_delete=models.CASCADE)
    type = models.CharField(max_length=20, blank=False, null=False)
    order = models.IntegerField(null=False)

    def __str__(self):
        return "%s - %s" % (self.application, self.type)

    class Meta:
        ordering = ["application", "order"]

Now I want to map these last 2 together, so I could link up Server and Servertype, but limit the Servertype choices to whatever is chosen as Application in Server, and is defined for this Application in Servertype. But I'm not fully sure how this would work. Certainly not like this:

from servers.models import Server
from applications.models import Application

class ServerServertype(models.Model):
    server = models.ForeignKey(Server, on_delete=models.CASCADE)
    applications = models.ForeignKey(Application, on_delete=models.CASCADE, limit_choices_to=Server)

Anyone an idea?

Ron
  • 119
  • 1
  • 10

2 Answers2

0

I think you should have a look at this answer here:

How do I restrict foreign keys choices to related objects only in django

It seems you then would be able to do something like this:

# Limit the choices of applications based on the selected applications for the server
self._meta.get_field('applications').limit_choices_to = {
    'pk__in': selected_applications.values_list('pk', flat=True)
}

Have you tried something like that?

EvilSmurf
  • 819
  • 1
  • 7
  • 21
0

for mapping between server and Servertype while limiting the choices for Servertype based on the selected applications for each server you don't need the intermediate model SeverServertype, you can use combination of ManyToManyField and custom filtering in the form

so you models.py should be like this:

from django.db import models

class Application(models.Model):
    name = models.CharField(max_length=30)

    def __str__(self):
        return self.name

class Servertype(models.Model):
    application = models.ForeignKey(Application, on_delete=models.CASCADE)
    type = models.CharField(max_length=20, blank=False, null=False)
    order = models.IntegerField(null=False)

    def __str__(self):
        return "%s - %s" % (self.application, self.type)

    class Meta:
        ordering = ["application", "order"]

class Server(models.Model):
    name = models.CharField(max_length=20, blank=False, null=False)
    server_types = models.ManyToManyField(Servertype, blank=True)

    ip = models.CharField(max_length=15, blank=True)
    dns = models.CharField(max_length=100, blank=True)

    def __str__(self):
        return self.name

and your forms.py should be like this:

from django import forms
from .models import Server

class ServerForm(forms.ModelForm):
    class Meta:
        model = Server
        fields = ['name', 'server_types', 'ip', 'dns']

    def __init__(self, *args, **kwargs):
        super(ServerForm, self).__init__(*args, **kwargs)

        # filter the Servertype choices based on selected applications for this server
        if self.instance.pk:
            self.fields['server_types'].queryset = Servertype.objects.filter(
                application__in=self.instance.application.all()
            )
        else:
            self.fields['server_types'].queryset = Servertype.objects.none()

now when you create or update a Server the server_type field in the form will display only the Servertype choices that are associated with the selected Application instances for that server.

remember to use ServerForm in your views.py when handling the creation and updating of Server.

so views.py should be something like this:

from django.shortcuts import render, redirect
from .models import Server
from .forms import ServerForm

def create_server(request):
    if request.method == 'POST':
        form = ServerForm(request.POST)
        if form.is_valid():
            server = form.save()
            # additional processing or redirect to server detail page
            return redirect('server_detail', pk=server.pk)
    else:
        form = ServerForm()
    return render(request, 'create_server.html', {'form': form})

def update_server(request, pk):
    server = Server.objects.get(pk=pk)
    if request.method == 'POST':
        form = ServerForm(request.POST, instance=server)
        if form.is_valid():
            server = form.save()
            # additional processing or redirect to server detail page
            return redirect('server_detail', pk=server.pk)
    else:
        form = ServerForm(instance=server)
    return render(request, 'update_server.html', {'form': form})

I hope this helps you.

Kiarash Gh
  • 166
  • 4