Django trying to add "_id" to the primary key OneToOne column - django

Just started Django.
I have 2 models. Radusergroup and expiration. username is primary key on Radusergroup and a OnetoOne Field in expiration with primary_key=True. Django is trying query for username_id in expiration model although the field itself is username only.
When I dont explicitly define Managed=False it also tries to change the username field in expiration table from the database to username_id as well.
What am I doing wrong here ?
class Radusergroup(models.Model):
username = models.CharField(max_length=64,primary_key=True)
groupname = models.CharField(max_length=64)
priority = models.IntegerField()
class Meta:
managed = False
class expiration(models.Model):
username = models.OneToOneField(Radusergroup,on_delete=models.CASCADE, to_field='username', primary_key=True)
expiration = models.DateTimeField()
class Meta:
managed = False
python .\manage.py shell
>>> help(expiration())
Help on expiration in module panel_app.models object:
class expiration(django.db.models.base.Model)
| expiration(*args, **kwargs)
|
| expiration(username, expiration)
|
| Method resolution order:
| expiration
| django.db.models.base.Model
| builtins.object
|
| Methods defined here:
|
| expiration = <django.db.models.query_utils.DeferredAttribute object>
| get_next_by_expiration = _method(self, *, field=<django.db.models.fields.DateTimeField: expiration>, is_next=True, **
kwargs)
|
| get_previous_by_expiration = _method(self, *, field=<django.db.models.fields.DateTimeField: expiration>, is_next=Fals
e, **kwargs)
|
| username_id = <django.db.models.query_utils.DeferredAttribute object>
| ----------------------------------------------------------------------

Thanks dirkgroten for pointing me to the right direction.
Adding db_column solved my problem
class expiration(models.Model):
username = models.OneToOneField(Radusergroup,on_delete=models.PROTECT, to_field='username',db_column="username" , primary_key=True)

Related

Linking one table to each user in Django

I am working on a Django project where I need to link one table(model) to each user.
Assume MyTable_1 maps to user_1 and so on.
The primary key for MyTable will be a DateField which contains continuous dates from the time user signed-up.
MyTable_1 for User_1
|-----------|----------|-------------|-----------------|
| Date(PK) | food_ate | game_played | ran_today |
|-----------|----------|-------------|-----------------|
| 10/01/20 | rice | chess | Yes |
|-----------|----------|-------------|-----------------|
| 11/01/20 |sandwhich | tennis | No |
|-----------|----------|-------------|-----------------|
MyTable_2 for User_2
|-----------|----------|-------------|-----------------|
| Date(PK) | food_ate | game_played | ran_today |
|-----------|----------|-------------|-----------------|
| 16/03/19 | pizza | rugby | Yes |
|-----------|----------|-------------|-----------------|
| 17/03/19 | pasta | football | Yes |
|-----------|----------|-------------|-----------------|
And so on for every new user created. User logs in those information in MyTable.
How can I implement this? I am using PostgreSQL and have written custom User Model.
You really don't need seperate tables just seperate rows.
A ForeignKey relation will do the trick, something like this in your models.py:
# user model:
User(models.Model, ...):
first_name = models.CharField(...)
last_name = models.CharField(...)
...
# log model:
Log(models.Model):
user = models.ForeignKey(User, ...)
date = models.DateField(...)
food_ate = models.CharField(...)
game_played = models.CharField(...)
ran_today = models.CharField(...)
class Meta: unique_together = ('user', 'date',)
Then, elsewhere, you can access your users' logs like so:
user = User.objects.get(id='the_user_id')
logs = user.logs.all()

Django query assigns database columns to wrong model instance properties

