Is a tearDown function in a below class really necessary? - django-rest-framework

That`s a code from one of the DRF tutorial. What is the point of tearDown fn if there is nothing new added?
from rest_framework.test import APITestCase
from django.urls import reverse
class TestSetUp(APITestCase):
def setUp(self):
self.register_url = reverse('register')
self.user_data = {
'email': 'example#test.com',
...
}
return super().setUp()
def tearDown(self):
return super().tearDown()

Related

converting Django generic class based LISTVIEW to Rest framework LISTAPIVIEW

I need help to convert the below class-based LISTVIEW to the rest framework LISTAPIVIEW because I want to authenticate users using permission classes simple JWT authentication.
thanks
class MessagesModelList(ListView):
http_method_names = ['get', ]
paginate_by = getattr(settings, 'MESSAGES_PAGINATION', 500)
def get_queryset(self):
if self.kwargs.get('dialog_with'):
qs = MessageModel.objects \
.filter(Q(recipient=self.request.user, sender=self.kwargs['dialog_with']) |
Q(sender=self.request.user, recipient=self.kwargs['dialog_with'])) \
.select_related('sender', 'recipient')
else:
qs = MessageModel.objects.filter(Q(recipient=self.request.user) |
Q(sender=self.request.user)).prefetch_related('sender', 'recipient', 'file')
return qs.order_by('-created')
def render_to_response(self, context, **response_kwargs):
user_pk = self.request.user.pk
data = [serialize_message_model(i, user_pk)
for i in context['object_list']]
page: Page = context.pop('page_obj')
paginator: Paginator = context.pop('paginator')
return_data = {
'page': page.number,
'pages': paginator.num_pages,
'data': data
}
return JsonResponse(return_data, **response_kwargs)
you need to create the below files and and try the following
serializer.py
from rest_framework import serializers
from rest_framework.pagination import PageNumberPagination
from .models import MessageModel
class CustomPagination(PageNumberPagination):
page_size = 500
page_size_query_param = 'page_size'
max_page_size = 10000
class MessagesModelSerializer(serializers.ModelSerializer):
class Meta:
model = MessageModel
fields = "__all__" #use this if you want all the fields of your model available
fields = ['field1','field2', etc..] #use this if you want specific fields of your model
views.py
from .models import MessageModel
from rest_framework import mixins,viewsets
from .serializer import MessagesModelSerializer,CustomPagination
class MessagesModelListView(mixins.ListModelMixin,
viewsets.GenericViewSet):
serializer_class = MessagesModelSerializer
pagination_class = CustomPagination
def get_queryset(self):
if self.kwargs.get('dialog_with'):
qs = MessageModel.objects \
.filter(Q(recipient=self.request.user, sender=self.kwargs['dialog_with']) |
Q(sender=self.request.user, recipient=self.kwargs['dialog_with'])) \
.select_related('sender', 'recipient')
else:
qs = MessageModel.objects.filter(Q(recipient=self.request.user) |
Q(sender=self.request.user)).prefetch_related('sender', 'recipient', 'file')
return qs.order_by('-created')
urls.py
from .views import MessageModelListView
from rest_framework.routers import DefaultRouter
router=DefaultRouter()
router.register('messages', MessagesModelList, 'messages')
This is a basic example of how you can create ListView using DRF. if you need more customization, please refer the documentation : https://www.django-rest-framework.org/api-guide/generic-views/

how to scrape using scrapy with infinite loop without next page information

i need to scrape a url using scrapy and i cant scroll down the website to load all the elements.
i try to seach the next page information but i cant found it
my code of the spider is:
import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
from appinformatica.items import appinformaticaItem
import w3lib.html
class appinformaticaSpider (CrawlSpider):
name = 'appinformatica'
item_count=0
start_urls =['https://www.appinformatica.com/telefonos/moviles/']
rules = {
Rule(LinkExtractor(allow=(), restrict_xpaths=('//*[#class="info-ficha"]/div[1]/a')),
callback='parse_item', follow=False)
}
def parse_item(self, response):
item = appinformaticaItem()
self.item_count += 1
item['Modelo'] = w3lib.html.remove_tags(response.xpath("//h1").get(default=''))
item['Position'] = self.item_count
item['Precio'] = w3lib.html.remove_tags(response.xpath('//*[#id="ficha-producto"]/div[2]/div[1]/div/div[1]').get(default=''))
item['PrecioTienda'] = w3lib.html.remove_tags(response.xpath('//*[#id="ficha-producto"]/div[2]/div[1]/div/div[2]').get(default=''))
item['Stock'] = w3lib.html.remove_tags(response.xpath('//*[#id="ficha-producto"]/div[2]/div[3]/p[3]').get(default=''))
item['Submodelo'] = w3lib.html.remove_tags(response.xpath('//*[#id="ficha-producto"]/div[2]/div[3]/p[2]/strong[2]').get(default=''))
item['Url'] = w3lib.html.remove_tags(response.url)
yield item
anyone can help me?
Change allow to allow=(r'/moviles/.*.html'),follow=True and put your allowed_domains. And try this.
import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
# from appinformatica.items import appinformaticaItem
import w3lib.html
class appinformaticaSpider (CrawlSpider):
name = 'appinformatica'
allowed_domains = ["appinformatica.com"]
item_count=0
start_urls =['https://www.appinformatica.com/telefonos/moviles/']
rules = {
Rule(LinkExtractor(allow=(r'/moviles/.*\.html'), ),
callback='parse_item', follow=True)
}
def parse_item(self, response):
item = {}
self.item_count += 1
item['Modelo'] = w3lib.html.remove_tags(response.xpath("//h1").get(default=''))
item['Position'] = self.item_count
item['Precio'] = w3lib.html.remove_tags(response.xpath('//*[#id="ficha-producto"]/div[2]/div[1]/div/div[1]').get(default=''))
item['PrecioTienda'] = w3lib.html.remove_tags(response.xpath('//*[#id="ficha-producto"]/div[2]/div[1]/div/div[2]').get(default=''))
item['Stock'] = w3lib.html.remove_tags(response.xpath('//*[#id="ficha-producto"]/div[2]/div[3]/p[3]').get(default=''))
item['Submodelo'] = w3lib.html.remove_tags(response.xpath('//*[#id="ficha-producto"]/div[2]/div[3]/p[2]/strong[2]').get(default=''))
item['Url'] = w3lib.html.remove_tags(response.url)
yield item

A simple query but Graphene-Django is returning null values

I am trying to make a simple query with graphene-django but i can not get the DB, it gives me null.
I think the code is ok, what is going wrong, I am working for hours on it.
Do you have any idea, what it is?
Thanks in advance
import graphene
from graphene_django.types import DjangoObjectType, ObjectType
from myProject.models import Times
class TimesType(DjangoObjectType):
class Meta:
model=Times
fields="__all__"
class Query(ObjectType):
today_times = graphene.Field(TimesType, id=graphene.ID())
all_times = graphene.List(TimesType)
def resolve_todaytimes(self, info, id=None):
return Times.objects.get(pk=id)
def resolve_alltimes(root, info, **kwargs):
return Times.objects.all()
schema = graphene.Schema(query=Query, mutation=Mutation)
query {todayTimes(id:"1029"){id}}
{
"data": {
"todayTimes": null
}
}
The resolver method should be named in resolve_<FieldName> format
class Query(ObjectType):
today_times = graphene.Field(TimesType, id=graphene.ID())
all_times = graphene.List(TimesType)
def resolve_today_times(self, info, id=None): # not `resolve_todaytimes`
return Times.objects.get(pk=id)
def resolve_all_times(root, info, **kwargs): # not `resolve_alltimes`
return Times.objects.all()
Alternatively, you can use the resolver parameter to set the callable resolver as,
def resolve_todaytimes(self, info, id=None):
return Times.objects.get(pk=id)
def resolve_alltimes(root, info, **kwargs):
return Times.objects.all()
class Query(ObjectType):
today_times = graphene.Field(
TimesType,
id=graphene.ID(),
resolver=resolve_todaytimes
)
all_times = graphene.List(
TimesType,
resolver=resolve_alltimes
)

Django Rest Framework Testing Exceptions In Views

I have a test class that inherits from APITestCase. This test class has a test case that attempts to mock a function called to raise an exception by another object in one the views being tested. However, my exception is never getting raised by the mock. If I don't inherit from APITestCase the test cases works as expected essentially.
Does APITestCase hide or prevent exceptions from being propagated up?
Here is my view file:
views.py
class Foo(object):
def bar(self):
pass
class Foo2(object):
def bar2(self, f):
f = Foo()
f.bar()
class JobListRest(generics.ListAPIView, generics.CreateAPIView):
queryset = Job.objects.all()
serializer_class = JobSerializer
"""
List all jobs, or create a new job.
"""
#csrf_exempt
def get(self, request, format=None):
jobs = Job.objects.all()
serializer = JobSerializer(jobs, many=True)
return Response(serializer.data)
#csrf_exempt
def post(self, request, format=None):
foo = Foo()
foo.bar()
serializer = JobSerializer(data=request.data)
if serializer.is_valid():
job = serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
test.py
Exception does NOT get raised
class JobPostTest(APITestCase):
def setUp(self):
self.valid_job = """{
'name': 'foo',
'tasks':
[
{
'name':'test_task'
}
]
}"""
#patch('app.views.Foo')
def test_create_job_fails(self, mock):
error = ValidationError
mock.bar.side_effect = error
with self.assertRaises(error):
self.client.post('/api/jobs/', self.valid_job, format='json')
Exception does get raised
class FooTest(TestCase):
#patch('app.views.Foo')
def test_bar(self, mock):
mock.bar.side_effect=ValidationError
foo2 = Foo2()
self.assertRaises(ValidationError, foo2.bar2(1))

How can I force ModelForm to use specific database?

I have this ModelForm:
class ClienteForm(ModelForm):
class Meta:
model = Pessoa
def __init__(self, *args, **kwargs):
vUserProfile = kwargs.pop('vUserProfile', None)
super(ClienteForm, self).__init__(*args, **kwargs)
How can I force to use a specific database?
I can't use db router, because the "specific" database is setting in my User profile, and I don't know how to get UserProfile in db-router class..
I know I can use in ClienteForm.save(using=XXX), but when I try ClienteForm.is_valid I got error, because django is try to use "default" database.
thanks
Reply my own question...
The only way to get this right is make one middleware to get database name and work with locals, like this:
File: middleware.py
from threading import local
from django.contrib.sessions.models import Session
from django.contrib.auth.models import User
from web_core.models import UserProfile
my_local_global = local()
class CustomerMiddleware(object):
def process_request(self, request):
my_local_global.database_name = get_database_name(request)
def get_database_name(request):
session_key = request.session.session_key
try:
session = Session.objects.get(session_key=session_key)
uid = session.get_decoded().get('_auth_user_id')
user = User.objects.get(pk=uid)
profile = UserProfile.objects.get(pk=uid)
if profile:
return profile.dbname
else:
return None
except:
return None
after this, add middleware.py in your settings.py:
MIDDLEWARE_CLASSES = (
(..)
'middleware.CustomerMiddleware',
)
to finish, make one more file to get db router:
File: authrouter:
class PadraoRouter(object):
def db_for_read(self, model, **hints):
from middleware import my_local_global
return my_local_global.database_name
def db_for_write(self, model, **hints):
from middleware import my_local_global
return my_local_global.database_name
def allow_relation(self, obj1, obj2, **hints):
return None
def allow_syncdb(self, db, model):
return True
class AuthRouter(object):
def db_for_read(self, model, **hints):
if model._meta.app_label == 'auth':
return 'auth_db'
if model._meta.app_label == 'sessions':
return 'auth_db'
if model._meta.app_label == 'web_core':
return 'auth_db'
return None
def db_for_write(self, model, **hints):
if model._meta.app_label == 'auth':
return 'auth_db'
if model._meta.app_label == 'sessions':
return 'auth_db'
if model._meta.app_label == 'web_core':
return 'auth_db'
return None
def allow_relation(self, obj1, obj2, **hints):
if obj1._meta.app_label == 'auth' or\
obj2._meta.app_label == 'auth':
return True
if obj1._meta.app_label == 'sessions' or\
obj2._meta.app_label == 'sessions':
return True
if obj1._meta.app_label == 'web_core' or\
obj2._meta.app_label == 'web_core':
return True
return None
def allow_syncdb(self, db, model):
if db == 'auth_db':
return model._meta.app_label == 'auth'
elif model._meta.app_label == 'auth':
return False
return None
NOTE: I need to put import in each def, because Django 1.5.1 has a bug, if you put import into top of file.. cycle imports..
after this, change again your settings.py to add the router:
DATABASE_ROUTERS = ['authrouter.AuthRouter',
'authrouter.PadraoRouter']
Remember
I make this way, because I have one database, only for auth.. each user can access a different database, depending what is save in dbname field.
If you have other solution, please let's me know!
Thanks to everybody.

Resources