Django form Integer array Field - arrays

I would like to use django forms to validate fields being Integer Array. What is the best way to achieve this ? I don't want to use a ChoiceField and I am not sure what is the easiest way to achieve this. Any suggestion in that matter ?

For storing the array I would use a django-picklefield or a custom field like this:
from django.db import models
class IntArrayField(models.TextField):
__metaclass__ = models.SubfieldBase
def __init__(self, *args, **kwargs):
super(IntArrayField, self).__init__(*args, **kwargs)
def to_python(self, value):
if not value:
return None
if isinstance(value, list):
return value
return [int(n) for n in value.split('|')]
def get_db_prep_value(self, value):
if not value:
return None
assert(isinstance(value, list) or isinstance(value, tuple))
return '|'.join(str(value))
def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
return self.get_db_prep_value(value)
For validation you can use clean_fieldname():
def clean_fieldname(self):
data = self.cleaned_data['fieldname']
# if <data is not an int array>:
# raise forms.ValidationError("You must enter an int array.")
return data
And it's also good to have some JavaScript code to validate input and make entering an int array easier on your client side.

Related

Pass arguments to aiohttp class based view

Is there any simple way to pass custom arguments to View instances with aiohttp ?
This works:
import aiohttp.web
import functools
class Parent():
def __init__(self, val):
self.var = val
class BaseView(aiohttp.web.View):
def __init__(self, *args, **kwargs):
self.parent = kwargs.pop("parent")
super().__init__(*args, **kwargs)
class Handler(BaseView):
async def get(self):
return aiohttp.web.Response(text=self.parent.var)
def partial_class(cls, *args, **kwargs):
class NewCls(cls):
__init__ = functools.partialmethod(cls.__init__, *args, **kwargs)
return NewCls
def main():
parent = Parent("blablabla")
app = aiohttp.web.Application()
# New method with args
app.router.add_view_with_args = functools.partial(
lambda this, path, handler, d: this.add_view(path, partial_class(handler, **d)),
app.router,
)
# Tornado-style
app.router.add_view_with_args("/test", Handler, {"parent": parent})
aiohttp.web.run_app(app)
main()
But I feel like this is overcomplicated.
With Tornado, you can pass additionnal data as a dict object when you instanciate your web Application.
Answering my own question:
It turns out that you are allowed to store global-like variables in an Application instance and then access it in the request handler. It is described in the docs: https://docs.aiohttp.org/en/latest/web_advanced.html#application-s-config

How to create a completely (uniformly) random dataset on PyTorch

I need to run some experiments on custom datasets using pytorch. The question is, how can I create a dataset using torch.Dataloader?
I have two lists, one is called Values and has a datapoint tensor at every entry, and the other one is called Labels, that has the corresponding label. What I did is the following:
for i in range(samples):
dataset[i] = [values[i],labels[I]]
So I have a list with datapoint and respective label, and then tried the following:
dataset = torch.tensor(dataset).float()
dataset = torch.utils.data.TensorDataset(dataset)
data_loader = torch.utils.data.DataLoader(dataset=dataset, batch_size=100, shuffle=True, num_workers=4, pin_memory=True)
But, first of all, I get the error "Not a sequence" in the torch.tensor command, and second, I'm not sure this is the right way of creating one. Any suggestion?
Thank you very much!
You do not need to overload DataLoader, but rather create a Dataset for your data.
For instance,
class MyDataset(Dataset):
def __init__(self):
super(MyDataset, self).__init__()
# do stuff here?
self.values = values
self.labels = labels
def __len__(self):
return len(self.values) # number of samples in the dataset
def __getitem__(self, index):
return self.values[index], self.labels[index]
Just to enrich the answer by #shai
class MyDataset(Dataset):
def __init__(self, values):
super(MyDataset, self).__init__()
self.values = values
def __len__(self):
return len(self.values)
def __getitem__(self, index):
return self.values[index]
values = np.random.rand(51000, 3)
dataset = MyDataset(values)

Converting value to json inside serve method. Wagtail

