I have a Django app that works with multiple databases and I'm having an issue trying to read data specifically from (testdb2) database.
I do know that you can choose which database that you want to read data using keyword (Using) but that didn't work. The result is it's always tries to read data from (testdb).
Here is the code for database in (Settings.py):
DATABASES = {
'default': {
'NAME': 'testdb',
'ENGINE': 'django.db.backends.postgresql',
'USER': 'username',
'PASSWORD': 'password',
'HOST': 'host',
'PORT': 'port',
},
'users': {
'NAME': 'testdb2',
'ENGINE': 'sql_server.pyodbc',
'USER': 'username',
'PASSWORD': 'password',
'HOST': 'host',
'PORT': 'port',
'OPTIONS': {
'driver': 'ODBC Driver 13 for SQL Server',
},
},
}
Here is the code for (Views.py):
from rest_framework import viewsets
from .models import MyModel
from .serializers import MyModelSerializer
# Create your views here.
class MyModelView(viewsets.ModelViewSet):
queryset = MyModel.objects.using('users').all()
serializer_class = MyModelSerializer
Here is the code for (Models.py):
from django.db import models
from django.db import connection
# Create your models here.
class MyModel(models.Model):
columnName = models.IntegerField(db_column='columnName', primary_key=True)
columnEmail= models.IntegerField(db_column='columnEmail')
columnAddress= models.IntegerField(db_column='columnAddress')
columnPhone= models.IntegerField(db_column='columnPhone')
class Meta:
managed = False # Created from a view. Don't remove.
db_table = 'UserTable'
MyModel is based on a view that is created inside the database.
My question: How can I read data from the database (testdb2)
Thanks :D
I think viewset uses using method only in list. Because using method is only in queryset, so don't use viewset, or use a database router.
I recommend you database router. Check Database Router Doc
In addition to Yongjin Jo's opinion, ModelViewSet in DRF inherits CreateModelMixin. And it's create function.
class CreateModelMixin(object):
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
def get_success_headers(self, data):
try:
return {'Location': str(data[api_settings.URL_FIELD_NAME])}
except (TypeError, KeyError):
return {}
function create model instance by Serializer. So using method is not used.
You can override save method in Serializer. Or Use database router as Yongjin Jo said.
Related
I'am using MySQL and PostgreSQL in my Django project. Below are the settings:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mysql_db',
'USER': 'username',
'PASSWORD': 'password',
'HOST': 'hostname',
'PORT': '3306',
},
'postgres_db': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'pgsql_db',
'USER': 'username',
'PASSWORD': 'password',
'HOST': 'hostname',
'PORT': '5432',
}
}
And this is the sample model
from postgres_copy import CopyManager
class Items(models.Model):
class params:
db = "postgres_db"
sales_value = models.CharField(max_length=255, null=True, blank=True)
primary_email = models.CharField(max_length=255, null=True, blank=True)
objects = CopyManager()
I want to use Items.objects.all().to_csv('./path/to/csv) this ORM to export model data to CSV. I have used this before in exporting large dataset to csv.
But in this configuration it gives below error
psycopg2.errors.SyntaxError: syntax error at or near "."
LINE 1: COPY (SELECT `sales_item`.`id`, `sales_item`.`sales_value`,...
This seems to be an issue with multiDB.
If I run this ORM in single DB configuration, or even if I set default alias on PostgreSQL this works fine.
CopyManager seems to be getting default alias somehow which I have no idea about.
How can I run this ORM in current settings without any issues?
Any help would be appreciated.
Thanks in advance.
We use postgres and MariaDB in the same time in one project.
I can say - you dont need any additional data manager, in your case it can be:
from django.db.import models
class ItemsQuerySetManager(models.Manager):
def get_queryset(self, *args, **kwargs):
return super().get_queryset(*args, **kwargs).using("postgres_db")
class Items(models.Model):
sales_value = models.CharField(max_length=255, null=True, blank=True)
primary_email = models.CharField(max_length=255, null=True, blank=True)
objects = ItemsQuerySetManager()
more info here: https://docs.djangoproject.com/en/4.1/topics/db/multi-db/
I tried to start using Postgresql instead of sqlite in my Django project.
I installed postgreqL ON MY Windows, creatred a new database, user and password.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'database_name',
'USER': 'admin',
'PASSWORD': 'admin',
'HOST': 'localhost',
'PORT': '5432',
}
}
But when I try to migrate or makemigrations, I got this:
File
"C:\Users\s...\venv\lib\site-packages\django\db\backends\utils.py",
line 85, in _execute
return self.cursor.execute(sql, params) psycopg2.errors.UndefinedTable: relation "authentication_author" does
not exist LINE 1: ...hentication_author"."is_doctor" FROM
"authentic...
here is my model:
class Author(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, related_name="author")
slug = models.CharField(max_length=50, null=True, blank=True,)
is_doctor = models.BooleanField(default=False)
And yes, I deleted the sqlite3 database, all the migrations folders and I created new ones with the init.py inside of them.
But still get the same problem.
Updated
Traceback screenshots:
It happens with Django. Sometimes you can invoke some code that relies on a new DB schema at the time you're trying to makemigrations.
All you need in this situation is to temporarily comment out all the code that connects makemigrations with your new model's schema. As it was in this question, you can trace related blocks of code just using full traceback.
Error: TypeError: Field 'id' expected a number but got <class 'account.models.User'>.
I have been reading the authentication documentation and I keep getting that error. I have tried a few different permutations of this but I'm really not sure what is going wrong other than its obviously a type error.
The end goal is to just return the 'id' and 'email' of the newly created user, along with the token, I haven't been able to test the token returning yet, because of this error, but I imagine it should be good.
What is working though is it is successfully posting a new user to the database with a token in another table with a matching key and now I have about 50 users from just testing and messing around.
Side note I have overridden the default User Django sets you up with, but I followed the documentation so that code should be solid, but if need I can obviously post it
Views.py
from rest_framework import status
from .models import User
from .serializers import UserSerializer, RegisterSerializer
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework.authtoken.models import Token
#api_view(['POST',])
def RegisterAPI(request):
if request.method == 'POST':
serializer = RegisterSerializer(data = request.data)
if serializer.is_valid(raise_exception=True):
user = serializer.save()
content = {
'user': {'id': user.pk, 'email': user.email},
'auth': Token.objects.get(user = User).key
}
# Return the reponse
return Response(content)`
Serializers.py
from rest_framework import serializers
from django.contrib.auth import get_user_model
from django.contrib.auth import authenticate
from .models import User
# Register Serializer
class RegisterSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'email', 'password')
extra_kwargs = {'password':{'write_only': True}}
def save(self):
user = User(
email = self.validated_data['email'],
)
password = self.validated_data['password']
user.set_password(password)
user.save()
return user
# User Serializer
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('email')
Documentation
Similar article that didn't help me
You are passing the User model class to the .get(...) method, but it should be the User model instance which is just got from the serializer.
#api_view(['POST', ])
def register_api(request):
if request.method == 'POST':
serializer = RegisterSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
content = {
'user': {'id': user.pk, 'email': user.email},
'auth': Token.objects.get(user=user).key
}
# Return the reponse
return Response(content)
I created a simple test case like this:
from unittest import TestCase
import user_manager
class UserTest(TestCase):
def test_register(self):
email = "dung7#gmail.com"
password = "123456"
result, user = user_manager.setup_new_user(email, password)
self.assertEqual(result, CodeID.SUCCESS)
Then I run the testcase:
python manage.py test users
And here is the log:
Creating test database for alias 'default'...
/Users/admin/Projects/MyApp/venv/lib/python2.7/site-packages/django/db/backends/mysql/base.py:112: Warning: Table 'mysql.column_stats' doesn't exist
return self.cursor.execute(query, args)
Creating test database for alias 'myapp_log'...
.FE
======================================================================
ERROR: test_register (users.tests.UserTest)
----------------------------------------------------------------------
Traceback (most recent call last):
...
ProgrammingError: (1146, "Table 'test_myapp.user' doesn't exist")
So it created a test database but seem like it didn't create the tables. Here is my DATABASES setting:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "myapp",
'USER': "root",
'PASSWORD': "",
'HOST': '127.0.0.1',
'PORT': '',
},
'myapp_log': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "myapp_log",
'USER': "root",
'PASSWORD': "",
'HOST': '127.0.0.1',
'PORT': '',
},
}
And my model:
class User(BaseModel):
uid = models.IntegerField(primary_key=True)
email = models.CharField(max_length=200)
password = models.CharField(max_length=200)
create_time = models.IntegerField()
update_time = models.IntegerField()
status = models.IntegerField()
social_token = models.CharField(max_length=200)
social_app = models.IntegerField()
class Meta:
db_table = 'user'
Anyone know why the table 'user' is not created?
UPDATE:
user_manager from my testcase will do some query and add new record on table user.
And I thought when I run the testcase, Django will somehow read my models and create a test database with all the table from those models. Am I right about this?
So I found out I need to put my models.py in my users' folder and add 'users' into the INSTALLED_APPS setting. Now it worked.
Your test database needs to be different than your production database. Test databases are destroyed once the test cases are run. In your case the database was not created. You should go through this documentation for detailed information https://docs.djangoproject.com/en/1.10/topics/testing/overview/
Can you also add the snippet of your user_manager module
I need to execute filter query inside tastypie resources. the input should be the headers of url for example
new Ext.data.Store({
proxy: {
url :'api/users/'
type: "ajax",
headers: {
"Authorization": "1"
}
}
})
I tried below
from tastypie.authorization import Authorization
from django.contrib.auth.models import User
from tastypie.authentication import BasicAuthentication
from tastypie import fields
from tastypie.resources import ModelResource, ALL, ALL_WITH_RELATIONS
from tastypie.validation import Validation
from userInfo.models import ExProfile
class UserResource(ModelResource,request):
class Meta:
queryset = User.objects.filter(id=request.META.get('HTTP_AUTHORIZATION'))
resource_name = 'user'
excludes = ['email', 'password', 'is_active', 'is_staff', 'is_superuser']
authorization = Authorization()
authentication=MyAuthentication()
it is saying name 'request' is not defined. How to pass filters on ORM them?
Not sure why are you inheriting request in UserResource.
I needed to do something like this and the best solution I could come up was to overwrite the dispatch method. Like this
class UserResource(ModelResource):
def dispatch(self, request_type, request, **kwargs):
self._meta.queryset.filter(id=request.META.get('HTTP_AUTHORIZATION'))
return super(UserResource, self).dispatch(request_type, request, **kwargs)
Well , i found apply_filter very useful.
We can pass link like
http://localhost:8000/api/ca/entry/?format=json&userid=a7fc027eaf6d79498c44e1fabc39c0245d7d44fdbbcc9695fd3c4509a3c67009
Code
class ProfileResource(ModelResource):
class Meta:
queryset =ExProfile.objects.select_related()
resource_name = 'entry'
#authorization = Authorization()
#authentication = MyAuthentication()
filtering = {
'userid': ALL,
'homeAddress': ALL,
'email': ALL,
'query': ['icontains',],
}
def apply_filters(self, request, applicable_filters):
base_object_list = super(ProfileResource, self).apply_filters(request, applicable_filters)
query = request.META.get('HTTP_AUTHORIZATION')
if query:
qset = (
Q(api_key=query)
)
base_object_list = base_object_list.filter(qset).distinct()
return base_object_list