---
# System prepended metadata

title: React x Django

---

# React x Django

* [[React x Django] React Setup](/M7PPnLw4Q5yAFzGw3XoNsQ)
* [[React x Django] React Router](/96BTQu6zR_yUPpsR5P6tGA)
* [[React x Django] 後端環境架設](/ozxW1lbISAqnhUVzr-yNew)
* [[React x Django] Django REST Framework](/o6pWjIXQRHS1GHScFb2Z_A)
* [[React x Django] Fetching Data (Axios)](/MVJSODOHRK2FMaE4KRQ8FA)
* [[Django] 上傳圖片](/2hy5qHDJQmeFqAuVkSt95w)
* [[React x Django] Serializers 序列化](/isUMEhIISvudUKh0vo_rTA)
* [[React x Django] Simple JWT](/6pYUYhOBRGmUHZ0J76bFwA)

---
後端API製作
>[[React x Django] Update Profile Endpoint](/Et_SDYq1QRKLqUePqHN22w)
---
* [[React x Django] 前後端整合(上)- User Login Reducer and Action](/7uQrGG7zQ3i7knAcstJoCQ)
* [[React x Django] 前後端整合(下)- User Login Screen and Functionality](/dPqXR4LaTOK9S3u6_4TVmw)
* [[React x Django] 畫面整合（純顯示）](/sOdjbtedSWO2w1X6_KGL8A)
* [[React x Django] 顯示登入資訊（ Logout & Login Navbar）](/9FjocdUbQj6Ys9z3uPov9A)
* [[React x Django] User Register](/Sa8VdhnjR2K4HVyzAizKsg)
* [[React x Django] Google登入登出功能](/nom1EsZ6QXm-mOjGjA90vw)
* [[React x Django] Update Profile Endpoint](/Et_SDYq1QRKLqUePqHN22w)
* [[React x Django] 有外來鍵的物件/外來鍵下拉式選單](/GpPj14j3Ru6hmvja60mZ7A)

---
小 Tips
* [[React x Django] Headers Config](/E9ZFwOAjTLyiRAfQjK41jA)
* [[React x Django] UseEffect 渲染無窮迴圈](/uRWZV5zsQZ2Kvpf9-xjvFw)
* [[React x Django] Checkbox](/d5qcAWr-R9CBsc0A9RBw9w)
* [[React] React-bootstrap Datepicker](/wZW1a5OjTGWhQlpe_T1YCw)
---
參考連結：

