Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
D
django2-project-template
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
django2-project-template
Commits
1d21a00f
Unverified
Kaydet (Commit)
1d21a00f
authored
Ara 04, 2018
tarafından
Uğur Özyılmazel
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Fix: default managers for base models
üst
44503153
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
124 additions
and
153 deletions
+124
-153
.pylintrc
.pylintrc
+1
-1
README.md
README.md
+21
-53
base.py
applications/baseapp/admin/base.py
+1
-1
user.py
applications/baseapp/admin/user.py
+1
-80
__init__.py
applications/baseapp/forms/__init__.py
+1
-0
user.py
applications/baseapp/forms/user.py
+86
-0
base.py
applications/baseapp/models/base.py
+2
-4
test_basemodel.py
applications/baseapp/tests/test_basemodel.py
+5
-5
test_basemodelwithsoftdelete.py
applications/baseapp/tests/test_basemodelwithsoftdelete.py
+6
-9
No files found.
.pylintrc
Dosyayı görüntüle @
1d21a00f
...
...
@@ -251,7 +251,7 @@ ignore-on-opaque-inference=yes
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local,__proxy__,Style,BaseModelWithSoftDelete
ignored-classes=optparse.Values,thread._local,_thread._local,__proxy__,Style,BaseModelWithSoftDelete
,BasicPost
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
...
...
README.md
Dosyayı görüntüle @
1d21a00f
[
![Build Status
](
https://travis-ci.org/vigo/django2-project-template.svg?branch=master
)
](https://travis-ci.org/vigo/django2-project-template)
![
Python
](
https://img.shields.io/badge/django-3.7.0-green.svg
)
![
Django
](
https://img.shields.io/badge/django-2.1.3-green.svg
)
![
Version
](
https://img.shields.io/badge/version-1.
0.1
-yellow.svg
)
![
Version
](
https://img.shields.io/badge/version-1.
1.0
-yellow.svg
)
# Django Project Starter Template
...
...
@@ -760,7 +760,9 @@ This is a common model. By default, `BaseModel` contains these fields:
-
`updated_at`
-
`status`
Also has custom manager called:
`objects_bm`
. There are 4 basic status types:
We are overriding the default manager.
`BaseModel`
uses
`BaseModelQuerySet`
as
manager,
`BaseModelWithSoftDelete`
uses
`BaseModelWithSoftDeleteManager`
.
There are 4 basic status types:
```
python
STATUS_OFFLINE
=
0
...
...
@@ -769,13 +771,13 @@ STATUS_DELETED = 2
STATUS_DRAFT
=
3
```
Custom manager has custom querysets against these statuses such a
s:
You can make these querie
s:
```
python
>>>
Post
.
objects
_bm
.
deleted
()
# filters: status = STATUS_DELETED
>>>
Post
.
objects
_bm
.
actives
()
# filters: status = STATUS_ONLINE
>>>
Post
.
objects
_bm
.
offlines
()
# filters: status = STATUS_OFFLINE
>>>
Post
.
objects
_bm
.
drafts
()
# filters: status = STATUS_DRAFT
>>>
Post
.
objects
.
deleted
()
# filters: status = STATUS_DELETED
>>>
Post
.
objects
.
actives
()
# filters: status = STATUS_ONLINE
>>>
Post
.
objects
.
offlines
()
# filters: status = STATUS_OFFLINE
>>>
Post
.
objects
.
drafts
()
# filters: status = STATUS_DRAFT
```
## `BaseModelWithSoftDelete`
...
...
@@ -794,7 +796,7 @@ This works exactly like Django’s `delete()`. Broadcasts `pre_delete` and
a dictionary with the number of deletion-marks per object type.
```
python
>>>
Post
.
objects
_bm
.
all
()
>>>
Post
.
objects
.
all
()
SELECT
"blog_post"
.
"id"
,
"blog_post"
.
"created_at"
,
...
...
@@ -812,7 +814,7 @@ Execution time: 0.000135s [Database: default]
<
BaseModelWithSoftDeleteQuerySet
[
<
Post
:
Python
post
1
>
,
<
Post
:
Python
post
2
>
,
<
Post
:
Python
post
3
>
]
>
>>>
Category
.
objects
_bm
.
all
()
>>>
Category
.
objects
.
all
()
SELECT
"blog_category"
.
"id"
,
"blog_category"
.
"created_at"
,
...
...
@@ -826,14 +828,14 @@ SELECT "blog_category"."id",
<
BaseModelWithSoftDeleteQuerySet
[
<
Category
:
Python
>
]
>
>>>
Category
.
objects
_bm
.
delete
()
>>>
Category
.
objects
.
delete
()
(
4
,
{
'blog.Category'
:
1
,
'blog.Post'
:
3
})
>>>
Category
.
objects
_bm
.
all
()
>>>
Category
.
objects
.
all
()
<
BaseModelWithSoftDeleteQuerySet
[]
>
# rows are still there! don’t panic!
>>>
Category
.
objects
.
all
()
<
QuerySet
[
<
Category
:
Python
>
]
>
>>>
Category
.
objects
.
deleted
()
<
BaseModelWithSoftDelete
QuerySet
[
<
Category
:
Python
>
]
>
```
...
...
@@ -1406,46 +1408,7 @@ $ rake test:coverage
```
bash
$ DJANGO_ENV
=
test
python manage.py
test
baseapp
-v
2
# or
$ DJANGO_ENV
=
test
python manage.py
test
baseapp.tests.test_user.CustomUserTestCase
# run single unit
$
rake
test
:baseapp
```
---
## Notes
If you created models via management command or rake task, you’ll have admin
file automatically and generated against your model type. If you created a model
with
`BaseModelWithSoftDelete`
, you’ll have
`BaseAdminWithSoftDelete`
set.
`BaseAdminWithSoftDelete`
uses
`objects_bm`
in
`get_queryset`
and by default,
you’ll have extra actions and soft delete feature. If you don’t want to use
`objects_bm`
manager, you need to override it manually:
```
python
# example: blog/admin/post.py
from
django.contrib
import
admin
from
baseapp.admin
import
BaseAdminWithSoftDelete
from
..models
import
Post
__all__
=
[
'PostAdmin'
,
]
class
PostAdmin
(
BaseAdminWithSoftDelete
):
# sticky_list_filter = None
# hide_deleted_at = False
def
get_queryset
(
self
,
request
):
return
self
.
model
.
objects
.
get_queryset
()
# this line!
admin
.
site
.
register
(
Post
,
PostAdmin
)
$
rake
test
:run[baseapp]
```
---
...
...
@@ -1504,6 +1467,11 @@ This project is licensed under MIT
## Change Log
**2018-12-04**
-
Update:
`BaseModel`
and
`BaseModelWithSoftDelete`
now override
`objects`
via
their own managers.
**2018-11-30**
-
Update: flake8 ignores configured
...
...
applications/baseapp/admin/base.py
Dosyayı görüntüle @
1d21a00f
...
...
@@ -42,7 +42,7 @@ class BaseAdminWithSoftDelete(BaseAdmin):
hide_deleted_at
=
True
def
get_queryset
(
self
,
request
):
qs
=
self
.
model
.
objects
_bm
.
get_queryset
()
qs
=
self
.
model
.
objects
.
get_queryset
()
if
request
.
GET
.
get
(
'status__exact'
,
None
):
if
(
numerify
(
request
.
GET
.
get
(
'status__exact'
))
...
...
applications/baseapp/admin/user.py
Dosyayı görüntüle @
1d21a00f
from
django
import
forms
from
django.contrib
import
admin
from
django.contrib.auth.admin
import
(
UserAdmin
as
BaseUserAdmin
,
)
from
django.contrib.auth.forms
import
(
ReadOnlyPasswordHashField
,
)
from
django.db
import
models
from
django.utils.html
import
format_html
from
django.utils.translation
import
ugettext_lazy
as
_
from
..forms
import
UserChangeForm
,
UserCreationForm
from
..models
import
User
from
..widgets
import
AdminImageFileWidget
__all__
=
[
'UserAdmin'
]
class
UserChangeForm
(
forms
.
ModelForm
):
password
=
ReadOnlyPasswordHashField
(
label
=
_
(
'Password'
),
help_text
=
_
(
'Raw passwords are not stored, so there is no way to see this '
'user
\'
s password, but you can change the password using '
'<a href="../password/">this form</a>.'
),
)
class
Meta
:
model
=
User
fields
=
(
'email'
,
'first_name'
,
'last_name'
,
'password'
,
'is_active'
,
'is_staff'
,
'is_superuser'
,
)
labels
=
{
'first_name'
:
_
(
'first name'
)
.
title
(),
'last_name'
:
_
(
'last name'
)
.
title
(),
}
def
clean_password
(
self
):
return
self
.
initial
[
'password'
]
class
UserCreationForm
(
forms
.
ModelForm
):
password1
=
forms
.
CharField
(
label
=
_
(
'Password'
),
widget
=
forms
.
PasswordInput
)
password2
=
forms
.
CharField
(
label
=
_
(
'Password confirmation'
),
widget
=
forms
.
PasswordInput
,
)
class
Meta
:
"""
`fields` property holds only required fields.
"""
model
=
User
fields
=
(
'first_name'
,
'last_name'
)
labels
=
{
'first_name'
:
_
(
'first name'
)
.
title
(),
'last_name'
:
_
(
'last name'
)
.
title
(),
}
def
clean_password2
(
self
):
password1
=
self
.
cleaned_data
.
get
(
'password1'
)
password2
=
self
.
cleaned_data
.
get
(
'password2'
)
if
(
password1
and
password2
and
password1
!=
password2
):
raise
forms
.
ValidationError
(
_
(
'Passwords don
\'
t match'
)
)
return
password2
def
save
(
self
,
commit
=
True
):
user
=
super
(
UserCreationForm
,
self
)
.
save
(
commit
=
False
)
user
.
set_password
(
self
.
cleaned_data
[
'password1'
])
if
commit
:
user
.
save
()
return
user
class
UserAdmin
(
BaseUserAdmin
):
form
=
UserChangeForm
...
...
applications/baseapp/forms/__init__.py
0 → 100644
Dosyayı görüntüle @
1d21a00f
from
.user
import
*
# noqa
applications/baseapp/forms/user.py
0 → 100644
Dosyayı görüntüle @
1d21a00f
from
django
import
forms
from
django.contrib.auth
import
get_user_model
from
django.contrib.auth.forms
import
(
ReadOnlyPasswordHashField
,
)
from
django.utils.translation
import
ugettext_lazy
as
_
__all__
=
[
'UserChangeForm'
,
'UserCreationForm'
]
User
=
get_user_model
()
class
UserChangeForm
(
forms
.
ModelForm
):
password
=
ReadOnlyPasswordHashField
(
label
=
_
(
'Password'
),
help_text
=
_
(
'Raw passwords are not stored, so there is no way to see this '
'user
\'
s password, but you can change the password using '
'<a href="../password/">this form</a>.'
),
)
class
Meta
:
model
=
User
fields
=
(
'email'
,
'first_name'
,
'last_name'
,
'password'
,
'is_active'
,
'is_staff'
,
'is_superuser'
,
)
labels
=
{
'first_name'
:
_
(
'first name'
)
.
title
(),
'last_name'
:
_
(
'last name'
)
.
title
(),
}
def
clean_password
(
self
):
return
self
.
initial
[
'password'
]
class
UserCreationForm
(
forms
.
ModelForm
):
password1
=
forms
.
CharField
(
label
=
_
(
'Password'
),
widget
=
forms
.
PasswordInput
)
password2
=
forms
.
CharField
(
label
=
_
(
'Password confirmation'
),
widget
=
forms
.
PasswordInput
,
)
class
Meta
:
"""
`fields` property holds only required fields.
"""
model
=
User
fields
=
(
'first_name'
,
'last_name'
)
labels
=
{
'first_name'
:
_
(
'first name'
)
.
title
(),
'last_name'
:
_
(
'last name'
)
.
title
(),
}
def
clean_password2
(
self
):
password1
=
self
.
cleaned_data
.
get
(
'password1'
)
password2
=
self
.
cleaned_data
.
get
(
'password2'
)
if
(
password1
and
password2
and
password1
!=
password2
):
raise
forms
.
ValidationError
(
_
(
'Passwords don
\'
t match'
)
)
return
password2
def
save
(
self
,
commit
=
True
):
user
=
super
(
UserCreationForm
,
self
)
.
save
(
commit
=
False
)
user
.
set_password
(
self
.
cleaned_data
[
'password1'
])
if
commit
:
user
.
save
()
return
user
applications/baseapp/models/base.py
Dosyayı görüntüle @
1d21a00f
...
...
@@ -160,8 +160,7 @@ class BaseModel(models.Model):
verbose_name
=
_
(
'Status'
),
)
objects
=
models
.
Manager
()
objects_bm
=
BaseModelQuerySet
.
as_manager
()
objects
=
BaseModelQuerySet
.
as_manager
()
class
Meta
:
abstract
=
True
...
...
@@ -173,8 +172,7 @@ class BaseModelWithSoftDelete(BaseModel):
null
=
True
,
blank
=
True
,
verbose_name
=
_
(
'Deleted At'
)
)
objects
=
models
.
Manager
()
objects_bm
=
BaseModelWithSoftDeleteManager
()
objects
=
BaseModelWithSoftDeleteManager
()
class
Meta
:
abstract
=
True
...
...
applications/baseapp/tests/test_basemodel.py
Dosyayı görüntüle @
1d21a00f
...
...
@@ -30,7 +30,7 @@ class BaseModelTestCase(TestCase):
def
test_basemodel_queryset
(
self
):
self
.
assertQuerysetEqual
(
BasicPost
.
objects
_bm
.
all
()
.
order_by
(
'id'
),
BasicPost
.
objects
.
all
()
.
order_by
(
'id'
),
[
'<BasicPost: Test Post 1>'
,
'<BasicPost: Test Post 2>'
,
...
...
@@ -39,18 +39,18 @@ class BaseModelTestCase(TestCase):
],
)
self
.
assertQuerysetEqual
(
BasicPost
.
objects
_bm
.
actives
()
.
order_by
(
'id'
),
BasicPost
.
objects
.
actives
()
.
order_by
(
'id'
),
[
'<BasicPost: Test Post 1>'
],
)
self
.
assertQuerysetEqual
(
BasicPost
.
objects
_bm
.
offlines
(),
BasicPost
.
objects
.
offlines
(),
[
'<BasicPost: Test Post 3>'
],
)
self
.
assertQuerysetEqual
(
BasicPost
.
objects
_bm
.
deleted
(),
BasicPost
.
objects
.
deleted
(),
[
'<BasicPost: Test Post 2>'
],
)
self
.
assertQuerysetEqual
(
BasicPost
.
objects
_bm
.
drafts
(),
BasicPost
.
objects
.
drafts
(),
[
'<BasicPost: Test Post 4>'
],
)
applications/baseapp/tests/test_basemodelwithsoftdelete.py
Dosyayı görüntüle @
1d21a00f
...
...
@@ -36,17 +36,17 @@ class BaseModelWithSoftDeleteTestCase(TestCase):
],
)
self
.
assertQuerysetEqual
(
Category
.
objects
_bm
.
actives
(),
Category
.
objects
.
actives
(),
[
'<Category: Python>'
],
)
self
.
assertQuerysetEqual
(
Category
.
objects
_bm
.
offlines
(),
[]
Category
.
objects
.
offlines
(),
[]
)
self
.
assertQuerysetEqual
(
Category
.
objects
_bm
.
deleted
(),
[]
Category
.
objects
.
deleted
(),
[]
)
self
.
assertQuerysetEqual
(
Category
.
objects
_bm
.
drafts
(),
[]
Category
.
objects
.
drafts
(),
[]
)
def
test_softdelete
(
self
):
...
...
@@ -56,14 +56,11 @@ class BaseModelWithSoftDeleteTestCase(TestCase):
(
3
,
{
'baseapp.Category'
:
1
,
'baseapp.Post'
:
2
}),
)
self
.
assertQuerysetEqual
(
Category
.
objects
_bm
.
deleted
(),
Category
.
objects
.
deleted
(),
[
'<Category: Python>'
],
)
self
.
assertQuerysetEqual
(
Category
.
objects
.
all
(),
[
'<Category: Python>'
]
)
self
.
assertQuerysetEqual
(
Post
.
objects_bm
.
deleted
()
.
order_by
(
'id'
),
Post
.
objects
.
deleted
()
.
order_by
(
'id'
),
[
'<Post: Python post 1>'
,
'<Post: Python post 2>'
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment