json
This commit is contained in:
parent
ab4454320a
commit
a3723bcdd6
18519
logs/app.log
18519
logs/app.log
File diff suppressed because it is too large
Load Diff
13
main.py
13
main.py
|
@ -3,7 +3,8 @@ from fastapi.responses import RedirectResponse
|
|||
from fastapi.templating import Jinja2Templates
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from model.database import init_db
|
||||
from routers import index, logins, users, product, profile, jobs, client
|
||||
from routers import index, logins, users, product, profile, jobs, client, auth1
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
import logging
|
||||
|
||||
|
@ -23,6 +24,14 @@ app = FastAPI(title="API для turboapply",
|
|||
# on_startup=[start_workers]
|
||||
)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"], # Разрешить запросы отовсюду (для тестов)
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
# Настройка шаблонов
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
||||
|
@ -35,6 +44,8 @@ app.include_router(logins.router, tags=["login"], include_in_schema=False)
|
|||
app.include_router(users.router, tags=["users"], include_in_schema=False)
|
||||
app.include_router(product.router, tags=["product"], include_in_schema=False)
|
||||
app.include_router(client.router, tags=["client"])
|
||||
app.include_router(auth1.router, tags=["auth1"], include_in_schema=False)
|
||||
|
||||
|
||||
|
||||
# Подключение роутеров
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from sqlalchemy import Column, Integer, String, Text, DateTime, Float, Boolean, BigInteger, ForeignKey, DateTime
|
||||
from sqlalchemy.dialects.mysql import JSON
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||
|
||||
from typing import AsyncGenerator
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql import func
|
||||
from sqlalchemy.orm import sessionmaker, declarative_base
|
||||
|
@ -50,9 +51,14 @@ async def init_db():
|
|||
await session.commit()
|
||||
|
||||
# Зависимость FastAPI для работы с БД
|
||||
async def get_async_session() -> AsyncSession:
|
||||
# async def get_async_session() -> AsyncSession:
|
||||
# async with async_session() as session:
|
||||
# yield session
|
||||
|
||||
async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
|
||||
async with async_session() as session:
|
||||
yield session
|
||||
yield session # Сессия остается открытой во время запроса
|
||||
|
||||
|
||||
# Функции для хеширования паролей
|
||||
def hash_password(password: str) -> str:
|
||||
|
@ -115,6 +121,7 @@ class Job(Base):
|
|||
link = Column(String(2083), nullable=True) # URL вакансии
|
||||
link_company = Column(String(2083), nullable=True) # URL компании
|
||||
active = Column(Boolean, default=True) # Вакансия активна?
|
||||
text = Column(Text, nullable=True)
|
||||
|
||||
|
||||
# Связь с AppliedJobs
|
||||
|
@ -129,6 +136,9 @@ class Client(Base):
|
|||
user_login = Column(String(55), unique=True, index=True, nullable=False) # ✅ Правильно
|
||||
user_nicename = Column(String(55), unique=True, index=True, nullable=True) # ✅ Правильно
|
||||
user_email = Column(String(55), unique=True, index=True, nullable=True) # ✅ Правильно
|
||||
phone = Column(String(55), unique=True, index=True, nullable=True) # ✅ Правильно
|
||||
|
||||
json_data = Column(Text, nullable=True)
|
||||
# user_registered = Column(String(2083), nullable=True) # URL вакансии
|
||||
user_status = Column(Boolean, default=True)
|
||||
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
from fastapi import FastAPI, Depends, HTTPException, status, Form, Response, Request, APIRouter
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.future import select
|
||||
from passlib.context import CryptContext
|
||||
import jwt
|
||||
from datetime import datetime, timedelta
|
||||
from model.database import get_async_session, User
|
||||
|
||||
SECRET_KEY = "your_secret_key"
|
||||
REFRESH_SECRET_KEY = "your_refresh_secret_key"
|
||||
ALGORITHM = "HS256"
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES = 1
|
||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||
|
||||
def create_access_token(data: dict, expires_delta: timedelta | None = None):
|
||||
to_encode = data.copy()
|
||||
expire = datetime.utcnow() + (expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
|
||||
to_encode.update({"exp": expire})
|
||||
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
||||
|
||||
async def authenticate_user(db: AsyncSession, username: str, password: str):
|
||||
result = await db.execute(select(User).where(User.username == username))
|
||||
user = result.scalars().first()
|
||||
return user if user and pwd_context.verify(password, user.hashed_password) else None
|
||||
|
||||
router = APIRouter(prefix="/auth", tags=["auth"])
|
||||
|
||||
@router.post("/logins")
|
||||
async def logins(username: str = Form(...), password: str = Form(...), db: AsyncSession = Depends(get_async_session)):
|
||||
user = await authenticate_user(db, username, password)
|
||||
if not user:
|
||||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Неправильный логин или пароль")
|
||||
|
||||
access_token = create_access_token({"sub": user.username, "role": user.role})
|
||||
refresh_token = create_access_token({"sub": user.username}, expires_delta=timedelta(days=7))
|
||||
|
||||
response = Response()
|
||||
response.set_cookie(key="access_token", value=access_token, httponly=True)
|
||||
response.set_cookie(key="refresh_token", value=refresh_token, httponly=True)
|
||||
|
||||
return {"message": "Успешный вход"}
|
||||
|
||||
@router.post("/logout")
|
||||
async def logout(response: Response):
|
||||
response.delete_cookie("access_token")
|
||||
response.delete_cookie("refresh_token")
|
||||
return {"message": "Вы вышли"}
|
||||
|
||||
@router.post("/refresh")
|
||||
async def refresh_token(request: Request, response: Response):
|
||||
refresh_token = request.cookies.get("refresh_token")
|
||||
if not refresh_token:
|
||||
raise HTTPException(status_code=401, detail="❌ Refresh token отсутствует")
|
||||
|
||||
try:
|
||||
payload = jwt.decode(refresh_token, REFRESH_SECRET_KEY, algorithms=[ALGORITHM])
|
||||
username = payload.get("sub")
|
||||
if not username:
|
||||
raise HTTPException(status_code=401, detail="❌ Ошибка токена")
|
||||
except jwt.ExpiredSignatureError:
|
||||
raise HTTPException(status_code=401, detail="❌ Refresh token истёк")
|
||||
except jwt.InvalidTokenError:
|
||||
raise HTTPException(status_code=401, detail="❌ Ошибка refresh токена")
|
||||
|
||||
new_access_token = create_access_token({"sub": username})
|
||||
response.set_cookie(key="access_token", value=new_access_token, httponly=True)
|
||||
|
||||
return {"access_token": new_access_token}
|
|
@ -1,9 +1,13 @@
|
|||
from fastapi import FastAPI, HTTPException, APIRouter, Request, Header
|
||||
from fastapi import FastAPI, HTTPException, APIRouter, Request, Header, Depends
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from typing import Dict
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.orm import Session
|
||||
import json
|
||||
from model.database import get_async_session, Client
|
||||
from utils.clients import upsert_client
|
||||
from typing import Union
|
||||
|
||||
router = APIRouter()
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
|
@ -11,7 +15,7 @@ API_KEY = "4545454"
|
|||
|
||||
# Пример данных
|
||||
clients = {
|
||||
27: {"username": "John Doe", "email": "john@example.com", "phone": "+123456781"},
|
||||
1: {"username": "John Doe", "email": "john@example.com", "phone": "+123456781"},
|
||||
44: {"username": "Jane Smith", "email": "jane@example.com", "phone": "+987654321"}
|
||||
}
|
||||
@router.get("/get_client/{client_id}", include_in_schema=False)
|
||||
|
@ -22,17 +26,36 @@ async def get_client_modal(client_id: int):
|
|||
return JSONResponse(content=client)
|
||||
|
||||
class JsonData(BaseModel):
|
||||
json_data: str
|
||||
|
||||
json_data: Union[dict, str]
|
||||
|
||||
|
||||
@router.post("/client/")
|
||||
async def client(data: JsonData, x_api_key: str = Header(None)):
|
||||
# Проверяем API-ключ
|
||||
async def client(data: JsonData, x_api_key: str = Header(...), db: Session = Depends(get_async_session)):
|
||||
if x_api_key != "4545454":
|
||||
raise HTTPException(status_code=403, detail="Invalid API Key")
|
||||
|
||||
# Если json_data строка — декодируем
|
||||
if isinstance(data.json_data, str):
|
||||
try:
|
||||
data.json_data = json.loads(data.json_data)
|
||||
|
||||
|
||||
except json.JSONDecodeError:
|
||||
raise HTTPException(status_code=400, detail="Invalid JSON format")
|
||||
|
||||
print("Полученные данные:", data.json_data)
|
||||
return {"message": "JSON получен", "data": "ok"}
|
||||
|
||||
try:
|
||||
parsed_data = json.loads(data.json_data) # Декодируем JSON
|
||||
print("Полученные данные:", parsed_data)
|
||||
return {"message": "JSON получен", "data": parsed_data}
|
||||
except json.JSONDecodeError as e:
|
||||
raise HTTPException(status_code=400, detail=f"Invalid JSON: {str(e)}")
|
||||
|
||||
|
||||
|
||||
# first_name = parsed_data['first_name']
|
||||
# last_name = parsed_data['last_name']
|
||||
# email_addr = parsed_data['email_addr']
|
||||
# user_id = parsed_data['user_id']
|
||||
# phone_num = parsed_data['phone_num']
|
||||
|
||||
# print(first_name)
|
||||
# # data = await upsert_client(db, first_name, last_name, email_addr, parsed_data)
|
||||
# client = await upsert_client(db, user_id, first_name, last_name, email_addr, phone_num, str(parsed_data))
|
||||
# print(f"Received data: data={client}")
|
|
@ -52,7 +52,7 @@ async def login(
|
|||
return Response(content="Неправильный логин или пароль", media_type="text/html")
|
||||
|
||||
access_token = create_access_token(data={"sub": username, "role": user.role})
|
||||
response = RedirectResponse(url="/", status_code=303)
|
||||
response = RedirectResponse(url="/product", status_code=303)
|
||||
response.set_cookie(key="access_token", value=access_token, httponly=True)
|
||||
return response
|
||||
|
||||
|
|
4780
search_jobes2.json
4780
search_jobes2.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -28,12 +28,7 @@
|
|||
</a>
|
||||
<div class="side-nav__devider my-6"></div>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/" class="side-menu {% if current_path == '/' %}side-menu--active{% endif %}">
|
||||
<div class="side-menu__icon"> <i data-feather="home"></i> </div>
|
||||
<div class="side-menu__title"> Dashboard </div>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/product" class="side-menu {% if current_path.startswith('/product') %}side-menu--active{% endif %}">
|
||||
<div class="side-menu__icon"> <i data-feather="credit-card"></i> </div>
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<h2 class="text-lg font-medium mr-auto">Add Users</h2>
|
||||
|
||||
<form action="/users/create" method="post">
|
||||
<div class="mt-3"> <label>Email</label> <input type="text" class="input w-full border mt-2" name="username" placeholder="username"> </div>
|
||||
<div class="mt-3"> <label>Username</label> <input type="text" class="input w-full border mt-2" name="username" placeholder="username"> </div>
|
||||
<div class="mt-3"> <label>Password</label> <input type="password" name="password"class="input w-full border mt-2" placeholder="secret"> </div>
|
||||
|
||||
<label>Role:</label>
|
||||
|
|
179
utils/app.py
179
utils/app.py
|
@ -47,10 +47,15 @@ def pars_jobs(geo):
|
|||
}
|
||||
for item in search_jobs
|
||||
]
|
||||
# print(search_job)
|
||||
file_path = "search_jobes2.json"
|
||||
|
||||
|
||||
# file_path = "search_jobes2.json"
|
||||
# with open(file_path, "w", encoding="utf-8") as json_file:
|
||||
# json.dump(search_jobes, json_file, indent=4, ensure_ascii=False)
|
||||
|
||||
file_path = "search_jobes3.json"
|
||||
with open(file_path, "w", encoding="utf-8") as json_file:
|
||||
json.dump(search_jobes, json_file, indent=4, ensure_ascii=False)
|
||||
json.dump(search_jobs, json_file, indent=4, ensure_ascii=False)
|
||||
|
||||
print(f"Результаты успешно сохранены в {file_path}")
|
||||
|
||||
|
@ -59,31 +64,90 @@ def add_to_bd():
|
|||
#[ ]: Написать функцию записи в БД
|
||||
pass
|
||||
|
||||
def get_job(job_id):
|
||||
jobs = api.get_job(job_id)
|
||||
text = jobs['description']['text']
|
||||
location = jobs['formattedLocation']
|
||||
title = jobs['title']
|
||||
listedAt = jobs['listedAt']
|
||||
async def get_job(db: AsyncSession, job_id: str):
|
||||
try:
|
||||
jobs = api.get_job(job_id)
|
||||
|
||||
# Проверка наличия всех необходимых данных в ответе
|
||||
required_keys = ["description", "formattedLocation", "title", "listedAt", "companyDetails"]
|
||||
for key in required_keys:
|
||||
if key not in jobs:
|
||||
logging.error(f"❌ Ошибка: Ключ {key} отсутствует в API-ответе")
|
||||
return None
|
||||
|
||||
# Извлечение данных
|
||||
text = jobs['description']['text']
|
||||
location = jobs['formattedLocation']
|
||||
title = jobs['title']
|
||||
listed_at = jobs['listedAt']
|
||||
|
||||
company_info = jobs.get("companyDetails", {}).get("com.linkedin.voyager.deco.jobs.web.shared.WebCompactJobPostingCompany", {}).get("companyResolutionResult", {})
|
||||
company_name = company_info.get("name", "Unknown")
|
||||
company_url = company_info.get("url", "")
|
||||
|
||||
link = f'https://www.linkedin.com/jobs/view/{job_id}/'
|
||||
|
||||
|
||||
workplace_types = jobs.get("workplaceTypesResolutionResults", {})
|
||||
|
||||
# Преобразование из миллисекунд в секунды и конвертация
|
||||
future_date = datetime.fromtimestamp(listedAt / 1000)
|
||||
# Текущая дата
|
||||
current_date = datetime.now()
|
||||
# Разница в днях
|
||||
difference = abs((future_date - current_date).days)
|
||||
jobPostingId = jobs['jobPostingId']
|
||||
localizedName = jobs['workplaceTypesResolutionResults']
|
||||
# Извлекаем все localizedName
|
||||
localized_names = [value['localizedName'] for value in localizedName.values()]
|
||||
localized_name = ", ".join(localized_names)
|
||||
# localized_name = workplaceTypesResolutionResults['urn:li:fs_workplaceType:2']['localizedName']
|
||||
link = f'https://www.linkedin.com/jobs/view/{job_id}/'
|
||||
names = jobs['companyDetails']['com.linkedin.voyager.deco.jobs.web.shared.WebCompactJobPostingCompany']['companyResolutionResult']['name']
|
||||
url = jobs['companyDetails']['com.linkedin.voyager.deco.jobs.web.shared.WebCompactJobPostingCompany']['companyResolutionResult']['url']
|
||||
if workplace_types:
|
||||
first_key = next(iter(workplace_types)) # Берём первый (и единственный) ключ
|
||||
workplace_data = workplace_types[first_key]
|
||||
|
||||
localized_name = workplace_data.get("localizedName", "Unknown")
|
||||
entity_urn = workplace_data.get("entityUrn", "")
|
||||
|
||||
logging.info(f"🏢 Тип работы: {localized_name} ({entity_urn})")
|
||||
else:
|
||||
localized_name = "Unknown"
|
||||
entity_urn = ""
|
||||
|
||||
# Теперь можно добавить эти значения в БД
|
||||
# job.location_type = localized_name
|
||||
# job.entity_urn = entity_urn
|
||||
|
||||
# Проверка, есть ли вакансия в базе
|
||||
query = select(Job).filter(Job.job_id == job_id)
|
||||
result = await db.execute(query)
|
||||
job = result.scalars().first()
|
||||
|
||||
if job:
|
||||
logging.info(f"🔄 Обновление вакансии {job_id} в базе...")
|
||||
job.text = json.dumps(jobs)
|
||||
job.link = link
|
||||
job.location = location
|
||||
job.job_company = company_name
|
||||
job.link_company = company_url
|
||||
job.location_type = localized_name
|
||||
else:
|
||||
logging.info(f"🆕 Добавление вакансии {job_id} в базу...")
|
||||
job = Job(
|
||||
job_id=job_id,
|
||||
text=json.dumps(jobs),
|
||||
link=link,
|
||||
location=location,
|
||||
job_company=company_name,
|
||||
link_company=company_url
|
||||
)
|
||||
db.add(job)
|
||||
|
||||
# Коммит и обновление внутри активной сессии
|
||||
await db.commit()
|
||||
await db.refresh(job)
|
||||
logging.info(f"✅ Вакансия {job_id} успешно сохранена")
|
||||
return job
|
||||
|
||||
except Exception as e:
|
||||
# await db.rollback() # Откат транзакции при ошибке
|
||||
logging.error(f"❌ Ошибка при обработке вакансии {job_id}: {e}")
|
||||
# return None
|
||||
|
||||
# except Exception as e:
|
||||
# await db.rollback()
|
||||
# logging.error(f"❌ Ошибка при обработке вакансии {job_id}: {e}")
|
||||
# return None
|
||||
# [ ]: job_level job_type hourly_rate найти minimum_annual_salary и salary_currency добавил description names Компании url на компанию
|
||||
logging.info(f"title: {title}, location: {location}, jobPostingId: {jobPostingId}, difference: {difference}, location_type: {localized_name}, link: {link} ===== {names} {url}") #text:{text},
|
||||
# logging.info(f"title: {title}, location: {location}, jobPostingId: {jobPostingId}, difference: {difference}, location_type: {localized_name}, link: {link} ===== {url}") #text:{text},
|
||||
|
||||
|
||||
|
||||
|
@ -132,41 +196,53 @@ async def get_vakansi():
|
|||
|
||||
|
||||
|
||||
geo = '100025096'
|
||||
# geo = '100025096'
|
||||
# pars_jobs(geo)
|
||||
|
||||
|
||||
|
||||
|
||||
# def main():
|
||||
# get_vakansi()
|
||||
# logging.info("WORK")
|
||||
# get_job('4130181356')
|
||||
# async def main():
|
||||
# # get_vakansi()
|
||||
# # logging.info("WORK")
|
||||
# # jobs =
|
||||
# # async def main():
|
||||
# async for db in get_async_session(): # Асинхронный генератор сессий
|
||||
|
||||
# query = select(Job).filter(Job.active == 2)
|
||||
# result = await db.execute(query)
|
||||
# job = result.scalars().first()
|
||||
# for j in job:
|
||||
# ids = j.job_id
|
||||
# print(ids)
|
||||
# # await get_job(db, '4192842821')
|
||||
# # break # Выход после первого использования
|
||||
|
||||
|
||||
|
||||
# pars_jobs(geo)
|
||||
# # pars_jobs(geo)
|
||||
|
||||
# main()
|
||||
# if __name__ == "__main__":
|
||||
# asyncio.run(main())
|
||||
|
||||
from sqlalchemy.orm import sessionmaker, declarative_base
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||
# from sqlalchemy.orm import sessionmaker, declarative_base
|
||||
# from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||
|
||||
DATABASE_URL = os.getenv('DATABASE_URL')
|
||||
engine = create_async_engine(DATABASE_URL, echo=True)
|
||||
# DATABASE_URL = os.getenv('DATABASE_URL')
|
||||
# engine = create_async_engine(DATABASE_URL, echo=True)
|
||||
|
||||
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
||||
# async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
||||
|
||||
|
||||
async_session_maker = sessionmaker(
|
||||
engine, class_=AsyncSession, expire_on_commit=False
|
||||
)
|
||||
async def main():
|
||||
await get_vakansi()
|
||||
await engine.dispose() # Корректно закрываем соединение перед завершением
|
||||
# async_session_maker = sessionmaker(
|
||||
# engine, class_=AsyncSession, expire_on_commit=False
|
||||
# )
|
||||
# async def main():
|
||||
# await get_vakansi()
|
||||
# await engine.dispose() # Корректно закрываем соединение перед завершением
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main()) # 🚀 Запускаем программу в единственном event loop
|
||||
# if __name__ == "__main__":
|
||||
# asyncio.run(main()) # 🚀 Запускаем программу в единственном event loop
|
||||
|
||||
# [x] Обмен по времени не удалять main() что бы при старте сразу отрабатывала)
|
||||
# Запуск функции каждые 5 минут
|
||||
|
@ -184,3 +260,16 @@ if __name__ == "__main__":
|
|||
# time.sleep(1) # Пауза между проверками
|
||||
|
||||
|
||||
|
||||
async def main():
|
||||
async for db in get_async_session(): # Асинхронный генератор сессий
|
||||
query = select(Job).filter(Job.active == 2)
|
||||
result = await db.execute(query)
|
||||
jobs = result.scalars().all() # Получаем ВСЕ записи в виде списка
|
||||
|
||||
for job in jobs:
|
||||
print(job.job_id)
|
||||
await get_job(db, job.job_id)
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
|
@ -0,0 +1,43 @@
|
|||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.future import select
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from model.database import Client
|
||||
|
||||
async def upsert_client(db: AsyncSession, user_id: str, user_login: str, user_nicename: str, user_email: str, phone: str, json_data: str):
|
||||
# Проверяем, существует ли клиент с таким логином или email
|
||||
async with db.begin():
|
||||
result = await db.execute(
|
||||
select(Client).filter((Client.id == user_id))# | (Client.user_email == user_email))
|
||||
)
|
||||
client = result.scalars().first() # Получаем первый результат или None
|
||||
|
||||
if client:
|
||||
# Если клиент существует, обновляем его данные
|
||||
client.user_nicename = user_nicename
|
||||
client.phone = phone
|
||||
client.json_data = json_data
|
||||
# Можно добавить другие поля для обновления
|
||||
|
||||
try:
|
||||
await db.commit() # Применяем изменения в базе данных
|
||||
await db.refresh(client) # Обновляем объект в Python
|
||||
return client
|
||||
except IntegrityError:
|
||||
await db.rollback() # В случае ошибки откатываем изменения
|
||||
raise
|
||||
else:
|
||||
# Если клиента нет, создаем нового
|
||||
new_client = Client(
|
||||
user_login=user_login,
|
||||
user_nicename=user_nicename,
|
||||
user_email=user_email,
|
||||
json_data=json_data,
|
||||
)
|
||||
db.add(new_client)
|
||||
try:
|
||||
await db.commit() # Сохраняем нового клиента в базе данных
|
||||
await db.refresh(new_client) # Обновляем объект в Python
|
||||
return new_client
|
||||
except IntegrityError:
|
||||
await db.rollback() # В случае ошибки откатываем изменения
|
||||
raise
|
Loading…
Reference in New Issue