[Django ORM Cookbook](https://books.agiliq.com/projects/django-orm-cookbook/en/latest/index.html)

---
## DB 遷移
`python manage.py makemigrations`

`python manage.py migrate`

## BUGFIX

### 網路傳輸問題
#### 405 POST method not allowed
` "POST /api/school/create HTTP/1.1" 405 41`
解決方式：
要POST的網址最後少一個 `/`


#### AssertionError: Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` to be returned from the view, but received a `<class 'str'>`
解決方式：
要在Response 前加入 `return Response`

### 系統端問題
#### Django後端改admin密碼
解決方式：
`python manage.py changepassword ME`

### 資料庫問題

#### 如果 `models.py` migrate 後還是 `No such table` 或 `No detection` ,`No migrations to apply`可以改執行
`python manage.py migrate --run-syncdb`

#### 初始makemigrations記得加上`my_app`名稱才能把migration都紀錄在資料夾中
`python manage.py makemigrations <my_app>`

#### 萬一migrate之後有欄位要加入，出現`no such column 'fields'`
處理方式：
先將`fields`從`models.py`中刪掉
執行
`python manage.py makemigrations`
`python manage.py migrate`
如果有錯誤，多執行下面這行
`python manage.py migrate --fake`
然後繼續把`fields`再重新加回 `models.py`
執行
`python manage.py makemigrations`
`python manage.py migrate`

### Serializer
#### SerializerMethodField
外來鍵關聯的物件有很多欄位我們是用不到的，都傳給前端會有資料冗餘，就需要我們自己去定製序列化外來鍵物件的哪些欄位


#### DRF模型序列化器默認僅返回數據庫中已存在字段，如果想新增輸出字段，該如何操作?
例如:輸出用戶角色時,順便輸出當前角色總共有多少用戶.

`models.py`

```python=
class Role(models.Model):
    """角色表,一的一方"""
    name = models.CharField(max_length=30, unique=True, verbose_name=‘角色名稱‘)  # 媒體運營,廣告運營,活動運營,財務,技術,唯一,必填
    desc = models.CharField(max_length=100, null=True, blank=True, verbose_name=‘角色描述‘)  # 非必填
 
    class Meta:
        db_table = ‘tb_role‘
        verbose_name = ‘角色‘
        verbose_name_plural = verbose_name
 
    def __str__(self):
        """控制對象輸出內容"""
        return self.name
 
 
class User(BaseModel):
    """用戶表,多的一方"""
    account = models.CharField(max_length=30, unique=True, verbose_name=‘登錄賬戶‘)  # 必填,唯一
    password = models.CharField(max_length=100, null=True, blank=True, default=‘888888‘,
                                verbose_name=‘登錄密碼‘)  # 非必填,默認888888,長度100是為了以後加密擴展
    username = models.CharField(max_length=30, null=True, blank=True, verbose_name=‘用戶名稱‘)  # 非必填
    role = models.ForeignKey(Role, on_delete=models.CASCADE, related_name=‘user‘, verbose_name=‘角色‘)
 
    class Meta:
        db_table = ‘tb_user‘
        verbose_name = ‘用戶‘
        verbose_name_plural = verbose_name
 
    def __str__(self):
        """控制對象輸出內容"""
        return self.account
```

`serializer.py`
```python=
class RoleModelSerializer(serializers.ModelSerializer):
    """角色模型序列化器"""
    user_count = serializers.SerializerMethodField(label=‘用戶數量‘)  # 新增數據庫不存在字段用戶數量
 
    class Meta:
        model = Role
        fields = [‘id‘, ‘name‘, ‘desc‘, ‘user_count‘]
 
    def get_user_count(self, obj):
        """
        返回當前角色用戶數量
        固定寫法,obj代表Role實例對象,模型類配置了反向引用user代表當前角色用戶
        """
        number = obj.user.count()
        return number
```

### 外鍵資料顯示名稱而不是id 在Serilizers調整

希望在table上不要顯示id，而是外鍵的實際名稱
![](https://i.imgur.com/pkWGL0D.png)

```python=
class MemberSerializer(serializers.ModelSerializer):
    family = serializers.SerializerMethodField(read_only = True)
    intro_by = serializers.SerializerMethodField(read_only = True)
    class Meta:
        model = Member
        fields = '__all__'
    
    def get_family(self, obj):
        family_one = obj.family
    
        serializer = MemberSerializer(family_one, many=False)
       
        return serializer.data['name']

    def get_intro_by(self, obj):
        intro_by_one = obj.intro_by
        serializer = MemberSerializer(intro_by_one, many=False)
        
        return serializer.data['name']
```
第2行 family：為我們宣告Member其中一個欄位 `family`
第3行 intro_by：為我們宣告Member其中一個欄位 `intro_by`

在前面先行宣告代表我們後面要進行處理
第8行 get_family 及 第15行 get_intro_by

名字不能改變，程式執行時要拿family與intro_by時就會去get_family 及 get_intro_by
而models中的外鍵是對Member，這邊則拿family的id去執行Member的Serilizer找出該 id 的member，然後我們回傳的時候要Member裡name的欄位
經過這個函式處理，family這個欄位會由 id 轉成 family 的 name 顯示回去
get_intro_by也是同樣道理


### Django ORM Self-Join
```manager = models.ForeignKey('self', on_delete=models.CASCADE)```

### ForeignKey does not allow null values

```
The blank option is used in the form validation, and the null is used when writing to database.

So you might add null=True to that field.

EDIT: continue the comment

Considering the two steps when saving object:

Validator(controlled by blank)
Database limitation(controlled by null)
For default option, take IntegerField for example,
default=5, blank=True, null=False, pass (1) even if you didn't assign a value(having blank=True), pass (2) because it has a default value(5) and writes 5 instead of None to DB.
blank=True, null=False, which pass (1) but not (2), because it attempts to write None to DB.

Thus, if you want to make a field optional, use either default=SOMETHING, blank=True, null=False or blank=True, null=True.


```
所以，如果有Foreign Key的欄位要optional的話
改成 `blank=True, null=True`
```python=
family = models.ForeignKey('self', on_delete=models.SET_NULL, blank=True, null=True,related_name="member_family_User")
```

#### Model 日期自動更新
```python=
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
```

#### BUG: __str__ returned non-string (type Student)
```python=
 def __str__(self):
    return self.student_name
```
serilizers.py需作修改
```python=
 def __str__(self):
    return str(self.student_name)
```


### Table 內排序
`models.py`中，每個table末端補上
```python=
 class Meta:
        ordering = ('-created_at',)
```
* 記得加上 `,` ，不然會出現
`'ordering' must be a tuple or list (even if you want to order by only one field).` 錯誤

### 多Table Join


---

### React 
#### 下拉式選單

##### Uncaught Error: input is a void element tag and must neither have `children` nor use `dangerouslySetInnerHTML`.

##### `Warning: Each child in an array or iterator should have a unique 'key' prop.`
在 JSX 的 { } 中用 inline 的寫法：
```javascript=
{numbers.map((numbers) =>
      <li key={numbers.toString()}>{numbers}</li>
    )}
```
執行上面的例子，你可能有發現在 console 中 React 給你一個警告訊息是：
Warning: Each child in an array or iterator should have a unique 'key' prop.

`字面上的意思是，你需要給陣列中的每一個 React 元素一個唯一的編號 (unique key)，編號是字串型態，設定在 key 這個屬性上。`

因為 React 需要知道實際上哪個元素是哪一個，React 的 Virtual DOM Diff 演算法才能確定哪些元素是需要在 DOM 中被新增的、哪些是要更新的、哪些是要被刪除的。

`React 用 key 在陣列中判斷是不是同一個元素物件。`

改成：
```javascript=
const listItems = numbers.map((numbers) =>
  <li key={numbers.toString()}>{numbers}</li>
);`
```
或 每個元素不好想出個編號，或陣列中的元素順序是固定不變的

```javascript=

const todoItems = todos.map((todo, index) =>
  // 利用 map function 的第二個 index 參數
  <li key={index}>
    {todo.text}
  </li>
);

```

在我遇到的例子
將`<Dropdown.item></Dropdown.item>`加上 `index`, 及`key={index}`
```javascript=
{schools.map((school,index) =>{
            
            return <Dropdown.Item eventKey={[school._id,school.name] } key={index} >{school.name}</Dropdown.Item>
            })}
```

#### React顯示true or false
`沒辦法直接以oneStud.is_end顯示結果` 
需改成
```javascript=
<td>{oneStud.is_end == true ? "是":"否"}</td>
```

#### React 畫面重新整理
`history.push(redirect)`：只是跳回頁面
如果需要重新整理：
`window.location.href = redirect`：不用再跳回以後按重新整理

#### Objects are not valid as a React child. If you meant to render a collection of children, use an array instead
代表傳入的東西homes為Array，沒辦法直接在前端上跑出來
需要用迭代取出來
`homes.map(home => (...))`


#### TypeError: history.push is not a function
```javascript=
function SettingScreen(history)
```
要改成
```javascript=
function SettingScreen({history})
```


#### Uncaught TypeError: Cannot read property 'push' of undefined (React-Router-Dom)
成因：因為history的傳導過程斷掉了，可能是內崁頁面所以吃不到history
解決方式：
手動給一次
```javascript=
//載入 useHistory
import { useHistory } from "react-router-dom";
```
```javascript=
//把值塞給history
 let history = useHistory();
```
可正常跳轉了
```javascript=
history.push('/asdfg')
```
>ref:
[StackOverflow| uncaught-typeerror-cannot-read-property-push-of-undefined-react-router-dom](https://stackoverflow.com/questions/44009618/uncaught-typeerror-cannot-read-property-push-of-undefined-react-router-dom)

### 編輯時找不到match時會跳掉需要再按一次
將
```javascript=
if (!incomeContribute.context || incomeContribute._id != Number(incomeContributeContextId)){
             history.push(redirect)       
            }
             }else{
                setContext(incomeContribute.context)

            }
```
redirect移除，只進行判斷，不做任何處理
```javascript=
if (!incomeContribute.context || incomeContribute._id != Number(incomeContributeContextId)){
                 //保持無動作
            }
             }else{
                setContext(incomeContribute.context)

            }
