Ошибка целостности (поле ограничения FOREIGN KEY) возникает при попытке сохранить request.POST из формы модели

Я работаю над коммерческим приложением (с django, но очень новичок в этом), где пользователь может создать объявление через ModelForm под названием ListingForm, которое наследуется от модели под названием Listing.Вот код для модели Listing и ListingForm:


from django.contrib.auth.models import AbstractUser
from django.db import models

class Listing(models.Model):
   NAME_CHOICES = [ 
       ('Fashion', 'Fashion'),
       ('Toys','Toys'),
       ('Electronic','Electronics'),
       ('Home', 'Home'),
       ('Other', 'Other')
   ]
   import datetime
   title = models.CharField(max_length= 64)
   date_made = models.DateField(default= datetime.date.today())
   description = models.TextField()
   user = models.ForeignKey(User, to_field='username', on_delete=models.CASCADE, related_name='user_listings', null=True)
   starting_bid = models.DecimalField(decimal_places=2, max_digits=264, default=10.00)
   image_url = models.CharField(blank=True, max_length=1000)
   category = models.ForeignKey(Category, on_delete=models.CASCADE, to_field='name', related_name='category_listings', default=NAME_CHOICES[4][0])
   listing_category = models.CharField(max_length=12, choices=NAME_CHOICES, null=True, default=NAME_CHOICES[4][0])
   is_active = models.BooleanField(default=True)
   def __str__(self):
       return f'{self.title}' 

Вот код для ``ListingForm'':

from .models import Listing
from django.forms import ModelForm

class ListingForm(ModelForm):
    class Meta:
        model = Listing
        exclude = [
            'date_made',
            'user',
            'category',
            'is_active',
        ]

Модель Listing также имеет внешние ключи к и внутри моделей User, Category и Bid.

Вот код для этих моделей (те же импорты, что и для модели Listing):

class User(AbstractUser):
    def __str__(self):
        return f'{self.username} '



class Category(models.Model):
    NAME_CHOICES = [ 
        ('Fashion', 'Fashion'),
        ('Toys','Toys'),
        ('Electronic','Electronics'),
        ('Home', 'Home'),
        ('Other', 'Other')
    ]

    name = models.CharField(max_length=12, choices= NAME_CHOICES, unique=True)
    def __str__(self):
        return self.name

class Bid(models.Model):
    value = models.DecimalField(decimal_places=2, max_digits=256)
    listing = models.ForeignKey('Listing', on_delete=models.CASCADE, related_name='bid_listings', default=20.00)
    def __str__(self):
        return f'{self.value}'

Я хочу, чтобы пользователь мог создать листинг через представление, основанное на функциях:

def create_listing(request):

    if request.method == 'POST':
        import datetime
        listing_form = ListingForm(request.POST)
        bid = request.POST['starting_bid']
        

        
        if listing_form.is_valid():
            listing_form.save(commit=False)
            listing_form.user = request.user
            listing_form.date_made = datetime.datetime.today()
            listing_form.is_active = True
            listing_form.save()
            Bid.objects.create(value=bid, listing=listing_form)
            return HttpResponse('Listing has been saved successfully!')
        
    else:
        listing_form = ListingForm()
        return render(request, 'auctions/createlisting.html',{
        'listing_form':listing_form
    })

При попытке запустить py manage.py runserver в терминале, я получаю ошибку Integrity в /createlisting.

Вот отслеживание:

