How to save formwizard POST request to a database - sql

How do I save the form_data to a database?
forms.py
class ContactWizard(SessionWizardView):
template_name ='fitness/general.html'
def done(self, form_list, **kwargs):
form_data = process_form_data(form_list)
return render_to_response('fitness/general2.html', {'form_data': form_data})
def process_form_data(form_list):
form_data = [form.cleaned_data for form in form_list]
return form_data

I have encountered this problem before while doing an online resume builder
def done(self, form_list , **kwargs):
form_data = [
form for form in form_list
]
first_form = form_data[0]
first_instance = first_form.save(commit = False)
#TODO: add other stuff before saving
first_instance.save()
I believe this code may help you. It does nothing extra, as form_data contains all the forms, you can get them by indexing. Of course you can use loop but usually different forms may require different procedures.

Related

Unable to update image in Django Rest Framework , gives error " The submitted data was not a file. Check the encoding type on the form."

i was able to post the image but don't know why i am not able to update the image , i am using default form provided by DRF
i did not find any solutions yet for this one
i am uploading image via cloudinary api
the error
{
"image_1": [
"The submitted data was not a file. Check the encoding type on the form."
],
"image_2": [
"The submitted data was not a file. Check the encoding type on the form."
]
}
Model:
class MyDetail(models.Model):
name=models.CharField(max_length=50, null=True, blank=True)
image_1=models.URLField(null=True, blank=True)
image_2=models.URLField(null=True, blank=True)
Views:
class SingleDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset=MyDetail.objects.all()
serializer_class = SingleDetailSerializer
lookup_field='id'
def update(self, request, *args, **kwargs):
instance = self.get_object()
image_1 = request.FILES.get('image_1',None)
image_2 = request.FILES.get('image_2',None)
if image_1:
uploaded_image_1 = cloudinary.uploader.upload(image_1)
request.data['image_1'] = uploaded_image_1['secure_url']
if image_2:
uploaded_image_2 = cloudinary.uploader.upload(image_2)
request.data['image_2'] = uploaded_image_2['secure_url']
serializer = self.get_serializer(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
return Response({"message": "Updated successfully.", "data": serializer.data})
def perform_update(self, serializer):
serializer.save()
serializer:
class SingleDetailSerializer(serializers.ModelSerializer):
image_1 = serializers.ImageField(max_length=None,use_url=True,required=False)
image_2 = serializers.ImageField (max_length=None,use_url=True,required=False)
class Meta:
model = MyDetail
fields = ['id','name','image_1','image_2']
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['image_1'] = instance.image_1
representation['image_2'] = instance.image_2
return representation
my DRF Form image
i even tried from my react form but it was still not working , i was not able to find solutions online and i don't know why it is not able to recognize the file though i uploaded the file. Help me to fix this
Here is how i solved it
Instead of updating image through views , i updated image directly serializer where i modified the url field to image field to upload the image
views :
class SingleDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset=MyDetail.objects.all()
serializer_class = SingleDetailSerializer
lookup_field='id'
serializer :
class SingleDetailSerializer(serializers.ModelSerializer):
image_1 = serializers.ImageField(use_url=True, required=False)
image_2 = serializers.ImageField(use_url=True, required=False)
class Meta:
model = MyDetail
fields = ['id','name','image_1','image_2']
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['image_1'] = instance.image_1
representation['image_2'] = instance.image_2
return representation
def update(self, instance, validated_data):
image_1 = validated_data.get('image_1',None)
image_2 = validated_data.get('image_2',None)
if image_1:
uploaded_image_1 = cloudinary.uploader.upload(image_1)
validated_data['image_1'] = uploaded_image_1['secure_url']
if image_2:
uploaded_image_2 = cloudinary.uploader.upload(image_2)
validated_data['image_2'] = uploaded_image_2['secure_url']
instance = super().update(instance, validated_data)
return instance

Is passing additional data to save() the right way to store the results of logic triggered by a POST?

I've got a django rest framework view that passes data from a POST to another function that returns a result.
I want to store that result in the database so that you can GET a previous result or results.
Currently, I've got the "nornir_result" defined in my serializer and model.
The serializer field is set to required=False (because the result isn't known when the payload is passed in).
Then, to populate/save this information for later GETs, save(nornir_result=nornir_result) gets called during the POST.
Is my approach correct? Passing additional data to save() to store the results of logic triggered by a POST so it can be viewed later?
# views.py
class F5AuditList(APIView):
def get(self, request, format=None):
audits = F5Audit.objects.all()
serializer = F5AuditSerializer(audits, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = F5AuditSerializer(data=request.data)
if serializer.is_valid():
nornir_result = audit.django_result(request.data)
serializer.save(
audit_id=create_unique_number(), nornir_result=nornir_result
)
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# serializers.py
class F5AuditSerializer(serializers.Serializer):
audit_id = serializers.IntegerField(required=False)
created = serializers.DateTimeField(required=False)
devices = serializers.DictField()
audit_type = serializers.CharField(
max_length=None, style={"base_template": "textarea.html"}, required=False
)
nornir_result = serializers.CharField(
max_length=None, style={"base_template": "textarea.html"}, required=False
)
# models.py
class F5Audit(Document):
audit_id = fields.IntField(primary_key=True)
created = fields.DateTimeField(default=datetime.datetime.utcnow)
audit_type = fields.StringField(max_length=100, default="type of f5 audit")
devices = fields.DictField()
nornir_result = fields.StringField(max_length=1000)

Django returns empty QuerySet in the tests

I'm trying to make a test for this view:
def author_detail(request, pk):
author = get_object_or_404(Author, pk=pk)
blog = author.blog_set.all()
paginator = Paginator(blog, 1)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
context = {
'author': author,
'page_obj': page_obj,
}
return render(request, 'blog/author_detail.html', context=context)
The view is working normally. My problem is when I'm going to try to test this view. Here my test:
class AuthorDetailViewTest(TestCase):
def setUp(self):
user = User.objects.create(username='user01', password='123456')
self.author_instance = Author.objects.create(
user=user, date_of_birth='1998-09-08', bio='I am user01')
topic = Topic.objects.create(name='Testing')
Blog.objects.create(title='My blog', content="It's my blog")
Blog.author = self.author_instance
Blog.topic = topic
# The author.blog_set.all() are returning an empty QuerySet
# This problem are only happening in the tests, not in the view
def test_pagination_first_page(self):
response = self.client.get(
reverse('author-detail', kwargs={'pk':self.author_instance.pk}))
self.assertEqual(len(response.context['page_obj']), 1)
The result are:
FAIL: test_pagination_first_page (blog.tests.test_views.AuthorDetailViewTest)
-------------------------------------------------------------------
Traceback (most recent call last):
File "/home/carlos/problem/venv_01/the_blog/blog/tests/test_views.py", line 189,in test_pagination_first_page
self.assertEqual(len(response.context['page_obj']), 1)
AssertionError: 0 != 1
----------------------------------------------------------------------
The len(response.context['page_obj']) is equal 0. It should be at least 1, because I created one Blog object. When I print the QuerySet of author.blog_set.all(), the returned QuerySet are empty (<QuerySet []>). I think that the problem is in the creation of the Blog model, because the author and topic fields are ManyToManyField.
As I mentioned before, my problem is in the test, not in the view. The view is working normally.
The last 3 lines of the following code snippet have some issues:
def setUp(self):
user = User.objects.create(username='user01', password='123456')
self.author_instance = Author.objects.create(
user=user, date_of_birth='1998-09-08', bio='I am user01')
topic = Topic.objects.create(name='Testing')
Blog.objects.create(title='My blog', content="It's my blog")
Blog.author = self.author_instance
Blog.topic = topic
The blog object is created but never returned/fetched
Blog model is being used to connect author and topic. Instead, the blog object should be used.
Author and Topic are M2M on Blog. The new objects should be added via add method. See How to add data into ManyToMany field? for additional context.
Solution:
def setUp(self):
user = User.objects.create(username='user01', password='123456')
author = Author.objects.create(
user=user, date_of_birth='1998-09-08', bio='I am user01')
blog = Blog.objects.create(
title='My blog', content="It's my blog")
blog.author.add(author)
blog.topic.add(topic)
It worked.

insert_many in pymongo not persisting

I'm having some issues with persisting documents with pymongo when using insert_many.
I'm handing over a list of dicts to insert_many and it works fine from inside the same script that does the inserting. Less so once the script has finished.
def row_to_doc(row):
rowdict = row.to_dict()
for key in rowdict:
val = rowdict[key]
if type(val) == float or type(val) == np.float64:
if np.isnan(val):
# If we want a SQL style document collection
rowdict[key] = None
# If we want a NoSQL style document collection
# del rowdict[key]
return rowdict
def dataframe_to_collection(df):
n = len(df)
doc_list = []
for k in range(n):
doc_list.append(row_to_doc(df.iloc[k]))
return doc_list
def get_mongodb_client(host="localhost", port=27017):
return MongoClient(host, port)
def create_collection(client):
db = client["material"]
return db["master-data"]
def add_docs_to_mongo(collection, doc_list):
collection.insert_many(doc_list)
def main():
client = get_mongodb_client()
csv_fname = "some_csv_fname.csv"
df = get_clean_csv(csv_fname)
doc_list = dataframe_to_collection(df)
collection = create_collection(client)
add_docs_to_mongo(collection, doc_list)
test_doc = collection.find_one({"MATERIAL": "000000000000000001"})
When I open up another python REPL and start looking through the client.material.master_data collection with collection.find_one({"MATERIAL": "000000000000000001"}) or collection.count_documents({}) I get None for the find_one and 0 for the count_documents.
Is there a step where I need to call some method to persist the data to disk? db.collection.save() in the mongo client API sounds like what I need but it's just another way of inserting documents from what I have read. Any help would be greatly appreciated.
The problem was that I was getting my collection via client.db_name.collection_name and it wasn't getting the same collection I was creating with my code. client.db_name["collection-name"] solved my issue. Weird.

Transferring value of variable from one unrelated class to another

If I want to create a program using Python2.7 where:
1) There are three classes, namely Tagging, Commenting, and Posting
2) The self.content for both Tagging and Commenting classes will be sent to the self.compact of class Posting
class Tagging: # Handles Tagging - Create new Tags
def __init__(self):
self.content = []
self.initialTag = ""
def doTag(self): #Tag people
self.initialTag = raw_input("Name to Tag: ")
self.content.append(self.initialTag)
#Tagging can only be done if the user created new post.
class Commenting: #Handles Commenting - Create new Comments
def __init__(self):
self.content = []
self.initialComment = ""
def doComment(self): #Commenting on Posts
self.initialComment = raw_input("Comment: ")
self.content.append(self.initialComment)
#Commenting can only be done on Posts. No Post means no Comment. (Same goes to Tags)
class Posting: #Handles Posting - Create new Posts
def __init__(self):
self.content = [] #Content of the post
self.initialPost = ""
self.compact = [] #Post that contains the Post, Comments, and Tags
#How do I do this?
def doPost(self):
self.initialPost = raw_input("Post: ")
self.content.append(self.initialPost)
I tried inheriting class Posting to both class Tagging and class Commenting but I think using Inheritance just for one single variable of class Posting is illogical.
Can anyone suggest me a better way?
And additional question: Are the class Tagging and class Commenting having Aggregation relationship to class Posting? Or is it an Association relationship? (word definition by UML)
How about this, just example code in "__ main __" part:
class Tagging: # Handles Tagging - Create new Tags
def __init__(self):
self.content = []
self.initialTag = ""
def doTag(self): #Tag people
self.initialTag = raw_input("Name to Tag: ")
self.content.append(self.initialTag)
#Tagging can only be done if the user created new post.
class Commenting: #Handles Commenting - Create new Comments
def __init__(self):
self.content = []
self.initialComment = ""
def doComment(self): #Commenting on Posts
self.initialComment = raw_input("Comment: ")
self.content.append(self.initialComment)
#Commenting can only be done on Posts. No Post means no Comment. (Same goes to Tags)
class Posting: #Handles Posting - Create new Posts
def __init__(self, TaggingContent, CommentingContent):
self.content = [] #Content of the post
self.initialPost = ""
self.compact = TaggingContent + CommentingContent #Post that contains the Post, Comments, and Tags
#How do I do this?
def doPost(self):
self.initialPost = raw_input("Post: ")
self.content.append(self.initialPost)
if __name__ == "__main__":
T = Tagging()
C = Commenting()
##Do stuff here with tagging and commenting....
P = Posting(T.content, C.content)
#Do stuff with posting
That way you have the content from Tagging and Commenting into compact from Posting, or am I wrong about what you need?
If you want to ensure in OOP that a set of classes provides obeys a certain contract you normally define an interface.
Python does not provide interfaces directly, but instead it's common to use duck-typeing by the use of something like isinstance or hasattr, which means, that if your object has a content-property use it, if not, raise an error.
Another possiblity to emulate interfaces is available since Python 2.6 by means of Abstract Base Classes
Hope this helps.