Really weird problem - when I query for a model instance the data comes back assigned to the wrong properties.
The model:
class SaleLineItem(models.Model):
sale = models.ForeignKey(Sale, on_delete=models.CASCADE, related_name="sale_line_items")
stock_unit = models.ForeignKey(StockUnit, on_delete=models.CASCADE, related_name="sale_line_items")
currency = models.CharField(max_length=3)
price_original = models.FloatField()
price_paid = models.FloatField()
tax_amount = models.FloatField(null=True, blank=True)
num_sold = models.IntegerField()
sale_line_item_id = models.CharField(max_length=30, null=True, blank=True)
status = models.CharField(max_length=20, choices=SALE_STATUS_CHOICES, null=True, blank=True)
The database row:
id | currency | price_original | price_paid | tax_amount | num_sold | sale_line_item_id | status | sale_id | stock_unit_id
-------+----------+----------------+------------+------------+----------+-------------------+-----------+---------+---------------
15726 | THB | 130 | 130 | | 1 | | delivered | 16219 | 2
And the query:
sli = SaleLineItem.objects.get(pk=15726)
print(sli.pk)
-------------------------
16219
print(sli.stock_unit_id)
-------------------------
THB
print(sli.currency)
-------------------------
130.0
The data get populated on the object but everything is "shifted" by one column.
But if I do the query this way:
SaleLineItem.objects.filter(pk=15726).values()
-------------------------
<QuerySet [{'id': 15726, 'sale_id': 16219, 'stock_unit_id': 2, 'currency': 'THB', 'price_original': 130.0, 'price_paid': 130.0, 'tax_amount': None, 'num_sold': 1, 'sale_line_item_id': None, 'status': 'delivered'}]>
. . . the result is correct.
I thought I might have un-migrated models but I ran both makemigrations and migrate to no effect.
Same result when I use lower-level QuerySet methods:
qs = SaleLineItem.objects.all()
clone = qs._chain()
clone.query.add_q(Q(pk=15726))
print(clone)
------------------------------
<QuerySet [<SaleLineItem: SaleLineItem object (16219)>]>
Note the pk on the model __str__ is incorrect.
Any ideas what's happening here?
Running:
Python 3.7.3
Django 2.2.1
Postgres 10
Turns out it's because I overrode __init__ with an extra (non-field) argument.
#classmethod
def from_db(cls, db, field_names, values):
if len(values) != len(cls._meta.concrete_fields):
values_iter = iter(values)
values = [
next(values_iter) if f.attname in field_names else DEFERRED
for f in cls._meta.concrete_fields
]
new = cls(*values)
new._state.adding = False
new._state.db = db
return new
Database values are populated onto the model using *values, and the model expects fields in a specific order. So you can't have an extra argument in __init__ or the order gets messed up.
Edit:
Had not read this part in the docs (https://docs.djangoproject.com/en/2.1/ref/models/instances/):
You may be tempted to customize the model by overriding the __init__
method. If you do so, however, take care not to change the calling
signature . . .

How to fetch custom column which does not exist in database table?

How can I implement followig SQL QUERY in django rest framework
`SELECT `id` , `name_hi` as hi , `name_en` as en , false as `checked` FROM `tab_name`
where checked does not exist in the database table i.e. it is not a column .
id | hi | en | checked
1 | xx | xx | 0
2 | hi2| en2| 0
3 | hi3| en3| 0
I am using Django Rest framework.
How can I rename these fields also include checked
So far I have tried in serializer
class TabSerializer(serializers.ModelSerializer):
hi = serializers.CharField(source='name_en')
en = serializers.CharField(source='name_en')
class Meta:
model = Tab
fields =('id','name_en','name_hi')
It just return id name_en and name_hi irrespective of hi ,en and checked.
You set it in serializer for column alias
For column table alias
class TabSerializer(serializers.ModelSerializer):
hi = serializers.CharField(source='name_hi')
en = serializers.CharField(source='name_en')
class Meta:
model = TabFaultOption
fields =('id','hi','en')
Now for column which does not exist in the database you need to change in the related model
model.py
class Tab(models.Model):
id = models.IntegerField()
name_hi = models.CharField(max_length=1000)
name_en = models.CharField(max_length=1000)
checked=False
class Meta:
managed = False
db_table = 'tab'
Now in serializer include the checked column
class TabSerializer(serializers.ModelSerializer):
hi = serializers.CharField(source='name_en')
en = serializers.CharField(source='name_en')
checked= false
class Meta:
model = Tab
fields =('id','hi','en','checked')

Django view fetching data from two models in a single query

I have two tables in my database which are relevant for this problem:
exercise_state with following fields:
| id | intensity_level | progress | exercise_id | user_id | current_date | user_rating |
auth_user with following fields:
| id | password | last_login | is_superuser | username | first_name | last_name | email | is_staff | is_active | date_joined |
Right now I am fetching some data in my view as follows:
def get_specific_exercise_finish_count(request, exerciseId):
# Number of users who completed a specific exercise
specific_exercise_finish_count = Exercise_state.objects.filter(exercise_id=exerciseId, intensity_level=7).count()
data = {}
data['count'] = specific_exercise_finish_count
return JSONResponse(data)
Now I want to filter those results further for specific set of usernames i.e. usernames those starts with 'yg_' (I have two sets of usernames registered in my system one group starts with 'yg' and the other with 'yg_'). As username is not a field of exercise_state, I am not sure how to proceed.
How can I achieve this?
I solved it with following code of piece, see the extra part in filter statement:
def get_specific_exercise_finish_count_memoryGames(request, exerciseId):
# Number of users who completed a specific exercise
specific_exercise_finish_count_memoryGames = Exercise_state.objects.filter(exercise_id=exerciseId, intensity_level=7, user__username__startswith='yg_').count()
data = {}
data['count'] = specific_exercise_finish_count_memoryGames
return JSONResponse(data)

model inheritance + django admin

I am reusing the News model from cmsplugin_news, just adding some extra fields in my inheriting model. (Multi-table inheritance, just as explained here.
from cmsplugin_news.models import News
class News(News):
departments = models.ManyToManyField('department.Department', blank=True, related_name="news")
On my admin.py I am extending NewsAdmin to set my own form:
class MyNewsAdmin(NewsAdmin):
form = NewsModelForm
Which I have defined in forms.py:
from news.models import News
class NewsModelForm(NewsForm):
class Meta:
model = News
widgets = {
'excerpt': CKEditorWidget(config_name='basic'),
'content': CKEditorWidget(config_name='default')
}
def _get_widget(self):
from ckeditor.widgets import CKEditorWidget
return CKEditorWidget()
The model inheritance seems to work well when I save objects from the shell console. But when I try to create a MyNews object from the django admin and link it to a department, this field is not saved. Or at least this change is not shown anywhere
unicms-testnews=> select * from cmsplugin_news_news;
id | title | slug | excerpt | content | is_published | pub_date | created | updated | link
----+-------+------+---------+---------+--------------+------------------------+-------------------------------+-------------------------------+------
1 | dfad | dfad | | | f | 2013-09-10 13:44:46+02 | 2013-09-10 13:45:04.709556+02 | 2013-09-10 13:57:05.568696+02 |
(1 row)
unicms-testnews=> select * from news_news;
news_ptr_id
-------------
1
(1 row)
unicms-testnews=> select * from news_news_departments;
id | news_id | department_id
----+---------+---------------
1 | 1 | 1
(1 row)
I can't understand anything, can anyone help me please? Thank you very much!
You created a form for News, that also exist in your DB since the model is not abstract, not for MyNews. Thus your current form has no field for the departments attribute, even if you add a widget with an input for it. Do the code bellow instead:
class MyNewsForm(NewsForm):
class Meta:
model = MyNews # instead of just News
...
What Django does in background is to create two relations: the cmsplugin_news_news stores all the News fields, and the news_news_departments stores your new field and is in one-to-one relation with the first relation.