I realy tried to find answer to my question, but don't know what should I do. I found following question and they didn't help me. question1, question2, docs
I got different values with different functions that I used. Sometimes None value
sometimes TypeError: Object of type 'method' is not JSON serializable
and
AttributeError: 'str' object has no attribute 'status_code' and this
TypeError: 'method' object is not iterable
But i didn't still find solution to solve my problem.
Here is my Page model it has InlinePanel that takes some data from another class:
class ScreencastPage(Page):
content_panels = Page.content_panels + [
InlinePanel(
'groupstage_screencast_relationship', label="Choose Teams",
panels=None, max_num=2),
]
parent_page_types = ['home.HomePage']
def matches(self):
matches = [
n.match for n in self.groupstage_screencast_relationship.all()
]
return matches
def serve(self, request):
if request.is_ajax():
# TODO Convert self.mathes to JSON and return it
else:
return super(ScreencastPage, self).serve(request)
And here is the model that related to my ScreencastPage
#register_snippet
class GroupstageTournamentModel(ClusterableModel):
number = models.PositiveSmallIntegerField(
verbose_name="Match №:")
starts_at = models.DateTimeField()
# Team 1
team_1 = models.ForeignKey(
TeamRooster,
null=True, verbose_name='Erste Team',
on_delete=models.SET_NULL,
related_name="+",
)
team_1_dress = ColorField(blank=True, verbose_name='Dress')
team_1_first_halftime_score = models.PositiveSmallIntegerField(blank=True, default=0, verbose_name='Resultat 1. HZ')
team_1_first_halftime_point = models.PositiveSmallIntegerField(blank=True, default=0, verbose_name='Punkte 1. HZ')
...
UPDATE
Sorry if I ask too noob questions, but I'm new in programming. #gasman these are the ways I used.
1
def serve(self, request):
if request.is_ajax():
lst = []
d = {}
for pn in self.matches:
d['mpn']=pn
lst.append(d)
return json.dumps([dict(mpn=pn) for pn in lst])
returns: TypeError: 'method' object is not iterable
2
Just changed loop from for pn in self.matches: to for pn in self.matches():
def serve(self, request):
if request.is_ajax():
lst = []
d = {}
for pn in self.matches():
d['mpn']=pn
lst.append(d)
return json.dumps([dict(mpn=pn) for pn in lst])
returns: TypeError: Object of type 'GroupstageTournamentModel' is not JSON serializable
3
def serve(self, request):
if request.is_ajax():
if isinstance(self.matches, (list, dict, str, int, float, bool, type(None))):
data = JSONEncoder.default(self.matches())
return data
elif '_python_object' in self.matches():
data = pickle.loads(str(self.matches['_python_object']))
return data
returns: ValueError: The view wagtail.wagtailcore.views.serve didn't return an HttpResponse object. It returned None instead.
4
def serve(self, request):
if request.is_ajax():
data = [
n.match for n in self.groupstage_screencast_relationship.all()
]
return data
returns: AttributeError: 'list' object has no attribute 'status_code'
5
def serve(self, request):
if request.is_ajax():
data = [
n.match for n in self.groupstage_screencast_relationship.all()
]
if isinstance(data, (list, dict, str, int, float, bool, type(None))):
conv_data = json.JSONEncoder.default(data)
return conv_data
returns: TypeError: default() missing 1 required positional argument: 'o'
As I said, I do not know how this conversion works, so I tried to guess.
The important lesson here is to try to solve one problem at once. You're trying to deal with returning a response from serve at the same time as constructing some JSON, and it doesn't look like you're getting anywhere because fixing the first half of the problem just leads you to an error in the second half.
Let's make sure we know how to return something from serve, even if it's just something useless:
def serve(self, request):
if request.is_ajax():
return "hello world!"
else:
return super(ScreencastPage, self).serve(request)
This will fail with something like: 'str' object has no attribute 'get'. This tells us that returning a string is the wrong thing to do: whatever object we return, Wagtail is expecting it to have a get attribute. Looking at the documentation, we can see that it's supposed to be an HttpResponse object:
from django.http import HttpResponse
def serve(self, request):
if request.is_ajax():
return HttpResponse("hello world!")
else:
return super(ScreencastPage, self).serve(request)
This works, so now we know that whatever other stuff we do with JSON in this method, we need to end with return HttpResponse(some_result).
So now let's bring in json.dumps. Again, let's start with some fake data to make sure we're using it right:
import json
from django.http import HttpResponse
def serve(self, request):
if request.is_ajax():
result = ['first match', 'second match']
json_output = json.dumps(result)
return HttpResponse(json_output)
else:
return super(ScreencastPage, self).serve(request)
Hopefully this works too, so let's bring in the real data:
import json
from django.http import HttpResponse
def serve(self, request):
if request.is_ajax():
result = self.matches()
json_output = json.dumps(result)
return HttpResponse(json_output)
else:
return super(ScreencastPage, self).serve(request)
This now fails with something like: TypeError: Object of type 'GroupstageTournamentModel' is not JSON serializable. So now you have to ask: what's changed here? What's different about my real data from the 'fake' data? If you're not sure, add in a debugging line to see what's going on:
import json
from django.http import HttpResponse
def serve(self, request):
if request.is_ajax():
result = self.matches()
print(result) # this output will appear in the terminal / command prompt
json_output = json.dumps(result)
return HttpResponse(json_output)
else:
return super(ScreencastPage, self).serve(request)
The error message hopefully makes it clear: the value you're passing to json.dumps contains GroupstageTournamentModel objects, and JSON doesn't know how to deal with those. You need to convert them into basic values such as dicts, and that means specifying how each individual field is meant to appear in the output:
def serve(self, request):
if request.is_ajax():
result = [
{
'number': match.number,
'team1': match.team_1.name,
# ...
}
for match in self.matches()
]
json_output = json.dumps(result)
return HttpResponse(json_output)
else:
return super(ScreencastPage, self).serve(request)
In summary - when you encounter an error message:
don't just abandon your code and try something else;
look at what the error message is telling you, and especially, what line of code it's coming from;
see if there's a way to reduce it to a simpler case that does succeed, then work your way back up to the real solution.

