Django admin does update instead of insert - django

My models are the following:
class Station(models.Model):
sid = models.IntegerField(primary_key=True)
uid = models.ForeignKey('User', db_column='uid', verbose_name='User')
name = models.CharField(max_length=100)
# and others...
class Meta:
managed = False
db_table = 'Stations'
class Playlist(models.Model):
plid = models.IntegerField(primary_key=True)
name = models.CharField(max_length=200)
changed = models.BooleanField(default = False)
def __unicode__(self):
return self.name
class Meta:
managed = False
db_table = 'Playlists'
class Stationplaylist(models.Model):
spid = models.IntegerField(primary_key=True, db_column='spid')
sid = models.ForeignKey(Station, db_column='sid')
plid = models.ForeignKey(Playlist, db_column='plid')
syncronized = models.BooleanField()
def __unicode__(self):
return self.plid.name
class Meta:
managed = False
db_table = 'StationsPlaylists'
unique_together=('sid', 'plid')
and I want to perform insert operation in my view:
def addPlaylist(request, app_label='webadmin', **kwargs):
# stuff...
selected_playlists = request.POST.getlist('selected_playlists[]')
current_station = request.POST.get('station')
totalPlaylists = Stationplaylist.objects.filter(sid=current_station).count()
last_spid = None
for playlist in selected_playlists:
if playlist != 'on':
if totalPlaylists==0:
last_spid=1
elif last_spid == None:
last_obj = Stationplaylist.objects.order_by('-pk')[0]
last_spid = last_obj.spid + 1
else:
last_spid += 1
Stationplaylist(last_spid, current_station, playlist, 0).save() # 0-syncronized
totalPlaylists+=1
return HttpResponse('OK')
but when I call this for, say Station#1, with 3 playlists and then I call this on another one, let it be Station#2, the playlists are simply updated. I mean, in database, their station field is updated to the Station#2.
Why is that happening and how to solve it?
Thanks in advance

You've overridden the automatic primary key and made it a pure IntegerField. This doesn't autoincrement, so every new instance gets the same default primary key.
You really shouldn't define your own primary key field unless you have a really good reason. But if you do have that good reason, you should use AutoField rather than IntegerField.

Related

How to create a new pk if there is no pk in the table i refers to

