I was wondering if it's possible to store an array in a Django model?
I'm asking this because I need to store an array of int (e.g [1,2,3]) in a field and then be able to search a specific array and get a match with it or by it's possible combinations.
I was thinking to store that arrays as strings in CharFields and then, when I need to search something, concatenate the values(obtained by filtering other model) with '[', ']' and ',' and then use a object filter with that generated string. The problem is that I will have to generate each possible combination and then filter them one by one until I get a match, and I believe that this might be inefficient.
So, I hope you can give me other ideas that I could try.
I'm not asking for code, necessarily, any ideas on how to achieve this will be good.
I'd have two advices for you:
1) Use ArrayField if you are using PostgreSQL as your database. You can read more about ArrayField here.
2) Encode your array as JSON and store it either as a plain string or using a JSONField as found here.
I'd personally prefer option number 1 since that is the cleaner and nicer way but depending on what you are actually using to store your data that might not be available to you.
Yes, you can use it like this:
from django.contrib.postgres.fields import ArrayField
class Board(models.Model):
pieces = ArrayField(ArrayField(models.IntegerField()))
However, it can only be available when using PostgreSQL for the database.
If you aren't using Postgres, I recommend Django's validate_comma_separated_integer_list validator.
https://docs.djangoproject.com/en/dev/ref/validators/#django.core.validators.validate_comma_separated_integer_list
You use is as a validator on a CharField().
I don't know why nobody has suggested it, but you can always pickle things and put the result into a binary field.
The advantages of this method are that it will work with just about any database, it's efficient, and it's applicable to more than just arrays. The downside is that you can't have the database run queries on the pickled data (not easily, anyway).
you can store a json and good to go with sub arrays of that JSON:
if (data != "attachmentto") {
formData.append(data, this.recipe[data])
console.log('rec data ', data)}
else if (data == "attachmentto") {
console.log('rec data434 ', this.recipe.attachmentto)
var myObj = { name: this.recipe.attachmentto.name, age: 31, city: "New York" };
let kokos = JSON.stringify(myObj);
// this.recipe.attachmentto.name = this.recipe.attachmentto.name
formData.append('attachmentto', kokos)
}
Django backend:
class Video(models.Model):
objects = models.Manager()
title = models.CharField(max_length=80)
description = models.TextField(max_length=300)
picture = JSONField(encoder=None)
price = models.IntegerField(default=0)
url = models.URLField()
category = models.CharField(max_length=50)
subcategory = models.TextField(max_length=50)
attachmentto = JSONField(encoder=None)
# attachmentto2 = models.JSONField()
user = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
and result on backend API:
{
"id": 174,
"title": "ads",
"description": "ads",
"picture": {
"name": "https://v3.vuejs.org/logo.png"
},
"price": 0,
"user": 1,
"rating_average": 0,
"attachmentto": {
"age": 31,
"city": "New York",
"name": [
"https://restdj.herokuapp.com/media/uploads/ftf_3_cJ0V7TF.png",
"https://restdj.herokuapp.com/media/uploads/ftf_3.jpg"
]
}
},
I call it noicely(nicely). Notice that we send a JSON and we have a array in that JSON
Kokos is the full JSON disagned for djangoo:
var myObj = { name: this.recipe.attachmentto.name, age: 31, city: "New York" };
let kokos = JSON.stringify(myObj);
formData.append('attachmentto', kokos)
Above; name: this.recipe.attachmentto.name is an array
Here is the array:
"name": [
"https://restdj.herokuapp.com/media/uploads/ftf_3_cJ0V7TF.png",
"https://restdj.herokuapp.com/media/uploads/ftf_3.jpg"
]
Related
I am trying to pass json field as input for my graphql mutation.
I have been trying and searching but just no luck. I can pass array fine with I know by defining graphene.List(graphene.String) would work for passing array of strings.
I figured there's a type named graphene.JSONstring() which I thought would work if I use it with graphene.List(graphene.JSONstring) but no luck, still getting errors saying type is not right.
I have something like this during the mutation
mutation {
create(data:{
field1: [
{
"first": "first",
"last": "last"
},
{
"first":"first1",
"last":"last1"
}
]
})
}
as for input class
class NameInput(graphene.InputObjectType):
# please ignore the same field names, just listing what I have tried
field1 = graphene.JSONString()
field1 = graphene.List(graphene.JSONString)
field1 = graphene.List(graphene.String)
Does anyone has an idea how this would work?
Thanks in advance
Seems like you are trying to have nested input objects. Unfortunately I have never used graphene but maybe I can answer in terms of the GraphQL specification and then make an educated guess about the graphene code:
type Mutation {
create(data: NameInput): Boolean # <- Please don't return just Boolean
}
input NameInput {
field1: FistLastInput[]
}
input FirstLastInput {
first: String!
last: String!
}
This means you will need two input objects to describe the structure of your input. Create a new class for you object that takes the fields first and last:
class FirstLastInput(graphene.InputObjectType):
first = graphene.NonNull(graphene.String)
last = graphene.NonNull(graphene.String)
Now we can use the input object in our initial query:
class NameInput(graphene.InputObjectType):
field1 = graphene.List(FirstLastInput)
You could try like this:
class NameInput(graphene.InputObjectType):
field1 = graphene.JSONString()
And then:
mutation {
create(data:{
field1: "[
{
\"first\": \"first\",
\"last\": \"last\"
},
{
\"first\":\"first1\",
\"last\":\"last1\"
}
]"
})
}
So basically send json as string.
Graphene provides a GenericScalar type. You can use it to input/output generic types like int, str, dict, list, etc.
from graphene import InputObjectType, Mutation
from graphene.types.generic import GenericScalar
class InputObject(InputObjectType):
field1 = GenericScalar()
class Create(Mutation):
class Arguments:
data = InputObject()
def mutate(root, info, data):
# do something with data.field1
Then your input would look like
mutation {
create (
data: {
field1: [
{
first: "first",
last: "last"
},
{
first: "first1",
last: "last1"
}
]
}
)
}
Note that field1 can accept any generic input, so make sure to validate it.
Also, when using a GenericScalar field for output (query), you won't be able to query its subfields. But you can write a resolver for that field to make sure only specific subfields are returned.
Here is the link to the corresponding GitHub issue.
I'm using Django REST and I have these three objects :
class Object1():
name = ""
class Object2():
value = 0
class Object3():
list = [] # a list of object1 and object2
and I have their serializer like this :
class Object1Serializer(serializer.Serializer):
name = serializer.CharField(max_length=30)
class Object2Serializer(serializer.Serializer):
value = serializer.IntegerField()
How can I create a serializer for Object3
Edit
In my return response I want something like this :
{
"Object1" : {
"name": "name"
}
"object2": {
"value": 12
}
}
Check out the Serializer Fields Documentation — the basic idea would be to create a Field subclass that implements to_native to return the list you need.
There's the drf_compound_fields package that provides a ListField (and others) — this should either give you what you need or at least provide enough pointer to help you implement you own solution.
I hope that helps
Please excuse what may become evident to be python noobness. Here's a view function. Its a jsonp response, and works exactly as required, brilliant (some elements amended for anonimity).
Updated: This is my function, complete.
class stores(ListView):
model = Store
def get_queryset(self):
args = [Q()]
output = []
callback = self.request.GET.get('callback', False)
region = self.request.GET.get('region', False)
country = self.request.GET.get('country', False)
if region:
args.append(Q(country__region_id=int(region)))
if country:
args.append(Q(country=int(country)))
outputs = self.model.objects.filter(reduce(operator.and_, args))
for i, item in enumerate(outputs):
outputs[i].contacts = pk__in=list(list(Contact.objects.filter(store=item.id).values()))
return '%s(%s)' % (callback, json) if callback != False else json
This is a response that i get from the script
[{"pk": 2837, "model": "store.store", "fields": {"geolocation": "-30.8040344,111.8395886", "code": "", "logo": "dist/logo/theshop_Sykes_9.jpg", "photo": "", "postcode": "2222/1111", "openinghours": "", "exclude": false, "city": "Perth", "dealer_type": "distrib", "contacts": "[{'phone': u' +1111 7000', 'fax': u'+61 2222 2122', 'type': u'general', 'email': u'notworking#theshop.com'}, {'phone': u'+61 2222 1111', 'fax': u'+61 1111 2222', 'type': u'general', 'email': u'notworking#theshop.com'}]", "servedcountries": [{"lat": "-25.244398", "lng": "132.775136", "name": "Oz"}], "comments": "", "state": "", "latitude": "-31.8040344", "legal_store": "theshop Pty Ltd", "updated": "2013-08-06T15:11:15Z", "street1": "thehouse", "street2": "Landsdale", "street3": "", "phone": "", "address": "The house", "product_type": [], "name": "theshop Pty Ltd", "sectors": "Industrial", "created": "2013-08-06T13:50:48Z", "url": "http://www.theshopsykes.com/", "country": {"lat": "-25.274398", "lng": "133.775136", "name": "Australia"}, "longitude": "115.8395886", "local_store": "theshop Pty Ltd"}}]
Paste that string into a json decoder like the one at http://json.parser.online.fr/
You'll see that the contacts element is not correctly parsed.
I have tried:
outputs[i].contacts = serializers.serialize("json", Contact.objects.filter(distributor=item.id), use_natural_keys=True)
But i get an Error.
AttributeError: 'unicode' object has no attribute 'name'
Here is the model declaration, in case it'll help.
class Contact(models.Model):
contact_type = models.CharField('Email Type', max_length='20', choices=(('sales', 'Sales'), ('support', 'Support'), ('general', 'General')), blank=True)
email = models.EmailField(max_length=200, blank=True)
phone = models.CharField('Phone Number', max_length=200, blank=True)
fax = models.CharField('Fax Number', max_length=200, blank=True)
store = models.ForeignKey(Store)
def __unicode__(self):
return self.contact_type
def natural_key(self):
return self.contact_type
I guess that you are looking to serialize related objects (Contacts, related to Store).
As this is a non-trivial question, I would suggest having a look at something like https://code.google.com/p/wadofstuff/wiki/DjangoFullSerializers — not sure if there are more recent options in Django core as well (select_related ?).
Cheers,
Steve, I think your thinking about how serialization works is flawed. I envision a process of getting from a queryset to a JSON response as a two-step process, and the Django serializer does both.
1) Turning a queryset into a a dictionary of strings and numbers.
2) Turning that dictionary into JSON.
Step 1 is harder than one thinks. E.g. a serializer will have to decide which attributes are serialized. E.g. if you'd define a property on the model, it seems like they're being serialized (otherwise contacts wouldn't show up). I was expecting that the Django serializer only serializes model fields, but I guess not!
It also has to make decisions about how to present relationships to other models. This is called nesting, and there's multiple options: Just list the primary keys of the related model, or include serialized versions of it. One can do just list primary keys of related models, or include one or more levels of depth.
--
As far as solving your problem goes, I can suggest two things:
As madflo suggested, the Django serializer might be too basic for your needs. I'd have a look at what else is available. Personally, I'm a big fan of Django Rest Framework; but that might be overkill for your use case. Their documentation regarding nesting might still be useful.
I'd have a good look at the differences between servedcountries and contacts. It seems servedcountries is a related model that is getting serialized as expected, so find out why that is the case and contacts isn't. It would be helpful to include the declaration of the Store model.
Remark:
I'm not so sure about this line; I think you meant pk__in_list?
outputs[i].contacts = pk__in=list(list(Contact.objects.filter(store=item.id).values()))
Anyhow, if I understand it correctly, you should be able to replace it by
outputs[i].contacts = Contacts.objects.filter(store=item.id).values_list('pk', flat=True)
The problem I'm having is with mixing serialized Django models using django.core.serializers with some other piece of data and then trying to serialize the entire thing using json.dumps.
Example code:
scores = []
for indicator in indicators:
score_data = {}
score_data["indicator"] = serializers.serialize("json", [indicator,])
score_data["score"] = evaluation.indicator_percent_score(indicator.id)
score_data["score_descriptor"] = \
serializers.serialize("json",
[form.getDescriptorByPercent(score_data["score"]),],
fields=("order", "value", "title"))
scores.append(score_data)
scores = json.dumps(scores)
return HttpResponse(scores)
Which returns a list of objects like this:
{
indicator: "{"pk": 345345, "model": "forms.indicator", "fields": {"order": 1, "description": "Blah description.", "elements": [10933, 4535], "title": "Blah Title"}}",
score: 37.5,
score_descriptor: "{"pk": 66666, "model": "forms.descriptor", "fields": {"order": 1, "value": "1.00", "title": "Unsatisfactory"}}"
}
The problem I'm having can be seen in the JSON with the serialized Django models being wrapped in multiple sets of quotations. This makes the it very hard to work with on the client side as when I try to do something like
indicator.fields.order
it evaluates to nothing because the browser thinks I'm dealing with a string of some sort.
Ideally I would like valid JSON without the conflicting quotations that make it unreadable. Something akin to a list of objects like this:
{
indicator: {
pk: 12931231,
fields: {
order: 1,
title: "Blah Title",
}
},
etc.
}
Should I be doing this in a different order, using a different data structure, different serializer?
My solution involved dropping the use of django.core.serializers and instead using django.forms.model_to_dict and django.core.serializers.json.DjangoJSONEncoder.
The resulting code looked like this:
for indicator in indicators:
score_data = {}
score_data["indicator"] = model_to_dict(indicator)
score_data["score"] = evaluation.indicator_percent_score(indicator.id)
score_data["score_descriptor"] = \
model_to_dict(form.getDescriptorByPercent(score_data["score"]),
fields=("order", "value", "title"))
scores.append(score_data)
scores = json.dumps(scores, cls=DjangoJSONEncoder)
The problem seemed to arise from the fact that I was essentially serializing the Django models twice. Once with the django.core.serializers function and once with the json.dumps function.
The solution solved this by converting the model to a dictionary first, throwing it in the dictionary with the other data and then serializing it once using the json.dumps using the DjangoJSONEncoder.
Hope this helps someone out because I couldn't find my specific issue but was able to piece it together using other answer to other stackoverflow posts.
Apologies if the answer to this is obvious - I'm very new to django/python & haven't been able to find a solution in my searching so far.
I have a straightforward queryset, eg
members = LibraryMembers.objects.all()
with this I can do:-
for m in members:
member_books = LibraryBorrows.objects.filter(member_id=m[u'id'])
What I really want though is to be able to serialize the results into json, so it looks something like this:-
{
"members":
[
{
"id" : "1",
"name" : "Joe Bloggs"
"books":
[
{
"name" : "Five Go Exploring",
"author" : "Enid Blyton",
},
{
"name" : "Princess of Mars",
"author" : "Edgar Rice Burroughs",
},
]
}
]
}
To my mind, the obvious thing to try was:-
for m in members:
m[u'books'] = LibraryBorrows.objects.filter(member_id=m[u'id'])
However I'm getting TypeError: 'LibraryBorrows' object does not support item assignment
Is there any way to achieve what I'm after?
Model instances are not indeed not dicts. Now if you want dicts instead of model instances, then Queryset.values() is your friend - you get a list of dicts with only the required fields, and you avoid the overhead of retrieving unneeded fields from the database and building full-blown model instances.
>> members = LibraryMember.objects.values("id", "name")
>> print members
[{"id" : 1, "name" : "Joe Bloggs"},]
Then you code would look like:
members = LibraryMember.objects.values("id", "name")
for m in members:
m["books"] = LibraryBorrows.objects.filter(
member_id=m['id']
).values("name", "author")
Now you still have to issue one additionnal db query for each parent row which may not be that efficient, depending on the number of LibraryMember. If you have hundreds or more LibraryMember, a better approach would be to query on the LibraryBorrow instead, including the related fields from LibraryMember, then regroup the rows based on LibraryMember id, ie:
from itertools import group_by
def filter_row(row):
for name in ("librarymember__id", "librarymember__name"):
del row[name]
return row
members = []
rows = LibraryBorrow.objects.values(
'name', 'author', 'librarymember__id', 'librarymember__name'
).order_by('librarymember__id')
for key, group in group_by(rows, lambda r: r['librarymember__id']):
group = list(group)
member = {
'id' : group[0]['librarymember_id'],
'name':group[0]['librarymember_name']
'books' = [filter_row(row) for row in group]
}
members.append(member)
NB : this can be seen as premature optimization (and would be if you only have a couple LibraryMember in your db), but trading hundreds or more queries for one single query and a bit of postprocessing usually makes a real difference for "real life" datasets.
Well m is a LibraryMember object so you won't be able to treat it as a dictionary. As a side note: Most people don't name the models in plural form since they are just a class modeling an object, not a collection of objects.
One possible solution is to make a list of dictionaries with the values that you need from both objects, something like this in a one-liner:
o = [ { "id": m.id, "name": m.name, "books": [{"name": b.name, "author": b.author} for b in m.libraryborrows_set.all()] } for m in LibraryMembers.objects.all()]
Note that you can use the related manager to get the books for a given member. For better clarity:
o = []
for m in LibraryMembers.objects.all():
member_books = [{"name": b.name, "author": b.author} for b in m.libraryborrows_set.all()]
o.append( { "id": m.id, "name": m.name, "books": member_books } )
EDIT:
To serialize all the fields:
members = []
for member in LibraryMembers.objects.all():
member_details = {}
for field in member._meta.get_all_field_names():
member_details[field] = getattr(member, field)
books = []
for book in member.librayborrows_set.all():
book_details = {}
for field in book._meta.get_all_field_names():
book_details[field] = getattr(book, field)
books.append(book_details)
member_details['books'] = books
members.append(member_details)
I also found DjangoFullSerializers which I hadn't heard about until today:
http://code.google.com/p/wadofstuff/wiki/DjangoFullSerializers