```



---

### Uncaught Range Error invalid time value

原因：
因為我們的值傳入時的格式不正確


修改方式： 

因為原本的值來自moment轉出來的，
所以先將拿出來的string `semester.start_date` 強轉化成moment後
再轉成Date型態

```javascript=
var start_date_for=moment(semester.start_date).toDate();
setStart_date(start_date_for)
```

### Check Reducer is Null?

使用`{outcome} || []` 來判斷，不要使用`{outcome} === null`
```javascript=

const outcomeDetailReducer = useSelector(state=>state.outcomeDetail)
const {errorOutcomeDetail, loadingOutcomeDetail, outcome} = outcomeDetailReducer
    ...
return (
    ...
            {loadingOutcomeDetail ? <Loader />
                : errorOutcomeDetail ? <Message variant='danger'>{errorOutcomeDetail}</Message>
                    :{outcome} || []? <h1>無支出</h1>
                        :<div>

                          支出項目： {outcome.name} 
                          支出金額： {outcome.outcome_money} 
                        
                        </div>
            }
            ...
            )
```

### React Inline Color
```javascript=
<h3 style={{color:"red"}}>無資助項目</h3>
```




### Django jwt token error. "Given token not valid for any token type, token_not_valid"
調整抓token的方式
${userInfo.token} -> ${userInfo.access}
```javascript=
 const config = {
            headers: {
                'Content-type': 'application/json',
                Authorization: `Bearer ${userInfo.access}`
            }
        }
```