I am working on a web project using django drf.
There was a problem during the development, so I want someone who can help me. 😥
First, let me show you my models.
Container
class Container(models.Model):
cont_no = models.CharField(primary_key=True, max_length=11)
cont_sz = models.ForeignKey('Size', models.PROTECT, db_column='cont_sz')
cont_type = models.ForeignKey(
'Type', models.PROTECT, db_column='cont_type')
class Meta:
managed = False
db_table = 'container'
Size
class Size(models.Model):
sz = models.CharField(primary_key=True, max_length=5)
use_yn = models.BooleanField()
class Meta:
managed = False
db_table = 'size'
Type
class Type(models.Model):
type = models.CharField(primary_key=True, max_length=10)
type_name = models.CharField(max_length=20)
use_yn = models.BooleanField()
class Meta:
managed = False
db_table = 'type'
Import
class Import(models.Model):
wo_no = models.OneToOneField(
'Wo', models.PROTECT, db_column='wo_no', primary_key=True)
cont_no = models.ForeignKey(
Container, models.PROTECT, db_column='cont_no', blank=True, null=True)
category = models.CharField(max_length=6)
.
.
.
class Meta:
managed = False
db_table = 'import'
As you can see, the cont_no field in the Import table refers to the Container table.
The following data exists in the Container table:
cont_no | cont_sz | cont_type
-------------+---------+------------
ABCD0000001 | 4000 | DRY
ABCD0000002 | 2000 | DRY
ABCD0000003 | 4000 | DRY
I want a new value with pk 'ABCD0000004' in the Container table when the cont_no of the data present in the Import table is changed to 'ABCD0000004' using the patch method.
The method I tried is to define the save function of the model:
class Import(models.Model):
.
.
.
def save(self, *args, **kwargs):
all_containers = Container.objects.all()
size = Size.objects.get(sz='40ST')
type = Type.objects.get(type='DRY')
for container in all_containers:
if container.cont_no == self.cont_no.cont_no:
print("Match found:", container)
break
else:
new_container = Container(cont_no=self.cont_no, cont_sz=size, cont_type=type)
new_container.save()
print("Save new container:", new_container)
class Meta:
managed = False
db_table = 'import'
It's a similar code, but I tried one more time:
class Import(models.Model):
.
.
.
def save(self, *args, **kwargs):
size = Size.objects.get(sz='40ST')
type = Type.objects.get(type='DRY')
try:
container = Container.objects.get(cont_no=self.cont_no.cont_no)
print(container)
except Container.DoesNotExist:
new_container = Container(cont_no=self.cont_no.cont_no, cont_sz=size, cont_type=type)
new_container.save()
print(new_container)
class Meta:
managed = False
db_table = 'import'
However, all of the above methods cause the following error.
"PATCH /test/import/IM2302130001 HTTP/1.1" 400 35117
"cont_no": [
"Invalid pk \"ABCD0000004\" - object does not exist."
]
class Import(models.Model):
.
.
.
def save(self, *args, **kwargs):
size = Size.objects.get(sz='40ST')
type = Type.objects.get(type='DRY')
try:
container = Container.objects.get(cont_no=self.cont_no.cont_no)
except Container.DoesNotExist:
container = Container(cont_no=self.cont_no.cont_no, cont_sz=size, cont_type=type)
container.save()
super().save(*args, **kwargs)
How about calling save method of superclass?
I just add last line to call the save method.
You can also use get_or_create() in the following way:
class Import(models.Model):
...
def save(self, *args, **kwargs):
size = Size.objects.get(sz='40ST')
type = Type.objects.get(type='DRY')
container, created = Container.objects.get_or_create(
cont_no=self.cont_no.cont_no,
defaults={'cont_sz': size.sz,
'cont_type': type.type})
if created:
print("New Container has been created", container)
else:
print("Container already exists", container)
class Meta:
managed = False
db_table = 'import'

django 3.0 inline admin form foreignkey -> foreignkey

