deanz deanz - 13 days ago 4
Python Question

Django cannot assign value

i got error of this after start uploading a file with metadata.I want to save data_category into database but this error came out


Cannot assign "2": "Layer.data_category" must be a "DataCategory" instance.


"2" is the value that i want to store in the database.

html

<section class="data_category">
<label>{% trans "Select Category of Data" %}</label><br/>
<select id="data_category">
{% for category in category %}
<option value={{ category.id }}>{{ category.category_name }}</option>
{% endfor %}
</select>
</section>


views.py

if request.method == 'POST':
form = NewLayerUploadForm(request.POST, request.FILES)
tempdir = None
errormsgs = []
out = {'success': False}
if form.is_valid():
title = form.cleaned_data["layer_title"]
# Replace dots in filename - GeoServer REST API upload bug
# and avoid any other invalid characters.
# Use the title if possible, otherwise default to the filename
if title is not None and len(title) > 0:
name_base = title
else:
name_base, __ = os.path.splitext(
form.cleaned_data["base_file"].name)
name = slugify(name_base.replace(".", "_"))
try:
# Moved this inside the try/except block because it can raise
# exceptions when unicode characters are present.
# This should be followed up in upstream Django.
tempdir, base_file = form.write_files()
saved_layer = file_upload(
base_file,
name=name,
user=request.user,
overwrite=False,
charset=form.cleaned_data["charset"],
data_category=form.cleaned_data["data_category"],
abstract=form.cleaned_data["abstract"],
title=form.cleaned_data["layer_title"],
metadata_uploaded_preserve=form.cleaned_data["metadata_uploaded_preserve"]
)


forms.py

class NewLayerUploadForm(LayerUploadForm):
if 'geonode.geoserver' in settings.INSTALLED_APPS:
sld_file = forms.FileField(required=False)
if 'geonode_qgis_server' in settings.INSTALLED_APPS:
qml_file = forms.FileField(required=False)
xml_file = forms.FileField(required=False)

abstract = forms.CharField(required=False)
layer_title = forms.CharField(required=False)
permissions = JSONField()
charset = forms.CharField(required=False)
data_category = forms.IntegerField(required=False)
metadata_uploaded_preserve = forms.BooleanField(required=False)


utils.py

def file_upload(filename, name=None, user=None, title=None, abstract=None,
keywords=None, category=None, regions=None, date=None,
skip=True, overwrite=False, charset='UTF-8',
metadata_uploaded_preserve=False, data_category='1'):
"""Saves a layer in GeoNode asking as little information as possible.
Only filename is required, user and title are optional.
"""
if keywords is None:
keywords = []
if regions is None:
regions = []

if data_category == 1:
data_category = 1
if data_category == 2:
data_category = 2
if data_category == 3:
data_category = 3
# Get a valid user
theuser = get_valid_user(user)

# Create a new upload session
upload_session = UploadSession.objects.create(user=theuser)

# Get all the files uploaded with the layer
files = get_files(filename)

# Set a default title that looks nice ...
if title is None:
basename = os.path.splitext(os.path.basename(filename))[0]
title = basename.title().replace('_', ' ')

# Create a name from the title if it is not passed.
if name is None:
name = slugify(title).replace('-', '_')

if category is not None:
categories = TopicCategory.objects.filter(Q(identifier__iexact=category) | Q(gn_description__iexact=category))
if len(categories) == 1:
category = categories[0]
else:
category = None

# Generate a name that is not taken if overwrite is False.
valid_name = get_valid_layer_name(name, overwrite)

# Add them to the upload session (new file fields are created).
assigned_name = None
for type_name, fn in files.items():
with open(fn, 'rb') as f:
upload_session.layerfile_set.create(name=type_name,
file=File(f, name='%s.%s' % (assigned_name or valid_name, type_name)))
# save the system assigned name for the remaining files
if not assigned_name:
the_file = upload_session.layerfile_set.all()[0].file.name
assigned_name = os.path.splitext(os.path.basename(the_file))[0]