Traceback (most recent call last):
  File "C:\Users\ACER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
    response = get_response(request)
  File "C:\Users\ACER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\ACER\Desktop\Projects\commerce\auctions\views.py", line 84, in create_listing
    listing_form.save()
  File "C:\Users\ACER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\forms\models.py", line 548, in save
    self.instance.save()
  File "C:\Users\ACER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\base.py", line 806, in save
    self.save_base(
  File "C:\Users\ACER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\base.py", line 857, in save_base
    updated = self._save_table(
  File "C:\Users\ACER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\base.py", line 1000, in _save_table
    results = self._do_insert(
  File "C:\Users\ACER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\base.py", line 1041, in _do_insert
    return manager._insert(
  File "C:\Users\ACER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Users\ACER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\query.py", line 1434, in _insert
    return query.get_compiler(using=using).execute_sql(returning_fields)
  File "C:\Users\ACER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\models\sql\compiler.py", line 1632, in execute_sql
    self.connection.ops.fetch_returned_insert_columns(
  File "C:\Users\ACER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\backends\base\operations.py", line 205, in fetch_returned_insert_columns
    return cursor.fetchone()
  File "C:\Users\ACER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\utils.py", line 97, in inner
    with self:
  File "C:\Users\ACER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\utils.py", line 91, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "C:\Users\ACER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\db\utils.py", line 98, in inner
    return func(*args, **kwargs)
django.db.utils.IntegrityError: FOREIGN KEY constraint failed
[10/May/2022 21:00:05] ←[35;1m"POST /createlisting HTTP/1.1" 500 135972←[0m

Как решить эту ошибку? Я подозреваю, что это как-то связано с уникальностью моих идентификаторов в одной из моих моделей, или их отсутствием.

Здравствуйте,

Итак, я начну с некоторых улучшений, которые вы должны назначить своему проекту, а затем погружусь в основную проблему.

Во-первых, в вашем models. py, вы можете изменить date_made с DateField на DateTimeField, чтобы вы могли сохранить время, в которое был создан ваш листинг, без необходимости импортировать библиотеку datetime и переопределить его в ваших представлениях, когда форма отправляется, добавив атрибут, который является auto_now_add:

...

date_made = models.DateTimeField(auto_now_add=True)

Эта статья может быть полезна, если вы хотите найти разницу между DateTimeField и DateField

https://www.jafoor.com/post/django-datetimefield-datefield/

Во-вторых, в вашем views.py вы можете просто взять вашу grid, исходящую из данных поста в вашей форме, используя метод cleaned_data, который поставляется с нашей формой, и из него мы можем взять все данные поста, и будет лучше, если вы поместите это внутрь if listing_form.is_valid():

...

     if listing_form.is_valid():
        bid = listing_form.cleaned_data['starting_bid']

Подробнее о методе cleaned_data читайте здесь: Что такое использование cleaned_data в Django

В-третьих, в вашем views.py, вы должны изменить атрибут listing в Bid.objects.create() с listing_form на listing_form. instance, instance здесь означает объект, который ваша форма поместит вместо того, чтобы назначить всю форму, и, конечно, это приведет к ошибке:

...

   Bid.objects.create(value=bid, listing=listing_form.instance)

Теперь поговорим о вашей проблеме. Для ее решения сначала нужно присвоить атрибут полю category в классе Listing в вашем models.py, который называется db_constraint и мы установим его в False:

...

       category = models.ForeignKey(Category, on_delete=models.CASCADE, to_field='name', related_name='category_listings', default=NAME_CHOICES[4][0], db_constraint=False)

затем в вашей cmd введите python manage.py makemigrations затем python manage.py migrate для переноса этого изменения в вашу базу данных

Затем, идите и зарегистрируйте модель Category в admin.py, чтобы вы могли создавать категории вручную из панели администратора для последующего назначения в вашей форме:

from .models import Category

admin.site.register(Category)

Затем перейдите и создайте свои категории в панели администратора.

В последнюю очередь перейдите в ваш views.py, и мы добавим категорию вашего листинга вручную, взяв поле listing_category из нашей формы с помощью функции cleaned_data и этим мы возьмем категорию, которая имеет то же имя, что и listing_category:

from .models import  Listing, Bid, Category
...
   if listing_form.is_valid():
      ...
      listing_form.category = Category.objects.get(name=listing_form.cleaned_data['listing_category'])
      ...


  • Если у вас есть другие вопросы, свяжитесь со мной в моем discord: Ramy#8162
  • .
Вернуться на верх