I have any models and one Manager
app/models.py
class castratedListStudent(models.Manager):
use_in_migrations = False
def get_query_set(self):
return super().get_query_set().filter(isOn=1)
class student(models.Model):
id = models.AutoField(primary_key=True)
firstName = models.CharField(max_length=20)
lastName = models.CharField(max_length=20)
isOn = models.BooleanField()
default_manager = castratedListStudent()
objects = castratedListStudent()
class discipline(models.Model):
id = models.AutoField(primary_key=True)
nameDiscipline = models.CharField(max_length=100, null=False)
itemIdToDiscip = models.ForeignKey(item, on_delete=models.CASCADE, default=1)
class listOfStudForDiscipline(models.Model):
id = models.AutoField(primary_key=True)
discipListId = models.ForeignKey(discipline, on_delete=models.CASCADE)
studId = models.ForeignKey(student, on_delete=models.CASCADE)
I am using django inline
accounts/admin.py
class discipStudentInline(admin.TabularInline):
model = listOfStudForDiscipline
admin.TabularInline.verbose_name = 'Student'
extra = 0
def has_change_permission(self, request, obj=None):
return False
def get_queryset(self, request):
return self.model.objects.filter(studId__isOn=1)
class disciplineAdmin(admin.ModelAdmin):
model = discipline
inlines = [discipStudentInline]
The Inline form is displayed on the HTML page and filter (studId__isOn=1) works. But the problem is that on the HTML page below there is a field that allows you to add another student and the list of students is not filtered by the filter rule(studId__isOn=1) When I check in the DEBUG_SQL console, I can see how the query goes without the WHERE expression "FROM journal_student".
(0.000) SELECT `journal_listofstudfordiscipline`.`id`, `journal_listofstudfordiscipline`.`discipListId_id`, `journal_listofstudfordiscipline`.`studId_id` FROM `journal_listofstudfordiscipline` INNER JOIN `journal_student` ON (`journal_listofstudfordiscipline`.`studId_id` = `journal_student`.`id`) WHERE (`journal_student`.`isOn` = 1 AND journal_listofstudfordiscipline`.`discipListId_id` = 1) ORDER BY `journal_student`.`lastName` DESC; args=(True, 1)
(0.000) SELECT `journal_student`.`id`,..., `journal_student`.`descriptionStudent` FROM journal_student` ORDER BY `journal_student`.`lastName` ASC, `journal_student`.`firstName` ASC; args=()
I couldn't solve the problem using the model Manager.
I solved the problem. It turned out that after django version 1.7, the get_query_set() method was renamed to get_queryset(). And the Manager will now look like this:
class castratedListStudent(models.Manager):
use_in_migrations = False
def get_query_set(self):
return super(liveListStudent, self).get_queryset().filter(isOn=1)

Django import export - How to skip the new rows, and only update the existed ones

When importing a file I want to skip all of the new rows that doesn't exist, and only update and change the ones that already exists, I've been trying for days to solve this problem, any ideas will help.
https://ibb.co/1Gw4Q19
also the file type is ".xls" or ".xlsx"
here's my code:
models.py:
class Author(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Book(models.Model):
name = models.CharField('Book name', max_length=100)
author = models.ForeignKey(Author, blank=True, null=True, on_delete=models.CASCADE)
author_email = models.EmailField('Author email', max_length=75, blank=True)
imported = models.BooleanField(default=False)
published = models.DateField('Published', blank=True, null=True)
price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
categories = models.ManyToManyField(Category, blank=True)
def __str__(self):
return self.name
admin.py:
class BookResource(resources.ModelResource):
class Meta:
model = Book
import_id_field = 'id'
import_id_fields = ('id',)
fields = ('id', 'name', 'price',)
skip_unchanged = True
report_skipped = True
dry_run = True
class CustomBookAdmin(ImportMixin, admin.ModelAdmin):
resource_class = BookResource
# tried to override it like so but it didn't work
def skip_row(self, instance, original):
original_id_value = getattr(original, self._meta.import_id_field)
instance_id_value = getattr(instance, self._meta.import_id_field)
if original_id_value != instance_id_value:
return True
if not self._meta.skip_unchanged:
return False
for field in self.get_fields():
try:
if list(field.get_value(instance).all()) != list(field.get_value(original).all()):
return False
except AttributeError:
if field.get_value(instance) != field.get_value(original):
return False
return True
So if you want to skip any rows in the import file which do not already exist in the database, then you can ignore any rows which don't have a pk (i.e. have not previously been persisted):
Just add the following to your BookResource sub class
def skip_row(self, instance, original):
return getattr(original, "pk") is None
I hope this works - let me know if I've misunderstood anything.
The full solution exists here
To only update existing items while ignoring any new item you can use:
# Do not import any new items. Only update records
def skip_row(self, instance, original):
if original.id:
return False
return super(BookResource, self).skip_row(instance, original)
To import only new items while preventing updates you can use:
# Only import new items. Do not update any record
def skip_row(self, instance, original):
if not original.id:
return False
return True
This assumes import_id_fields = ('id',) and resource is called BookResource

How to use djando-table2 with class based view to display data from multiple table?

models.py
class DailyRecordManager(models.Manager):
def get_query_set(self):
qs = super(DailyRecordManager, self).get_query_set().order_by('date_organised')
return qs
class DailyRecord(models.Model):
date_organised = models.DateField('Ogransied Date', help_text=('Enter Date when the program is organised: CCYY-MM-DD'))
program_name = models.TextField('program name',)
venue = models.CharField('venue', max_length = 255, blank=True)
organiser = models.ForeignKey(Organiser, verbose_name = 'Organiser', related_name = 'organisers')
objects = models.Manager()
public = DailyRecordManager()
class Meta:
verbose_name = 'dailyrecord'
verbose_name_plural = 'dailyrecords'
ordering = ['-date_organised']
def __str__(self):
return self.program_name
class Participant(models.Model):
participant = models.CharField(max_length= 50, unique = True)
daily_record = models.ForeignKey(DailyRecord, verbose_name = 'program_name')
class Meta:
verbose_name = 'participant'
verbose_name_plural = 'participants'
def __str__(self):
return self.participant
views.py
class DailyActivityPageView(SingleTableView):
table_class = DailyRecordTable
queryset = DailyRecord.public.all()
# queryset = Participant(DailyRecord.public.all()) is not working
template_name = 'dailyrecord/daily-activity-record.html'
tables.py
class DailyRecordTable(tables.Table):
date_organised = tables.Column('Date')
program_name = tables.Column( 'Program Name')
venue = tables.Column( 'Venue')
organiser = tables.Column( 'Organiser')
participant = tables.Column( 'dailyrecord.participant')
# daily = tables.RelatedLinkColumn()
class Meta:
model = DailyRecord
Now what I need is to display the data from participant table too, corresponding to the daily_record foreign key.
Click this link to view the snapshot. see the last column of the table. I need the data of Participant.partcipant column here
Sorry for poor English.
Thank You
There are two problems here.
First is, that a daily record can have multiple participants. Thus, in order to fill last column you have to aggregate all possible participants into that column (for example as list).
Second is, that you should make Participant backwards related to DailyRecord by adding attribute "related_name" to daily_record in your Participant model, like this:
daily_record = models.ForeignKey(DailyRecord, verbose_name = 'program_name', related_name="participants")
Now, you should simply get participants from daily_record like this:
participants = DailyRecord.public.first().participants.all()
If you had OneToOneField instead of ForeignKey you could add (single) participant to table like this:
participant = tables.Column( "Participant", accessor='participant')

Auto populate DateTimeField not working in django forms

I am getting below error when I use auto_now_add in my Model Form.
TypeError: __init__() got an unexpected keyword argument 'auto_now_add'
Here is my model field
modified = models.DateTimeField(blank = True)
Declaration in form. I have seen in one of the posts DateTimeField Not Working
to add initial = datetime.datetime.now for auto populating
import datetime
modified = forms.DateTimeField(initial = datetime.datetime.now) - When I use this no error is coming but datetime was not auto populating.
I have used the same in self.fields['modified'] - Still no use
Any of the above statements were not working. Some one help me on this.
I am pasting all my model class and Model Form here
Model Class
class Users(models.Model):
name = models.CharField(max_length = 100)
role = models.ForeignKey(RolesConfig, db_column = 'role')
level = models.ForeignKey(LevelConfig, db_column = 'level')
team_name = models.ForeignKey(TeamNamesConfig, db_column = 'team_name')
location = models.ForeignKey(LocationConfig, db_column = 'location')
modified = models.DateTimeField(blank = True)
class Meta:
db_table = u'users'
def __str__(self):
return "%s" % (self.ldap)
def __unicode__(self):
return u'%s' % (self.ldap)
I have modified the field in phpmyadmin
This is my ModelForm
class TargetForm(forms.ModelForm):
modified = forms DateTimeField(initial = datetime.datetime.now)
def __init__(self, *args, **kwargs):
super(MMPodTargetForm, self).__init__(*args, **kwargs)
self.fields['modified'] = forms.DateTimeField(initial = datetime.datetime.now)
class Meta:
model = models.Users
I need to get current date and time autopopulated in the form, when the form loads. Tell me whats wrong in my code.
I think the error is because you're adding the auto_now_add extra argument to your form instead of to your mode. Try changing your model to the following to see if that fixes the problem (untested):
class Users(models.Model):
name = models.CharField(max_length = 100)
role = models.ForeignKey(RolesConfig, db_column = 'role')
level = models.ForeignKey(LevelConfig, db_column = 'level')
team_name = models.ForeignKey(TeamNamesConfig, db_column = 'team_name')
location = models.ForeignKey(LocationConfig, db_column = 'location')
modified = models.DateTimeField(auto_now = True)
class Meta:
db_table = u'users'
def __str__(self):
return "%s" % (self.ldap)
def __unicode__(self):
return u'%s' % (self.ldap)