Overriding validation for Django for base64 string for model.imagefield

I am using Angular and Bootstrap to serve my forms. If a user uploads an image, Angular serves it in the "data:" format, but Django is looking for a file type. I have fixed this issue by overriding both perform_authentication (To modify the image to a file) and perform_create (to inject my user_id). Is there a better way to override?
I'd rather not override my view. I'd rather override the way Django validates ImageFields. What I want to do is check if the passed value is a 64-bit string, if it is, modify it to a file type, then validate the ImageField. The below code works as is, I just don't feel is optimal.
Here is my view:
class UserCredentialList(generics.ListCreateAPIView):
permission_classes = (IsCredentialOwnerOrAdmin,)
serializer_class = CredentialSerializer
"""
This view should return a list of all the purchases
for the currently authenticated user.
"""
def get_queryset(self):
"""
This view should return a list of all models by
the maker passed in the URL
"""
user = self.request.user
return Credential.objects.filter(member=user)
def perform_create(self, serializer):
serializer.save(member_id=self.request.user.id)
def perform_authentication(self, request):
if request.method == 'POST':
data = request.data.pop('document_image', None)
from django.core.files.base import ContentFile
import base64
import six
import uuid
# Check if this is a base64 string
if isinstance(data, six.string_types):
# Check if the base64 string is in the "data:" format
if 'data:' in data and ';base64,' in data:
# Break out the header from the base64 content
header, data = data.split(';base64,')
# Try to decode the file. Return validation error if it fails.
try:
decoded_file = base64.b64decode(data)
except TypeError:
self.fail('invalid_image')
# Generate file name:
file_name = str(uuid.uuid4())[:12] # 12 characters are more than enough.
# Get the file name extension:
import imghdr
file_extension = imghdr.what(file_name, decoded_file)
file_extension = "jpg" if file_extension == "jpeg" else file_extension
complete_file_name = "%s.%s" % (file_name, file_extension,)
data = ContentFile(decoded_file, name=complete_file_name)
request.data['document_image'] = data
request.user
And here is my serializer:
class CredentialSerializer(serializers.ModelSerializer):
class Meta:
model = Credential
fields = (
'id',
'credential_type',
'credential_number',
'date_received',
'is_verified',
'date_verified',
'document_image',
)
And here is my model:
class Credential(models.Model):
"""Used to store various credentials for member validation."""
document_image = models.ImageField(
upload_to=get_upload_path(instance="instance",
filename="filename.ext",
path='images/credentials/'))
PASSENGER = 'P'
OWNER = 'O'
CAPTAIN = 'C'
CREDENTIAL_CHOICES = (
(PASSENGER, 'Passenger'),
(OWNER, 'Owner'),
(CAPTAIN, 'Captain'),
)
credential_type = models.CharField(max_length=1,
choices=CREDENTIAL_CHOICES,
default=PASSENGER)
credential_number = models.CharField(max_length=255)
date_received = models.DateTimeField(auto_now_add=True)
is_verified = models.BooleanField(default=False)
date_verified = models.DateTimeField(blank=True, null=True)
member = models.ForeignKey(settings.AUTH_USER_MODEL,
related_name='credentials')
I used the below link to help me, now I just want to figure out how override the proper method
Django REST Framework upload image: "The submitted data was not a file"
Well I've made one change since making: I have moved this function to my serializer and instead I now override the method: is_valid and that works as well. At least it's not in my view anymore.

