Hey so I'm having quite some problems. In effect trying to add a form to a home-page with options for a user to select based on a DB object. Then once submitted the page will refresh, and the form can be used again.
Forms.py
rom django import forms
from django.forms import ChoiceField, ModelForm, RadioSelect
from .models import command_node
class command_form(ModelForm):
class Meta:
model = command_node
fields = (
'host_id',
'current_commands'
)
host_id = forms.ModelChoiceField(
required=True,
queryset=command_node.host_id,
widget=forms.Select(
attrs={
'class': 'form-control'
},
)
)
current_comamnds = forms.ChoiceField(
required=True,
attrs={
'class': 'form-control'
},
choices=[
('Sleep', "Sleep"),
('Open SSH_Tunnel', 'Open SSH_Tunnel'),
('Close SSH_Tunnel', 'Close SSH_Tunnel'),
('Open TCP_Tunnel', 'Open TCP_Tunnel'),
('Close TCP_Tunnel', 'Close TCP_Tunnel'),
('Open Dynamic', 'Open Dynamic'),
('Close Dynamic', 'Close Dynamic'),
('Task', 'Task'),
])
Models.py
from tkinter import CASCADE
from turtle import update
from django.db import models
class beacon(models.Model):
host_id = models.BigAutoField('Id', primary_key=True)
hostname = models.CharField('Hostname', max_length=200)
internalIp = models.CharField('Internal-IP', max_length=200)
externalIp = models.CharField('External-IP', max_length=200)
current_user = models.CharField('Current_User', max_length=200)
os = models.CharField('OS', max_length=200)
admin = models.CharField('Admin', max_length=200)
def __str__(self):
return self.hostname
class command_node(models.Model):
host_id = models.ForeignKey(beacon, on_delete=models.CASCADE)
current_commands = models.CharField('current_command', max_length=50, null=True)
previous_commands = models.CharField('previous_commands', max_length=2000, null=True)
def __str__(self):
return str(self.host_id)
views.py
from django.shortcuts import render
from django.http import HttpResponse
from .models import beacon
from .models import command_node
from .forms import command_form
from django.http import HttpResponseRedirect
def home(request):
form = command_form,
if request.method == "POST":
form = form(request.POST)
if form.is_valid():
form.save()
return render(request, 'home.html', context)
context = {'form':form},
return render(request, 'home.html', context)
relevant HTML section
</br>
</br>
<form action="" method=POST>
{% csrf_token %}
{{ form.as_p }}
{{form}}
<button type="Submit" >Submit</button>
</form>
</body>
</html>
urls.py
from django.contrib import admin
from django.urls import path
from django.urls import include, re_path
from .forms import command_node
from . import views
urlpatterns = [
re_path('home/', views.home)
]
When I attempt to run the server or even now migrate I get the following.
PS C:\Python-projects\commandsite> python manage.py makemigrations
Traceback (most recent call last):
File "C:\Python-projects\commandsite\manage.py", line 22, in <module>
main()
File "C:\Python-projects\commandsite\manage.py", line 18, in main
execute_from_command_line(sys.argv)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\management\__init__.py", line 446, in execute_from_command_line
utility.execute()
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\management\__init__.py", line 440, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\management\base.py", line 414, in run_from_argv
self.execute(*args, **cmd_options)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\management\base.py", line 455, in execute
self.check()
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\management\base.py", line 487, in check
all_issues = checks.run_checks(
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\checks\registry.py", line 88, in run_checks
new_errors = check(app_configs=app_configs, databases=databases)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\checks\urls.py", line 14, in check_url_config
return check_resolver(resolver)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\checks\urls.py", line 24, in check_resolver
return check_method()
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\urls\resolvers.py", line 480, in check
for pattern in self.url_patterns:
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\utils\functional.py", line 49, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\urls\resolvers.py", line 696, in url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\utils\functional.py", line 49, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\urls\resolvers.py", line 689, in urlconf_module
return import_module(self.urlconf_name)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\importlib\__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 883, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "C:\Python-projects\commandsite\commandsite\urls.py", line 22, in <module>
re_path('website/', include('website.urls'))
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\urls\conf.py", line 38, in include
urlconf_module = import_module(urlconf_module)
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\importlib\__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 883, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "C:\Python-projects\commandsite\website\urls.py", line 4, in <module>
from .forms import command_node
File "C:\Python-projects\commandsite\website\forms.py", line 6, in <module>
class command_form(ModelForm):
File "C:\Python-projects\commandsite\website\forms.py", line 7, in command_form
class Meta:
File "C:\Python-projects\commandsite\website\forms.py", line 14, in Meta
host_id = forms.ModelChoiceField(
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\forms\models.py", line 1463, in __init__
self.queryset = queryset
File "C:\Users\Admin\AppData\Local\Programs\Python\Python310\lib\site-packages\django\forms\models.py", line 1488, in _set_queryset
self._queryset = None if queryset is None else queryset.all()
AttributeError: 'ForwardManyToOneDescriptor' object has no attribute 'all'
PS C:\Python-projects\commandsite>
This was all working before I attempted to add a form in. Since tinkering with it to try and get a form this is the issue I face. So any help would be Greatly appericated. As I don't know what I've done wrong.
CodePudding user response:
Looking at your code, the error is raised because you're specifying queryset=command_node.host_id
in your form:
host_id = forms.ModelChoiceField(
required=True,
queryset=command_node.host_id,
widget=forms.Select(
attrs={
'class': 'form-control'
},
)
)
Actually, command_node.host_id
is a ForwardManyToOneDescriptor
(this is the class assigned to fields that are marked as ForeignKey
). In this case, what you want to supply as the queryset
parameter is a set of objects that should belong to the model beacon
which is the onea associated to host_id
:
host_id = forms.ModelChoiceField(
required=True,
queryset=beacon.objects.all(),
widget=forms.Select(
attrs={
'class': 'form-control'
},
)
)
This will display all beacon
objects in your DB as options in a dropsdown in your form (the widget used is a Select
). You could also display any queryset related to the beacon
model. For example if you wanted to display only the beacon
objects that have an internal IP equal to X.Y.Z.W
you could sepecify queryset=beacon.objects.filter(internalIP="X.Y.Z.W")
.
Some things to note here:
- Django already uses a
ModelChoiceField
when displaying the available options for fields that rely on aForeignKey
. You can check the associations Django makes betweenModel
fields andForm
fields here: https://docs.djangoproject.com/en/4.0/topics/forms/modelforms/#field-types. If you want allbeacon
objects to be able for selection in your form, your code could be simplified to:
class command_form(ModelForm):
class Meta:
model = command_node
fields = (
'host_id',
'current_commands'
)
current_comamnds = forms.ChoiceField(
required=True,
attrs={
'class': 'form-control'
},
choices=[
('Sleep', "Sleep"),
('Open SSH_Tunnel', 'Open SSH_Tunnel'),
('Close SSH_Tunnel', 'Close SSH_Tunnel'),
('Open TCP_Tunnel', 'Open TCP_Tunnel'),
('Close TCP_Tunnel', 'Close TCP_Tunnel'),
('Open Dynamic', 'Open Dynamic'),
('Close Dynamic', 'Close Dynamic'),
('Task', 'Task'),
])
- A common practice in Python (and therefore in Django too) is to write class names in
UpperCaseCamelCase
instead ofsnake_case
(see https://visualgit.readthedocs.io/en/latest/pages/naming_convention.html#classes). If you adopt this naming convention, differentiating the class from its instances is easier.