'choices' must be an iterable containing - django-models

I'm learning Django and I had an error in code
class Nomzod(models.Model):
Y = [
("Erkak", "Erkak"),
("Ayol", "Ayol"),
]
ism_f = models.CharField(max_length=100)
email = models.EmailField(unique=True, blank=True)
birinchisi = models.BooleanField(default=True)
jins = models.CharField(max_length=30, choices=Y)
Error:
asosiy.Universitet.yillik: (fields.E005) 'choices' must be an iterable containing (actual value, human readable name) tuples.System check identified 1 issue (0 silenced)
What I must do. Please help me
I already watched guides but they didn't helped me(

Try making your Y as tuple of tuples like this :
Y = (
("Erkak", ("Erkak")),
("Ayol", ("Ayol")),
)

Related

Add M2M field using create(): Django

I have a lot of doubts about managing the M2m field, I finally got a solution to add that data to a model, but there are still some issues, give me a solution to overcome this,
class CourseListSerializer(serializers.ModelSerializer):
instructors = serializers.SerializerMethodField()
image = FileField()
keyarea = CourseKeyAreaSerializer
subject = CourseSubjectsSerializer
sections = serializers.ListField(write_only=True)
beneficiaries = serializers.ListField(write_only=True)
section = CourseSectionSerializers
beneficiary = CourseBeneficiarySerializer
def create(self, validated_data):
data = validated_data
try:
new = Course.objects.create(image=data['image'], name=data['name'], description=data['description'], is_free=data['is_free'],
keyarea=data['keyarea'], subject=data['subject'])
new.save()
beneficiary_data = data['beneficiaries']
new.beneficiary.set(*[beneficiary_data])
section_data = data['sections']
new.section.set(*[section_data])
return new
except Exception as e:
e = "invalid data"
return e
here first creating the "new" object after that to set the M2M field like
"new.beneficiary.set(*[beneficiary_data])"
but is there any way to add beneficiary and section like this
"new = Course.objects.create(image=data['image'],name=data['name'], description=data['description'],is_free=data['is_free'],....)"

getting a django model field from another field