overwrite existing entity via bulkloader.Loader

I was going to CSV based export/import for large data with app engine. My idea was just simple.
First column of CSV would be key of entity.
If it's not empty, that row means existing entity and should overwrite old one.
Else, that row is new entity and should create new one.
I could export key of entity by adding key property.
class FrontExporter(bulkloader.Exporter):
def __init__(self):
bulkloader.Exporter.__init__(self, 'Front', [
('__key__', str, None),
('name', str, None),
])
But when I was trying to upload CSV, it had failed because bulkloader.Loader.generate_key() was just for "key_name" not "key" itself. That means all exported entities in CSV should have unique 'key_name' if I want to modify-and-reupload them.
class FrontLoader(bulkloader.Loader):
def __init__(self):
bulkloader.Loader.__init__(self, 'Front', [
('_UNUSED', lambda x: None),
('name', lambda x: x.decode('utf-8')),
])
def generate_key(self,i,values):
# first column is key
keystr = values[0]
if len(keystr)==0:
return None
return keystr
I also tried to load key directly without using generate_key(), but both failed.
class FrontLoader(bulkloader.Loader):
def __init__(self):
bulkloader.Loader.__init__(self, 'Front', [
('Key', db.Key), # not working. just create new one.
('__key__', db.Key), # same...
So, how can I overwrite existing entity which has no 'key_name'? It would be horrible if I should give unique name to all entities.....
From the first answer, I could handle this problem. :)
def create_entity(self, values, key_name=None, parent=None):
# if key_name is None:
# print 'key_name is None'
# else:
# print 'key_name=<',key_name,'> : length=',len(key_name)
Validate(values, (list, tuple))
assert len(values) == len(self._Loader__properties), (
'Expected %d columns, found %d.' %
(len(self._Loader__properties), len(values)))
model_class = GetImplementationClass(self.kind)
properties = {
'key_name': key_name,
'parent': parent,
}
for (name, converter), val in zip(self._Loader__properties, values):
if converter is bool and val.lower() in ('0', 'false', 'no'):
val = False
properties[name] = converter(val)
if key_name is None:
entity = model_class(**properties)
#print 'create new one'
else:
entity = model_class.get(key_name)
for key, value in properties.items():
setattr(entity, key, value)
#print 'overwrite old one'
entities = self.handle_entity(entity)
if entities:
if not isinstance(entities, (list, tuple)):
entities = [entities]
for entity in entities:
if not isinstance(entity, db.Model):
raise TypeError('Expected a db.Model, received %s (a %s).' %
(entity, entity.__class__))
return entities
def generate_key(self,i,values):
# first column is key
if values[0] is None or values[0] in ('',' ','-','.'):
return None
return values[0]
Your best option is probably to override create_entity. You'll need to copy most of the existing code there, but modify the constructor to supply a key argument instead of a key_name argument.

Resources