# Get a bounding box
bbox_x0, bbox_x1, bbox_y0, bbox_y1 = get_bbox(filename)

# by default, if RESOURCE_PUBLISHING=True then layer.is_published
# must be set to False
is_published = True
if settings.RESOURCE_PUBLISHING:
is_published = False

defaults = {
'upload_session': upload_session,
'title': title,
'abstract': abstract,
'owner': user,
'charset': charset,
'bbox_x0': bbox_x0,
'bbox_x1': bbox_x1,
'bbox_y0': bbox_y0,
'bbox_y1': bbox_y1,
'is_published': is_published,
'data_category': data_category,
'category': category
}

# set metadata
if 'xml' in files:
with open(files['xml']) as f:
xml_file = f.read()
defaults['metadata_uploaded'] = True
defaults['metadata_uploaded_preserve'] = metadata_uploaded_preserve

# get model properties from XML
identifier, vals, regions, keywords = set_metadata(xml_file)

if defaults['metadata_uploaded_preserve']:
defaults['metadata_xml'] = xml_file
defaults['uuid'] = identifier

for key, value in vals.items():
if key == 'spatial_representation_type':
value = SpatialRepresentationType(identifier=value)
elif key == 'topic_category':
value, created = TopicCategory.objects.get_or_create(
identifier=value.lower(),
defaults={'description': '', 'gn_description': value})
key = 'category'
defaults[key] = value
else:
defaults[key] = value

regions_resolved, regions_unresolved = resolve_regions(regions)
keywords.extend(regions_unresolved)

if getattr(settings, 'NLP_ENABLED', False):
try:
from geonode.contrib.nlp.utils import nlp_extract_metadata_dict
nlp_metadata = nlp_extract_metadata_dict({
'title': defaults.get('title', None),
'abstract': defaults.get('abstract', None),
'purpose': defaults.get('purpose', None)})
if nlp_metadata:
regions_resolved.extend(nlp_metadata.get('regions', []))
keywords.extend(nlp_metadata.get('keywords', []))
except:
print "NLP extraction failed."

# If it is a vector file, create the layer in postgis.
if is_vector(filename):
defaults['storeType'] = 'dataStore'

# If it is a raster file, get the resolution.
if is_raster(filename):
defaults['storeType'] = 'coverageStore'

# Create a Django object.
layer, created = Layer.objects.get_or_create(
name=valid_name,
defaults=defaults
)

# Delete the old layers if overwrite is true
# and the layer was not just created
# process the layer again after that by
# doing a layer.save()
if not created and overwrite:
if layer.upload_session:
layer.upload_session.layerfile_set.all().delete()
layer.upload_session = upload_session
# Pass the parameter overwrite to tell whether the
# geoserver_post_save_signal should upload the new file or not
layer.overwrite = overwrite
layer.save()

# Assign the keywords (needs to be done after saving)
keywords = list(set(keywords))
if keywords:
if len(keywords) > 0:
layer.keywords.add(*keywords)

# Assign the regions (needs to be done after saving)
regions_resolved = list(set(regions_resolved))
if regions_resolved:
if len(regions_resolved) > 0:
layer.regions.add(*regions_resolved)

if date is not None:
layer.date = datetime.strptime(date, '%Y-%m-%d %H:%M:%S')
layer.save()

return layer


models.py

class DataCategory(models.Model):
category_name = models.CharField(null = True, max_length=80)

class ResourceBase(PolymorphicModel, PermissionLevelMixin, ItemBase):
data_category = models.ForeignKey(DataCategory, blank=True, null=True)

Answer

please replace

data_category=form.cleaned_data["data_category"]

with

data_category= DataCategory.object.get(id=form.cleaned_data["data_category"])

i think it works for you (i assumed that form passes the id to backend)

Comments