i have this model
class Person(models.Model):
picture = models.ImageField(
default='default.jpg', upload_to='profile_pics', )
firstName = models.CharField(blank=True, max_length=100)
familyName = models.CharField(blank=True, max_length=100)
age = models.IntegerField(default=0)
GENDER = [
("M", 'Male'),
("F", 'Female'),
("U", 'UNKNOWN'),
]
gender = models.CharField(
max_length=2,
choices=GENDER,
default="U",
)
address = models.CharField(blank=True, max_length=100)
remark = models.TextField(default="no remark")
description_vector = models.TextField(blank=True)
i want to infer the description_vector from the picture field (with a method called identifie(pictur) that return a string ) whenever i add a new Person or changing a model image (if the image didn't change i dont want to change the description_vector)
i know i can use the save method like here but i dont know how to specify that when the image change the vector change.
i dont know if it changes anything but i use django-rest-framowrk to add and change persons
i know
I am not sure I understand what your specific doubt is, but I think this might be helpful.
def save(self, *args, **kwargs):
if self.id is not None: # check only when update
original_picture = self.objects.get(id=self.id).picture
if original_picture !== self.picture # You must add here your method to evaluate if both images are equal
self.vector = some_method_to_change_vector(self.picture)
return super().save(*args, **kwargs)

DRF - queryset filter using contains field lookup on SlugRelatedField

I am struggling to figure out the how to run queryset filter using "field__contains" on a SlugRelatedField.
I have a simple Book model and a Tag model that looks as following:
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
class MetaTag(models.Model):
book = models.ManyToManyField('Book', related_name='meta_tags',
help_text='The book this meta tag belongs to')
value = models.CharField(max_length=400, unique=True, help_text='Meta tag value')
class BookSerializer(serializers.HyperlinkedModelSerializer):
class BookHyperlink(serializers.HyperlinkedIdentityField):
"""A Hyperlink field for book details"""
def get_url(self, obj, view_name, request, format):
url_kwargs = {
'pk': obj.id,
}
return reverse(view_name, kwargs=url_kwargs, request=request, format=format)
url = BookHyperlink(view_name='book-detail')
meta_tags = CreatableSlugRelatedField(many=True, slug_field='value', queryset=MetaTag.objects.all())
class Meta:
model = Book
fields = (
'id',
'title',
'publisher',
'publication_date',
'meta_tags',
'url'
)
class MetaTagSerializer(serializers.ModelSerializer):
class Meta:
model = MetaTag
fields = ('id', 'book', 'value',)
class CreatableSlugRelatedField(serializers.SlugRelatedField):
def to_internal_value(self, data):
try:
return self.get_queryset().get_or_create(**{self.slug_field: data})[0]
except ObjectDoesNotExist:
self.fail('does_not_exist', slug_name=self.slug_field, value=smart_text(data))
except (TypeError, ValueError):
self.fail('invalid')
class Meta:
model = MetaTag
fields = ('id', 'book', 'value', )
Now in my BooksView, I want to be able to filter the queryset by meta_tags value. I've tried the following with "__contains" field lookup:
class Books(viewsets.ModelViewSet):
"""Default view for Book."""
queryset = Book.objects.all()
serializer_class = BookSerializer
permission_classes = (IsAuthenticated, )
filter_backends = (DjangoFilterBackend,)
filter_fields = tuple(f.name for f in Book._meta.get_fields())
def get_queryset(self):
search_pattern = self.request.query_params.get('search', None)
if search_pattern is not None and search_pattern is not '':
self.queryset = self.queryset.filter(meta_tags__contains = search_pattern)
return self.queryset
def get_object(self):
if self.kwargs.get('pk'):
return Book.objects.get(pk=self.kwargs.get('pk'))
But I get the following error from django:
File "~MyProject/venv/lib/python3.6/site-packages/django/db/models/sql/query.py", line 1076, in build_lookup
raise FieldError('Related Field got invalid lookup: {}'.format(lookup_name))
django.core.exceptions.FieldError: Related Field got invalid lookup: contains
Which as I understand means that since "meta_tags" is not a regular array or Text field, the contains field lookup cannot be applied on that field.
What is the best way if so to filter the queryset in such case for meta_tags value?
A django expert I've consulted about this issue, suggested to try append the "slug_field" ("__value" in this case) to "__contains" field lookup when used with external model.
It was not documented anywhere or even on django official documentation at https://docs.djangoproject.com/en/2.0/ref/contrib/postgres/fields/#contains, so I had no way to know it works this way, but this solution actually works:
queryset = queryset.filter(meta_tags__value__contains=search_pattern)
It actually makes sense when you look deeper at the MetaTag model, as "value" is the inner field of the meta_tags model:
class MetaTag(models.Model):
book = models.ManyToManyField('Book', related_name='meta_tags',
help_text='The book this meta tag belongs to')
value = models.CharField(max_length=400, unique=True, help_text='Meta tag value')
def __str__(self):
return '%s > %s' % (self.channel, self.value)
The reason it was not so obvious to append __value at the first place is because meta_tags array (array of objects) is flattened using the SlugRelatedField serializer where only the slug_field is projected and the rest fields are omitted.
So the final output of meta_tags array is flat:
meta_tags: ['tag1','tag2']
instead of:
meta_tags: [{book: 'a', value: 'tag1'},{book: 'a', value: 'tag2'}]
But since serialization on django DRF is made on a late stage (after queryset is completed) the original field schema should be considered.
Hope this will save somebody's headache someday.

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.

How to create a self-referencing one-to-many relationship in Flask-SQLAlchemy?

I have a model named Post, which has a boolean field called is_answer. If the is_answer field of a Post is True, it's a "question"; otherwise, it's an "answer". I want to create the following question-answer relationship:
One "question" may have many "answer"s, but one "answer" has and only has one "question". Due to the fact that both "question" and "answer" are essentially Posts, I think the relationship must be self-referencing.
Here is what I've tried:
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
is_question = db.Column(db.Boolean)
post_id = db.Column(db.Integer, db.ForeignKey('posts.id'))
question = db.relationship('Post', backref=db.backref('answer', lazy='dynamic'), uselist=False, lazy='dynamic')
The error is:
ArgumentError: Post.question and back-reference Post.answer are both
of the same direction symbol('ONETOMANY'). Did you mean to set
remote_side on the many-to-one side ?
You need to add remote_side argument to create self-referenced relation. More information in documentaion.
UPDATED: by the way, I think you don't need boolean flag is_question, because you can determine questions and answers by checking post_id field is Null or not.
class Post(Base):
__tablename__ = 'posts'
id = Column(Integer, primary_key=True)
post_id = Column(Integer, ForeignKey('posts.id'))
question = relationship('Post', remote_side=[id], backref=backref('answers'), uselist=False)
Test:
session.add(
Post(
id=1,
post_id=None
)
)
session.add(
Post(
id=2,
post_id=1
)
)
session.add(
Post(
id=3,
post_id=1
)
)
session.commit()
question = session.query(Post).get(1)
print question.answers # output [post2, post3]
answer = session.query(Post).get(2)
print answer.question.id # output 1
# Receive all answers
print session.query(Post).filter(Post.post_id.isnot(None)).all()
You can use the below question and answer table.
class Answer(Base):
__tablename__="answers"
id = Column(Integer, primary_key=True)
mcq_id = Column(Integer,ForeignKey('questions.id'))
answer_text = Column(Text())
is_correct = Column(Boolean, nullable=False, default=False)
class Question(Base):
__tablename__="questions"
id = Column(Integer, primary_key=True)
question_text = Column(Text())
answer_explanation = Column(Text())
answer_choices = relationship('Answer',
primaryjoin="and_(Question.id == Answer.mcq_id )",
cascade="all, delete-orphan",
foreign_keys=[Answer.mcq_id])
# If you have more than one answers then define this function in your model.
def has_more_than_one_correct_answer(self):
count = 0
for choice in self.answer_choices:
if choice.is_correct:
count = count + 1
if count > 1:
return True
else:
return False
You can see the relationship between two tables. And you can access the relationship using joinedload or joinedload_all if you are using sqlalchemy.

Resources